Merge to Fedora kernel-2.6.7-1.492
[linux-2.6.git] / drivers / net / netconsole.c
1 /*
2  *  linux/drivers/net/netconsole.c
3  *
4  *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
5  *
6  *  This file contains the implementation of an IRQ-safe, crash-safe
7  *  kernel console implementation that outputs kernel messages to the
8  *  network.
9  *
10  * Modification history:
11  *
12  * 2001-09-17    started by Ingo Molnar.
13  * 2003-08-11    2.6 port by Matt Mackall
14  *               simplified options
15  *               generic card hooks
16  *               works non-modular
17  * 2003-09-07    rewritten with netpoll api
18  */
19
20 /****************************************************************
21  *      This program is free software; you can redistribute it and/or modify
22  *      it under the terms of the GNU General Public License as published by
23  *      the Free Software Foundation; either version 2, or (at your option)
24  *      any later version.
25  *
26  *      This program is distributed in the hope that it will be useful,
27  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  *      GNU General Public License for more details.
30  *
31  *      You should have received a copy of the GNU General Public License
32  *      along with this program; if not, write to the Free Software
33  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34  *
35  ****************************************************************/
36
37 #include <linux/mm.h>
38 #include <linux/tty.h>
39 #include <linux/init.h>
40 #include <linux/module.h>
41 #include <linux/console.h>
42 #include <linux/tty_driver.h>
43 #include <linux/moduleparam.h>
44 #include <linux/string.h>
45 #include <linux/sysrq.h>
46 #include <linux/smp.h>
47 #include <linux/netpoll.h>
48 #include <asm/unaligned.h>
49
50 #include "netdump.h"
51
52 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
53 MODULE_DESCRIPTION("Console driver for network interfaces");
54 MODULE_LICENSE("GPL");
55
56 static char config[256];
57 module_param_string(netconsole, config, 256, 0);
58 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
59
60 static struct netpoll np = {
61         .name = "netconsole",
62         .dev_name = "eth0",
63         .local_port = 6665,
64         .remote_port = 514,
65         .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
66 };
67 static int configured = 0;
68
69 static char netlog_config[256];
70 module_param_string(netlog, netlog_config, 256, 0);
71 MODULE_PARM_DESC(netlog, " netlog=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
72 static struct netpoll netlog_np = {
73         .name = "netlog",
74         .dev_name = "eth0",
75         .local_port = 6664,
76         .remote_port = 6666,
77         .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
78 };
79 static int netlog_configured = 0;
80
81 #define MAX_PRINT_CHUNK 1000
82 #define SYSLOG_HEADER_LEN 4
83
84 static int syslog_chars = SYSLOG_HEADER_LEN;
85 static unsigned char syslog_line [MAX_PRINT_CHUNK + 10] = {
86         '<',
87         '5',
88         '>',
89         ' ',
90         [4 ... MAX_PRINT_CHUNK+5] = '\0',
91 };
92 static unsigned char netlog_line[MAX_PRINT_CHUNK + HEADER_LEN];
93 static unsigned int log_offset;
94
95 /*
96  * We feed kernel messages char by char, and send the UDP packet
97  * one linefeed. We buffer all characters received.
98  */
99 static inline void feed_syslog_char(const unsigned char c)
100 {
101         if (syslog_chars == MAX_PRINT_CHUNK)
102                 syslog_chars--;
103         syslog_line[syslog_chars] = c;
104         syslog_chars++;
105         if (c == '\n') {
106                 netpoll_send_udp(&np, syslog_line, syslog_chars);
107                 syslog_chars = SYSLOG_HEADER_LEN;
108         }
109 }
110
111 static void write_msg(struct console *con, const char *msg, unsigned int len)
112 {
113         int left, i;
114         unsigned long flags;
115         reply_t reply;
116         char *netlog_buf = &netlog_line[HEADER_LEN];
117
118         if (!np.dev && !netlog_np.dev)
119                 return;
120
121         if (unlikely(netdump_mode))
122                 return;
123
124         local_irq_save(flags);
125
126         if (np.dev)
127                 for (i = 0; i < len; i++)
128                         feed_syslog_char(msg[i]);
129
130         if (netlog_np.dev) {
131                 left = len;
132                 while (left) {
133                         if (left > MAX_PRINT_CHUNK)
134                                 len = MAX_PRINT_CHUNK;
135                         else
136                                 len = left;
137                         netlog_line[0] = NETDUMP_VERSION;
138
139                         reply.nr = 0;
140                         reply.code = REPLY_LOG;
141                         reply.info = log_offset;
142
143                         put_unaligned(htonl(reply.nr), 
144                                       (u32 *)(netlog_line + 1));
145                         put_unaligned(htonl(reply.code),
146                                       (u32 *)(netlog_line + 5));
147                         put_unaligned(htonl(reply.info),
148                                       (u32 *)(netlog_line + 9));
149
150                         log_offset += len;
151                         memcpy(netlog_buf, msg, len);
152
153                         netpoll_send_udp(&netlog_np, 
154                                          netlog_line, len + HEADER_LEN);
155                         msg += len;
156                         left -= len;
157                 }
158         }
159
160         local_irq_restore(flags);
161 }
162
163 static struct console netconsole = {
164         .flags = CON_ENABLED | CON_PRINTBUFFER,
165         .write = write_msg
166 };
167
168 static int option_setup(char *opt)
169 {
170         configured = !netpoll_parse_options(&np, opt);
171         return 0;
172 }
173
174 __setup("netconsole=", option_setup);
175
176 static int netlog_option_setup(char *opt)
177 {
178         netlog_configured = !netpoll_parse_options(&netlog_np, opt);
179         return 0;
180 }
181
182 __setup("netlog=", netlog_option_setup);
183
184 static int init_netconsole(void)
185 {
186         if(strlen(config))
187                 option_setup(config);
188
189         if (strlen(netlog_config))
190                 netlog_option_setup(netlog_config);
191
192         if (configured && netpoll_setup(&np))
193                 printk("netconsole: failed to configure syslog service\n");
194
195         if (netlog_configured && netpoll_setup(&netlog_np))
196                 printk("netconsole: failed to configured netlog service.\n");
197
198         if (!configured && !netlog_configured)
199                 return -EINVAL;
200
201         register_console(&netconsole);
202         printk(KERN_INFO "netconsole: network logging started\n");
203         return 0;
204 }
205
206 static void cleanup_netconsole(void)
207 {
208         unregister_console(&netconsole);
209
210         if (configured)
211                 netpoll_cleanup(&np);
212
213         if (netlog_configured)
214                 netpoll_cleanup(&netlog_np);
215 }
216
217 module_init(init_netconsole);
218 module_exit(cleanup_netconsole);