Whamcloud - gitweb
file lbnal_cb.c was initially added on branch b1_4.
[fs/lustre-release.git] / lustre / kernel_patches / patches / netconsole-2.4.24.patch
1 Index: linux-2.4.24/drivers/net/netconsole.c
2 ===================================================================
3 --- linux-2.4.24.orig/drivers/net/netconsole.c  2003-01-30 18:24:37.000000000 +0800
4 +++ linux-2.4.24/drivers/net/netconsole.c       2004-06-09 18:53:37.000000000 +0800
5 @@ -0,0 +1,1376 @@
6 +/*
7 + *  linux/drivers/net/netconsole.c
8 + *
9 + *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
10 + *  Copyright (C) 2002  Red Hat, Inc.
11 + *
12 + *  This file contains the implementation of an IRQ-safe, crash-safe
13 + *  kernel console implementation that outputs kernel messages to the
14 + *  network.
15 + *
16 + * Modification history:
17 + *
18 + * 2001-09-17    started by Ingo Molnar.
19 + * 2002-03-14    simultaneous syslog packet option by Michael K. Johnson
20 + * 2003-10-30    Add sysrq command processing by Wangdi <wangdi@clusterfs.com>
21 + * 
22 + */
23 +
24 +/****************************************************************
25 + *      This program is free software; you can redistribute it and/or modify
26 + *      it under the terms of the GNU General Public License as published by
27 + *      the Free Software Foundation; either version 2, or (at your option)
28 + *      any later version.
29 + *
30 + *      This program is distributed in the hope that it will be useful,
31 + *      but WITHOUT ANY WARRANTY; without even the implied warranty of
32 + *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33 + *      GNU General Public License for more details.
34 + *
35 + *      You should have received a copy of the GNU General Public License
36 + *      along with this program; if not, write to the Free Software
37 + *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 + *
39 + ****************************************************************/
40 +
41 +#include <net/tcp.h>
42 +#include <net/udp.h>
43 +#include <linux/mm.h>
44 +#include <linux/tty.h>
45 +#include <linux/init.h>
46 +#include <linux/delay.h>
47 +#include <linux/random.h>
48 +#include <linux/reboot.h>
49 +#include <linux/module.h>
50 +#include <asm/unaligned.h>
51 +#include <asm/pgtable.h>
52 +#if CONFIG_X86_LOCAL_APIC
53 +#include <asm/apic.h>
54 +#endif
55 +#include <linux/console.h>
56 +#include <linux/smp_lock.h>
57 +#include <linux/netdevice.h>
58 +#include <linux/tty_driver.h>
59 +#include <linux/etherdevice.h>
60 +#include <linux/elf.h>
61 +#include <linux/sysrq.h>
62 +#include "netconsole.h"
63 +
64 +static struct net_device *netconsole_dev;
65 +static u16 source_port, netdump_target_port, netlog_target_port, syslog_target_port;
66 +static u32 source_ip, netdump_target_ip, netlog_target_ip, syslog_target_ip;
67 +static unsigned char netdump_daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
68 +static unsigned char netlog_daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
69 +static unsigned char syslog_daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
70 +
71 +static unsigned int mhz = 500, idle_timeout;
72 +static unsigned long long mhz_cycles, jiffy_cycles;
73 +
74 +
75 +#define MAX_UDP_CHUNK 1460
76 +#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
77 +
78 +#define DEBUG 0 
79 +#if DEBUG
80 +# define Dprintk(x...) printk(KERN_INFO x)
81 +#else
82 +# define Dprintk(x...)
83 +#endif
84 +/*
85 + * We maintain a small pool of fully-sized skbs,
86 + * to make sure the message gets out even in
87 + * extreme OOM situations.
88 + */
89 +#define MAX_NETCONSOLE_SKBS 128
90 +
91 +static spinlock_t netconsole_lock = SPIN_LOCK_UNLOCKED;
92 +static int nr_netconsole_skbs;
93 +static struct sk_buff *netconsole_skbs;
94 +
95 +#define MAX_SKB_SIZE \
96 +               (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
97 +                               sizeof(struct iphdr) + sizeof(struct ethhdr))
98 +
99 +static int new_arp = 0;
100 +static unsigned char arp_sha[ETH_ALEN], arp_tha[ETH_ALEN];
101 +static u32 arp_sip, arp_tip;
102 +
103 +static void send_netconsole_arp(struct net_device *dev);
104 +
105 +static void __refill_netconsole_skbs(void)
106 +{
107 +       struct sk_buff *skb;
108 +       unsigned long flags;
109 +
110 +       spin_lock_irqsave(&netconsole_lock, flags);
111 +       while (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS) {
112 +               skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
113 +               if (!skb)
114 +                       break;
115 +               if (netconsole_skbs)
116 +                       skb->next = netconsole_skbs;
117 +               else
118 +                       skb->next = NULL;
119 +               netconsole_skbs = skb;
120 +               nr_netconsole_skbs++;
121 +       }
122 +       spin_unlock_irqrestore(&netconsole_lock, flags);
123 +}
124 +
125 +static struct sk_buff * get_netconsole_skb(void)
126 +{
127 +       struct sk_buff *skb;
128 +
129 +       unsigned long flags;
130 +
131 +       spin_lock_irqsave(&netconsole_lock, flags);
132 +       skb = netconsole_skbs;
133 +       if (skb) {
134 +               netconsole_skbs = skb->next;
135 +               skb->next = NULL;
136 +               nr_netconsole_skbs--;
137 +       }
138 +       spin_unlock_irqrestore(&netconsole_lock, flags);
139 +
140 +       return skb;
141 +}
142 +
143 +static unsigned long long t0;
144 +
145 +/*
146 + * Do cleanups:
147 + * - zap completed output skbs.
148 + * - send ARPs if requested
149 + * - reboot the box if inactive for more than N seconds.
150 + */
151 +static void zap_completion_queue(void)
152 +{
153 +       unsigned long long t1;
154 +       int cpu = smp_processor_id();
155 +
156 +       if (softnet_data[cpu].completion_queue) {
157 +               struct sk_buff *clist;
158 +
159 +               local_irq_disable();
160 +               clist = softnet_data[cpu].completion_queue;
161 +               softnet_data[cpu].completion_queue = NULL;
162 +               local_irq_enable();
163 +
164 +               while (clist != NULL) {
165 +                       struct sk_buff *skb = clist;
166 +                       clist = clist->next;
167 +                       __kfree_skb(skb);
168 +               }
169 +       }
170 +
171 +       if (new_arp) {
172 +               Dprintk("got ARP req - sending reply.\n");
173 +               new_arp = 0;
174 +               send_netconsole_arp(netconsole_dev);
175 +       }
176 +
177 +       rdtscll(t1);
178 +       if (idle_timeout) {
179 +               if (t0) {
180 +                       if (((t1 - t0) >> 20) > mhz_cycles * (unsigned long long)idle_timeout) {
181 +                               t0 = t1;
182 +                               printk("netdump idle timeout - rebooting in 3 seconds.\n");
183 +                               mdelay(3000);
184 +                               machine_restart(NULL);
185 +                       }
186 +               }
187 +       }
188 +       /* maintain jiffies in a polling fashion, based on rdtsc. */
189 +       {
190 +               static unsigned long long prev_tick;
191 +
192 +               if (t1 - prev_tick >= jiffy_cycles) {
193 +                       prev_tick += jiffy_cycles;
194 +                       jiffies++;
195 +               }
196 +       }
197 +}
198 +void (*irqfunc)(int, void *, struct pt_regs *);
199 +
200 +static void netdump_poll(struct net_device *dev)
201 +{
202 +       int budget = 1;
203 +
204 +       disable_irq(dev->irq);
205 +       
206 +       irqfunc(dev->irq, dev, 0);
207 +       
208 +       if(dev->poll && test_bit(__LINK_STATE_RX_SCHED, &dev->state))
209 +               dev->poll(dev, &budget);
210 +
211 +       enable_irq(dev->irq);
212 +
213 +}
214 +
215 +static struct sk_buff * alloc_netconsole_skb(struct net_device *dev, int len, int reserve)
216 +{
217 +       int once = 1;
218 +       int count = 0;
219 +       struct sk_buff *skb = NULL;
220 +
221 +repeat:
222 +       zap_completion_queue();
223 +       if (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS)
224 +               __refill_netconsole_skbs();
225 +
226 +       skb = alloc_skb(len, GFP_ATOMIC);
227 +       if (!skb) {
228 +               skb = get_netconsole_skb();
229 +               if (!skb) {
230 +                       count++;
231 +                       if (once && (count == 1000000)) {
232 +                               printk("possibly FATAL: out of netconsole skbs!!! will keep retrying.\n");
233 +                               once = 0;
234 +                       }
235 +                       Dprintk("alloc skb: polling controller ...\n");
236 +                       netdump_poll(dev);
237 +                       goto repeat;
238 +               }
239 +       }
240 +
241 +       atomic_set(&skb->users, 1);
242 +       skb_reserve(skb, reserve);
243 +       return skb;
244 +}
245 +
246 +static void transmit_raw_skb(struct sk_buff *skb, struct net_device *dev)
247 +{
248 +
249 +repeat_poll:
250 +       spin_lock(&dev->xmit_lock);
251 +       dev->xmit_lock_owner = smp_processor_id();
252 +
253 +       if (netif_queue_stopped(dev)) {
254 +               dev->xmit_lock_owner = -1;
255 +               spin_unlock(&dev->xmit_lock);
256 +
257 +               Dprintk("xmit skb: polling controller ...\n");
258 +               netdump_poll(dev);
259 +               zap_completion_queue();
260 +               goto repeat_poll;
261 +       }
262 +
263 +       dev->hard_start_xmit(skb, dev);
264 +
265 +       dev->xmit_lock_owner = -1;
266 +       spin_unlock(&dev->xmit_lock);
267 +}
268 +
269 +static void transmit_netconsole_skb(struct sk_buff *skb, struct net_device *dev,
270 +       int ip_len, int udp_len,
271 +       u16 source_port, u16 target_port, u32 source_ip, u32 target_ip,
272 +       unsigned char * macdaddr)
273 +{
274 +       struct udphdr *udph;
275 +       struct iphdr *iph;
276 +       struct ethhdr *eth;
277 +
278 +       udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
279 +       udph->source = source_port;
280 +       udph->dest = target_port;
281 +       udph->len = htons(udp_len);
282 +       udph->check = 0;
283 +
284 +       iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
285 +
286 +       iph->version  = 4;
287 +       iph->ihl      = 5;
288 +       iph->tos      = 0;
289 +       iph->tot_len  = htons(ip_len);
290 +       iph->id       = 0;
291 +       iph->frag_off = 0;
292 +       iph->ttl      = 64;
293 +       iph->protocol = IPPROTO_UDP;
294 +       iph->check    = 0;
295 +       iph->saddr    = source_ip;
296 +       iph->daddr    = target_ip;
297 +       iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
298 +
299 +       eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
300 +
301 +       eth->h_proto = htons(ETH_P_IP);
302 +       memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
303 +       memcpy(eth->h_dest, macdaddr, dev->addr_len);
304 +
305 +       transmit_raw_skb(skb, dev);
306 +}
307 +
308 +static void send_netconsole_arp(struct net_device *dev)
309 +{
310 +       int total_len, arp_len, arp_data_len;
311 +       struct sk_buff *skb;
312 +       unsigned char *arp;
313 +       struct arphdr *arph;
314 +       struct ethhdr *eth;
315 +
316 +       arp_data_len = 2*4 + 2*ETH_ALEN;
317 +       arp_len = arp_data_len + sizeof(struct arphdr);
318 +       total_len = arp_len + ETH_HLEN;
319 +
320 +       skb = alloc_netconsole_skb(dev, total_len, total_len - arp_data_len);
321 +
322 +       arp = skb->data;
323 +
324 +       memcpy(arp, dev->dev_addr, ETH_ALEN);
325 +       arp += ETH_ALEN;
326 +
327 +       memcpy(arp, &source_ip, 4);
328 +       arp += 4;
329 +
330 +       memcpy(arp, arp_sha, ETH_ALEN);
331 +       arp += ETH_ALEN;
332 +
333 +       memcpy(arp, &arp_sip, 4);
334 +       arp += 4;
335 +
336 +       skb->len += 2*4 + 2*ETH_ALEN;
337 +
338 +       arph = (struct arphdr *)skb_push(skb, sizeof(*arph));
339 +
340 +       arph->ar_hrd = htons(dev->type);
341 +       arph->ar_pro = __constant_htons(ETH_P_IP);
342 +       arph->ar_hln = ETH_ALEN;
343 +       arph->ar_pln = 4;
344 +       arph->ar_op = __constant_htons(ARPOP_REPLY);
345 +
346 +       eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
347 +
348 +       eth->h_proto = htons(ETH_P_ARP);
349 +       memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
350 +       memcpy(eth->h_dest, arp_sha, dev->addr_len);
351 +
352 +       transmit_raw_skb(skb, dev);
353 +}
354 +
355 +static void send_netdump_skb(struct net_device *dev, const char *msg, unsigned int msg_len, reply_t *reply)
356 +{
357 +       int total_len, ip_len, udp_len;
358 +       struct sk_buff *skb;
359 +
360 +       udp_len = msg_len + HEADER_LEN + sizeof(struct udphdr);
361 +       ip_len = udp_len + sizeof(struct iphdr);
362 +       total_len = ip_len + ETH_HLEN;
363 +
364 +       skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - HEADER_LEN);
365 +
366 +       skb->data[0] = NETCONSOLE_VERSION;
367 +       put_unaligned(htonl(reply->nr), (u32 *) (skb->data + 1));
368 +       put_unaligned(htonl(reply->code), (u32 *) (skb->data + 5));
369 +       put_unaligned(htonl(reply->info), (u32 *) (skb->data + 9));
370 +
371 +       memcpy(skb->data + HEADER_LEN, msg, msg_len);
372 +       skb->len += msg_len + HEADER_LEN;
373 +
374 +       transmit_netconsole_skb(skb, dev, ip_len, udp_len,
375 +               source_port, netdump_target_port, source_ip, netdump_target_ip, netdump_daddr);
376 +}
377 +
378 +#define SYSLOG_HEADER_LEN 4
379 +
380 +static void send_netlog_skb(struct net_device *dev, const char *msg, unsigned int msg_len, reply_t *reply)
381 +{
382 +       int total_len, ip_len, udp_len;
383 +       struct sk_buff *skb;
384 +
385 +       udp_len = msg_len + HEADER_LEN + sizeof(struct udphdr);
386 +       ip_len = udp_len + sizeof(struct iphdr);
387 +       total_len = ip_len + ETH_HLEN;
388 +
389 +       skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - HEADER_LEN);
390 +
391 +       skb->data[0] = NETCONSOLE_VERSION;
392 +       put_unaligned(htonl(reply->nr), (u32 *) (skb->data + 1));
393 +       put_unaligned(htonl(reply->code), (u32 *) (skb->data + 5));
394 +       put_unaligned(htonl(reply->info), (u32 *) (skb->data + 9));
395 +
396 +       memcpy(skb->data + HEADER_LEN, msg, msg_len);
397 +       skb->len += msg_len + HEADER_LEN;
398 +
399 +       transmit_netconsole_skb(skb, dev, ip_len, udp_len,
400 +               source_port, netlog_target_port, source_ip, netlog_target_ip, netlog_daddr);
401 +}
402 +
403 +#define SYSLOG_HEADER_LEN 4
404 +
405 +static void send_syslog_skb(struct net_device *dev, const char *msg, unsigned int msg_len, int pri)
406 +{
407 +       int total_len, ip_len, udp_len;
408 +       struct sk_buff *skb;
409 +
410 +       udp_len = msg_len + SYSLOG_HEADER_LEN + sizeof(struct udphdr);
411 +       ip_len = udp_len + sizeof(struct iphdr);
412 +       total_len = ip_len + ETH_HLEN;
413 +
414 +       skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - SYSLOG_HEADER_LEN);
415 +
416 +       skb->data[0] = '<';
417 +       skb->data[1] = pri + '0';
418 +       skb->data[2]= '>';
419 +       skb->data[3]= ' ';
420 +
421 +       memcpy(skb->data + SYSLOG_HEADER_LEN, msg, msg_len);
422 +       skb->len += msg_len + SYSLOG_HEADER_LEN;
423 +
424 +       transmit_netconsole_skb(skb, dev, ip_len, udp_len, source_port,
425 +               syslog_target_port, source_ip, syslog_target_ip, syslog_daddr);
426 +}
427 +
428 +#define MAX_SYSLOG_CHARS 1000
429 +
430 +static spinlock_t syslog_lock = SPIN_LOCK_UNLOCKED;
431 +static int syslog_chars;
432 +static unsigned char syslog_line [MAX_SYSLOG_CHARS + 10];
433 +
434 +/*
435 + * We feed kernel messages char by char, and send the UDP packet
436 + * one linefeed. We buffer all characters received.
437 + */
438 +static inline void feed_syslog_char(struct net_device *dev, const unsigned char c)
439 +{
440 +       if (syslog_chars == MAX_SYSLOG_CHARS)
441 +               syslog_chars--;
442 +       syslog_line[syslog_chars] = c;
443 +       syslog_chars++;
444 +       if (c == '\n') {
445 +               send_syslog_skb(dev, syslog_line, syslog_chars, 5);
446 +               syslog_chars = 0;
447 +       }
448 +}
449 +
450 +static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
451 +static unsigned int log_offset;
452 +
453 +static int thread_stopped = 0;
454 +/*Interrupt function for netdump */
455 +static int sysrq_mode = 0;
456 +static int stop_sysrq_thread = 0;
457 +#define Set_Sysrq_mode()       (sysrq_mode = 1)
458 +#define Clear_Sysrq_mode()     (sysrq_mode = 0)
459 +static char send_cache[MAX_PRINT_CHUNK];
460 +static unsigned int send_cache_pos = 0;
461 +wait_queue_head_t sysrq_thread_queue;
462 +wait_queue_head_t sysrq_thread_waiter_queue;
463 +
464 +#define SEND_MSG_BUFFER(buf, len)                      \
465 +do                                                     \
466 +{                                                      \
467 +       reply_t reply;                                  \
468 +       unsigned int flags;                             \
469 +       __save_flags(flags);                            \
470 +       __cli();                                        \
471 +       reply.code = REPLY_LOG;                         \
472 +       reply.nr = 0;                                   \
473 +       reply.info = 0;                                 \
474 +       spin_lock(&sequence_lock);                      \
475 +       send_netlog_skb(dev, buf, len, &reply); \
476 +       spin_unlock(&sequence_lock);                    \
477 +       __restore_flags(flags);                         \
478 +}while(0);
479 +
480 +void netconsole_do_sysrq(req_t *req)
481 +{
482 +        struct pt_regs regs;
483 +       struct net_device *dev = netconsole_dev;
484 +
485 +       if (!dev)
486 +               return;
487 +       Set_Sysrq_mode();
488 +       get_current_regs(&regs);
489 +       handle_sysrq((int)req->from, &regs, NULL, NULL);
490 +       Dprintk("Do the command netconsole\n"); 
491 +       if (send_cache_pos != 0){
492 +               SEND_MSG_BUFFER(send_cache, send_cache_pos);
493 +               memset(send_cache, 0, MAX_PRINT_CHUNK);
494 +               send_cache_pos = 0;
495 +       } 
496 +
497 +       Clear_Sysrq_mode();
498 +}
499 +static void write_netconsole_msg(struct console *con, const char *msg0, unsigned int msg_len)
500 +{
501 +       int len, left, i;
502 +       struct net_device *dev;
503 +       const char *msg = msg0;
504 +       reply_t reply;
505 +       
506 +       dev = netconsole_dev;
507 +       if (!dev || netdump_mode)
508 +               return;
509 +       if (sysrq_mode){
510 +               unsigned long total_len = send_cache_pos + msg_len;
511 +               unsigned long left_len = msg_len;
512 +               while (total_len >=  MAX_PRINT_CHUNK){
513 +                       unsigned long send_len = MAX_PRINT_CHUNK - send_cache_pos; 
514 +                       memcpy(send_cache + send_cache_pos, msg, send_len);
515 +                       SEND_MSG_BUFFER(send_cache, MAX_PRINT_CHUNK);
516 +                       send_cache_pos = 0;
517 +                       total_len -= MAX_PRINT_CHUNK;
518 +                       left_len -= send_len; 
519 +               }
520 +               if (left_len > 0){
521 +                       memcpy(send_cache + send_cache_pos, msg + (msg_len -left_len), left_len);
522 +                       send_cache_pos += left_len;
523 +               }
524 +               return; 
525 +       }else if (netif_running(dev)) {
526 +               unsigned long flags;
527 +
528 +               __save_flags(flags);
529 +               __cli();
530 +               left = msg_len;
531 +               if (netlog_target_ip) {
532 +                       while (left) {
533 +                               if (left > MAX_PRINT_CHUNK)
534 +                                       len = MAX_PRINT_CHUNK;
535 +                               else
536 +                                       len = left;
537 +                               reply.code = REPLY_LOG;
538 +                               reply.nr = 0;
539 +                               spin_lock(&sequence_lock);
540 +                               reply.info = log_offset;
541 +                               log_offset += len;
542 +                               spin_unlock(&sequence_lock);
543 +                               send_netlog_skb(dev, msg, len, &reply);
544 +                               msg += len;
545 +                               left -= len;
546 +                       }
547 +               }
548 +               if (syslog_target_ip) {
549 +                       spin_lock(&syslog_lock);
550 +                       for (i = 0; i < msg_len; i++)
551 +                               feed_syslog_char(dev, msg0[i]);
552 +                       spin_unlock(&syslog_lock);
553 +               }
554 +
555 +               __restore_flags(flags);
556 +       }
557 +}
558 +
559 +static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
560 +{
561 +       return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
562 +}
563 +
564 +static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
565 +                            unsigned short ulen, u32 saddr, u32 daddr)
566 +{
567 +       if (uh->check == 0) {
568 +               skb->ip_summed = CHECKSUM_UNNECESSARY;
569 +       } else if (skb->ip_summed == CHECKSUM_HW) {
570 +               skb->ip_summed = CHECKSUM_UNNECESSARY;
571 +               if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
572 +                       return 0;
573 +               skb->ip_summed = CHECKSUM_NONE;
574 +       }
575 +       if (skb->ip_summed != CHECKSUM_UNNECESSARY)
576 +               skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP,
577 +0);
578 +       /* Probably, we should checksum udp header (it should be in cache
579 +        * in any case) and data in tiny packets (< rx copybreak).
580 +        */
581 +       return 0;
582 +}
583 +
584 +static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
585 +{
586 +       return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
587 +}
588 +
589 +static __inline__ int udp_checksum_complete(struct sk_buff *skb)
590 +{
591 +       return skb->ip_summed != CHECKSUM_UNNECESSARY &&
592 +               __udp_checksum_complete(skb);
593 +}
594 +
595 +/*
596 + * NOTE: security depends on the trusted path between the netconsole
597 + *       server and netconsole client, since none of the packets are
598 + *       encrypted. The random magic number protects the protocol
599 + *       against spoofing.
600 + */
601 +static u64 netconsole_magic;
602 +static u32 magic1, magic2;
603 +
604 +static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
605 +static int nr_req = 0;
606 +static LIST_HEAD(request_list);
607 +
608 +static void add_new_req(req_t *req)
609 +{
610 +       unsigned long flags;
611 +
612 +       spin_lock_irqsave(&req_lock, flags);
613 +       list_add_tail(&req->list, &request_list);
614 +       nr_req++;
615 +       Dprintk("pending requests: %d.\n", nr_req);
616 +       spin_unlock_irqrestore(&req_lock, flags);
617 +
618 +       rdtscll(t0);
619 +}
620 +
621 +static req_t *get_new_req(void)
622 +{
623 +       req_t *req = NULL;
624 +       unsigned long flags;
625 +
626 +       spin_lock_irqsave(&req_lock, flags);
627 +       if (nr_req) {
628 +               req = list_entry(request_list.next, req_t, list);
629 +               list_del(&req->list);
630 +               nr_req--;
631 +       }
632 +       spin_unlock_irqrestore(&req_lock, flags);
633 +
634 +       return req;
635 +}
636 +
637 +static req_t *alloc_req(void)
638 +{
639 +       req_t *req;
640 +
641 +       req = (req_t *) kmalloc(sizeof(*req), GFP_ATOMIC);
642 +       return req;
643 +}
644 +
645 +static int netconsole_rx_hook(struct sk_buff *skb)
646 +{
647 +       int proto;
648 +       struct iphdr *iph;
649 +       struct udphdr *uh;
650 +       __u32 len, saddr, daddr, ulen;
651 +       req_t *__req;
652 +       req_t *req;
653 +       struct net_device *dev;
654 +
655 +#if DEBUG
656 +       {
657 +               static int packet_count;
658 +               Dprintk("        %d\r", ++packet_count);
659 +       }
660 +#endif
661 +       dev = skb->dev;
662 +       if (dev->type != ARPHRD_ETHER)
663 +               goto out;
664 +       proto = ntohs(skb->mac.ethernet->h_proto);
665 +       Dprintk("rx got skb %p (len: %d, users: %d), dev %s, h_proto: %04x.\n", skb, skb->len, atomic_read(&skb->users), dev->name, proto);
666 +       #define D(x) skb->mac.ethernet->h_dest[x]
667 +       Dprintk("... h_dest:   %02X:%02X:%02X:%02X:%02X:%02X.\n", D(0), D(1), D(2), D(3), D(4), D(5));
668 +       #undef D
669 +       #define D(x) skb->mac.ethernet->h_source[x]
670 +       Dprintk("... h_source: %02X:%02X:%02X:%02X:%02X:%02X.\n", D(0), D(1), D(2), D(3), D(4), D(5));
671 +       #undef D
672 +       if (skb->pkt_type == PACKET_OTHERHOST)
673 +               goto out;
674 +       if (skb_shared(skb))
675 +               goto out;
676 +       if (proto == ETH_P_ARP) {
677 +               struct arphdr *arp;
678 +               unsigned char *arp_ptr;
679 +
680 +               Dprintk("got arp skb.\n");
681 +               arp = (struct arphdr *)skb->data;
682 +               if (!pskb_may_pull(skb, sizeof(struct arphdr) + 2*4 + 2*ETH_ALEN))
683 +                       goto out;
684 +               if (htons(dev->type) != arp->ar_hrd)
685 +                       goto out;
686 +               if (arp->ar_pro != __constant_htons(ETH_P_IP))
687 +                       goto out;
688 +               if (arp->ar_hln != ETH_ALEN)
689 +                       goto out;
690 +               if (arp->ar_pln != 4)
691 +                       goto out;
692 +               if (arp->ar_op != __constant_htons(ARPOP_REQUEST))
693 +                       goto out;
694 +               /*
695 +                * ARP header looks ok so far, extract fields:
696 +                */
697 +               arp_ptr = (unsigned char *)(arp + 1);
698 +
699 +               memcpy(arp_sha, arp_ptr, ETH_ALEN);
700 +               arp_ptr += ETH_ALEN;
701 +
702 +               memcpy(&arp_sip, arp_ptr, 4);
703 +               arp_ptr += 4;
704 +
705 +               memcpy(arp_tha, arp_ptr, ETH_ALEN);
706 +               arp_ptr += ETH_ALEN;
707 +
708 +               memcpy(&arp_tip, arp_ptr, 4);
709 +
710 +               #define D(x) arp_sha[x]
711 +               Dprintk("... arp_sha:   %02X:%02X:%02X:%02X:%02X:%02X.\n", D(0), D(1), D(2), D(3), D(4), D(5));
712 +               #undef D
713 +               #define D(x) ((unsigned char *)&arp_sip)[x]
714 +               Dprintk("... arp_sip:   %d.%d.%d.%d.\n", D(0), D(1), D(2), D(3));
715 +               #undef D
716 +               #define D(x) arp_tha[x]
717 +               Dprintk("... arp_tha:   %02X:%02X:%02X:%02X:%02X:%02X.\n", D(0), D(1), D(2), D(3), D(4), D(5));
718 +               #undef D
719 +               #define D(x) ((unsigned char *)&arp_tip)[x]
720 +               Dprintk("... arp_tip:   %d.%d.%d.%d.\n", D(0), D(1), D(2), D(3));
721 +               #undef D
722 +               #define D(x) ((unsigned char *)&source_ip)[x]
723 +               Dprintk("... (source_ip):   %d.%d.%d.%d.\n", D(0), D(1), D(2), D(3));
724 +               #undef D
725 +
726 +               if (LOOPBACK(arp_tip) || MULTICAST(arp_tip))
727 +                       goto out;
728 +
729 +               if (arp_tip != source_ip)
730 +                       goto out;
731 +               new_arp = 1;
732 +               goto out;
733 +       }
734 +       if (proto != ETH_P_IP)
735 +               goto out;
736 +       /*
737 +        * IP header correctness testing:
738 +        */
739 +       iph = (struct iphdr *)skb->data;
740 +       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
741 +               goto out;
742 +       Dprintk("... IP ihl*4: %d, version: %d.\n", iph->ihl*4, iph->version);
743 +       if (iph->ihl < 5 || iph->version != 4)
744 +               goto out;
745 +       if (!pskb_may_pull(skb, iph->ihl*4))
746 +               goto out;
747 +       if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
748 +               goto out;
749 +       len = ntohs(iph->tot_len);
750 +       Dprintk("... IP len: %d.\n", len);
751 +       if (skb->len < len || len < iph->ihl*4)
752 +               goto out;
753 +       saddr = iph->saddr;
754 +       daddr = iph->daddr;
755 +       Dprintk("... IP src: %08x, dst: %08x.\n", saddr, daddr);
756 +       Dprintk("... IP protocol: %d.\n", iph->protocol);
757 +       if (iph->protocol != IPPROTO_UDP)
758 +               goto out;
759 +       Dprintk("... netdump src: %08x, dst: %08x.\n", source_ip, netlog_target_ip);
760 +       if (source_ip != daddr)
761 +               goto out;
762 +       if (netlog_target_ip != saddr)
763 +               goto out;
764 +       len -= iph->ihl*4;
765 +       uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
766 +       ulen = ntohs(uh->len);
767 +       Dprintk("... UDP len: %d (left %d).\n", ulen, len);
768 +
769 +#define MIN_COMM_SIZE (sizeof(*uh) + NETDUMP_REQ_SIZE)
770 +       if (ulen != len || ulen < MIN_COMM_SIZE) {
771 +               Dprintk("... UDP, hm, len not ok.\n");
772 +               goto out;
773 +       }
774 +       if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) {
775 +               Dprintk("... UDP, hm, checksum init not ok.\n");
776 +               goto out;
777 +       }
778 +       if (udp_checksum_complete(skb)) {
779 +               Dprintk("... UDP, hm, checksum complete not ok.\n");
780 +               goto out;
781 +       }
782 +       Dprintk("... UDP packet OK!\n");
783 +       Dprintk("... UDP src port: %d, dst port: %d.\n", uh->source, uh->dest);
784 +       if (source_port != uh->source)
785 +               goto out;
786 +       if (netlog_target_port != uh->dest)
787 +               goto out;
788 +       __req = (req_t *)(uh + 1);
789 +       Dprintk("... UDP netdump packet OK!\n");
790 +
791 +       req = alloc_req();
792 +       if (!req) {
793 +               printk("no more RAM to allocate request - dropping it.\n");
794 +               goto out;
795 +       }
796 +
797 +       req->magic = ntohl(__req->magic);
798 +       req->command = ntohl(__req->command);
799 +       req->from = ntohl(__req->from);
800 +       req->to = ntohl(__req->to);
801 +       req->nr = ntohl(__req->nr);
802 +
803 +       Dprintk("... netdump magic:   %08Lx.\n", req->magic);
804 +       Dprintk("... netdump command: %08x.\n", req->command);
805 +       Dprintk("... netdump from:    %08x.\n", req->from);
806 +       Dprintk("... netdump to:      %08x.\n", req->to);
807 +
808 +       if (netdump_mode) 
809 +               add_new_req(req);
810 +       else if (req->command == COMM_SYSRQ){
811 +               add_new_req(req);
812 +               wake_up(&sysrq_thread_queue);   
813 +               return NET_RX_DROP;
814 +       }
815 +out:
816 +       if (!netdump_mode)
817 +               return NET_RX_SUCCESS;
818 +       return NET_RX_DROP;
819 +}
820 +
821 +#define INVALID_PAGE "page is not valid!\n"
822 +
823 +static void send_netdump_mem (struct net_device *dev, req_t *req)
824 +{
825 +       int i;
826 +       char *kaddr;
827 +       char str[1024];
828 +       struct page *page;
829 +       unsigned long nr = req->from;
830 +       int nr_chunks = PAGE_SIZE/1024;
831 +       reply_t reply;
832 +
833 +       return ;
834 +       
835 +       reply.nr = req->nr;
836 +       reply.info = 0;
837 +       if (req->from >= max_mapnr) {
838 +               sprintf(str, "page %08lx is bigger than max page # %08lx!\n", nr, max_mapnr);
839 +               reply.code = REPLY_ERROR;
840 +               send_netdump_skb(dev, str, strlen(str), &reply);
841 +               return;
842 +       }
843 +       page = mem_map + nr;
844 +       if (PageReserved(page))
845 +               page = ZERO_PAGE(0);
846 +
847 +//     kaddr = (char *)kmap_atomic(page, KM_NETDUMP);
848 +
849 +       for (i = 0; i < nr_chunks; i++) {
850 +               unsigned int offset = i*1024;
851 +               reply.code = REPLY_MEM;
852 +               reply.info = offset;
853 +               send_netdump_skb(dev, kaddr + offset, 1024, &reply);
854 +       }
855 +
856 +//     kunmap_atomic(kaddr, KM_NETDUMP);
857 +}
858 +
859 +
860 +/*
861 + * This function waits for the client to acknowledge the receipt
862 + * of the netdump startup reply, with the possibility of packets
863 + * getting lost. We resend the startup packet if no ACK is received,
864 + * after a 1 second delay.
865 + *
866 + * (The client can test the success of the handshake via the HELLO
867 + * command, and send ACKs until we enter netdump mode.)
868 + */
869 +static void netdump_startup_handshake(struct net_device *dev)
870 +{
871 +       char tmp[200];
872 +       reply_t reply;
873 +       req_t *req = NULL;
874 +       int i;
875 +
876 +       netdump_mode = 1;
877 +
878 +repeat:
879 +       sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
880 +       reply.code = REPLY_START_NETDUMP;
881 +       reply.nr = 0;
882 +       reply.info = 0;
883 +       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
884 +
885 +       for (i = 0; i < 10000; i++) {
886 +               // wait 1 sec.
887 +               udelay(100);
888 +               Dprintk("handshake: polling controller ...\n");
889 +               netdump_poll(dev);              
890 +               zap_completion_queue();
891 +               req = get_new_req();
892 +               if (req)
893 +                       break;
894 +       }
895 +       if (!req)
896 +               goto repeat;
897 +       if (req->command != COMM_START_NETDUMP_ACK) {
898 +               kfree(req);
899 +               goto repeat;
900 +       }
901 +       kfree(req);
902 +
903 +       printk("NETDUMP START!\n");
904 +}
905 +
906 +#if 0
907 +
908 +static inline void print_status (req_t *req)
909 +{
910 +       static int count = 0;
911 +
912 +       switch (++count & 3) {
913 +               case 0: printk("/\r"); break;
914 +               case 1: printk("|\r"); break;
915 +               case 2: printk("\\\r"); break;
916 +               case 3: printk("-\r"); break;
917 +       }
918 +}
919 +
920 +#else
921 +
922 +static inline void print_status (req_t *req)
923 +{
924 +       static int count = 0;
925 +       static int prev_jiffies = 0;
926 +
927 +       if (jiffies/HZ != prev_jiffies/HZ) {
928 +               prev_jiffies = jiffies;
929 +               count++;
930 +               switch (count & 3) {
931 +                       case 0: printk("%d(%ld)/\r", nr_req, jiffies); break;
932 +                       case 1: printk("%d(%ld)|\r", nr_req, jiffies); break;
933 +                       case 2: printk("%d(%ld)\\\r", nr_req, jiffies); break;
934 +                       case 3: printk("%d(%ld)-\r", nr_req, jiffies); break;
935 +               }
936 +       }
937 +}
938 +
939 +#endif
940 +
941 +#define CLI 1
942 +
943 +#if CONFIG_SMP
944 +static void freeze_cpu (void * dummy)
945 +{
946 +       printk("CPU#%d is frozen.\n", smp_processor_id());
947 +#if CLI
948 +       for (;;) __cli();
949 +#else
950 +       for (;;) __sti();
951 +#endif
952 +}
953 +#endif
954 +
955 +static void netconsole_netdump (struct pt_regs *regs)
956 +{
957 +       reply_t reply;
958 +       char tmp[200];
959 +       unsigned long flags;
960 +       struct net_device *dev = netconsole_dev;
961 +       unsigned long esp;
962 +       unsigned short ss;
963 +       struct pt_regs myregs;
964 +       req_t *req;
965 +
966 +       __save_flags(flags);
967 +       __cli();
968 +#if CONFIG_X86_LOCAL_APIC
969 +       //nmi_watchdog = 0;
970 +#endif
971 +#if CONFIG_SMP
972 +       smp_call_function(freeze_cpu, NULL, 1, 0);
973 +#endif
974 +       mdelay(1000);
975 +       /*
976 +        * Just in case we are crashing within the networking code
977 +        * ... attempt to fix up.
978 +        */
979 +       spin_lock_init(&dev->xmit_lock);
980 +
981 +       esp = (unsigned long) ((char *)regs + sizeof (struct pt_regs));
982 +       ss = __KERNEL_DS;
983 +       if (regs->xcs & 3) {
984 +               esp = regs->esp;
985 +               ss = regs->xss & 0xffff;
986 +       }
987 +       myregs = *regs;
988 +       myregs.esp = esp;
989 +       myregs.xss = (myregs.xss & 0xffff0000) | ss;
990 +
991 +       rdtscll(t0);
992 +
993 +       printk("< netdump activated - performing handshake with the client. >\n");
994 +       netdump_startup_handshake(dev);
995 +
996 +       printk("< handshake completed - listening for dump requests. >\n");
997 +
998 +       while (netdump_mode) {
999 +               __cli();
1000 +               Dprintk("main netdump loop: polling controller ...\n");
1001 +               netdump_poll(dev);
1002 +               zap_completion_queue();
1003 +#if !CLI
1004 +               __sti();
1005 +#endif
1006 +               req = get_new_req();
1007 +               if (!req)
1008 +                       continue;
1009 +               Dprintk("got new req, command %d.\n", req->command);
1010 +               print_status(req);
1011 +               switch (req->command) {
1012 +               case COMM_NONE:
1013 +                       Dprintk("got NO command.\n");
1014 +                       break;
1015 +
1016 +               case COMM_SEND_MEM:
1017 +                       Dprintk("got MEM command.\n");
1018 +                       // send ->from ->to.
1019 +                       send_netdump_mem(dev, req);
1020 +                       break;
1021 +
1022 +               case COMM_EXIT:
1023 +                       Dprintk("got EXIT command.\n");
1024 +                       netdump_mode = 0;
1025 +                       break;
1026 +
1027 +               case COMM_REBOOT:
1028 +                       Dprintk("got REBOOT command.\n");
1029 +                       printk("netdump: rebooting in 3 seconds.\n");
1030 +                       mdelay(3000);
1031 +                       machine_restart(NULL);
1032 +                       break;
1033 +
1034 +               case COMM_HELLO:
1035 +                       sprintf(tmp, "Hello, this is netdump version 0.%02d\n", NETCONSOLE_VERSION);
1036 +                       reply.code = REPLY_HELLO;
1037 +                       reply.nr = req->nr;
1038 +                       reply.info = NETCONSOLE_VERSION;
1039 +                       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1040 +                       break;
1041 +
1042 +               case COMM_GET_PAGE_SIZE:
1043 +                       sprintf(tmp, "PAGE_SIZE: %ld\n", PAGE_SIZE);
1044 +                       reply.code = REPLY_PAGE_SIZE;
1045 +                       reply.nr = req->nr;
1046 +                       reply.info = PAGE_SIZE;
1047 +                       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1048 +                       break;
1049 +
1050 +               case COMM_GET_REGS:
1051 +               {
1052 +                       char *tmp2 = tmp;
1053 +                       elf_gregset_t elf_regs;
1054 +
1055 +                       reply.code = REPLY_REGS;
1056 +                       reply.nr = req->nr;
1057 +                       reply.info = max_mapnr;
1058 +                       tmp2 = tmp + sprintf(tmp, "Sending register info.\n");
1059 +                       ELF_CORE_COPY_REGS(elf_regs, regs);
1060 +                       memcpy(tmp2, &elf_regs, sizeof(elf_regs));
1061 +                       send_netdump_skb(dev, tmp, strlen(tmp) + sizeof(elf_regs), &reply);
1062 +                       break;
1063 +               }
1064 +
1065 +               case COMM_GET_NR_PAGES:
1066 +                       reply.code = REPLY_NR_PAGES;
1067 +                       reply.nr = req->nr;
1068 +                       reply.info = max_mapnr;
1069 +                       sprintf(tmp, "Number of pages: %ld\n", max_mapnr);
1070 +                       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1071 +                       break;
1072 +
1073 +               case COMM_SHOW_STATE:
1074 +                       netdump_mode = 0;
1075 +                       //if (regs)
1076 +                               //show_regs(regs);
1077 +                       //show_state();
1078 +                       //show_mem();
1079 +                       netdump_mode = 1;
1080 +                       reply.code = REPLY_SHOW_STATE;
1081 +                       reply.nr = req->nr;
1082 +                       reply.info = 0;
1083 +                       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1084 +                       break;
1085 +
1086 +               default:
1087 +                       reply.code = REPLY_ERROR;
1088 +                       reply.nr = req->nr;
1089 +                       reply.info = req->command;
1090 +                       Dprintk("got UNKNOWN command!\n");
1091 +                       sprintf(tmp, "Got unknown command code %d!\n", req->command);
1092 +                       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1093 +                       break;
1094 +               }
1095 +               kfree(req);
1096 +               req = NULL;
1097 +       }
1098 +       sprintf(tmp, "NETDUMP end.\n");
1099 +       reply.code = REPLY_END_NETDUMP;
1100 +       reply.nr = 0;
1101 +       reply.info = 0;
1102 +       send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1103 +       printk("NETDUMP END!\n");
1104 +       __restore_flags(flags);
1105 +}
1106 +static int netconsole_sysrq_schedule(void *arg) 
1107 +{
1108 +       struct task_struct *tsk = current;
1109 +
1110 +       sprintf(tsk->comm, "sysrq_schedule");
1111 +       sigfillset(&tsk->blocked);
1112 +
1113 +       /* main loop */
1114 +       thread_stopped = 0;     
1115 +       for (;;) {
1116 +               wait_event_interruptible(sysrq_thread_queue,
1117 +                                        !list_empty(&request_list) || stop_sysrq_thread);
1118 +               while (!list_empty(&request_list)) {
1119 +                       req_t *req = get_new_req();
1120 +                       Dprintk("get new req %d from req_list\n", (int)req->command);
1121 +                       if (req->command == COMM_SYSRQ) 
1122 +                               netconsole_do_sysrq(req);       
1123 +               }
1124 +               if (stop_sysrq_thread)
1125 +                       break;
1126 +               wake_up(&sysrq_thread_waiter_queue);
1127 +       }
1128 +       thread_stopped = 1;     
1129 +       wake_up(&sysrq_thread_waiter_queue);
1130 +       return 0;
1131 +}
1132 +
1133 +
1134 +static char *dev;
1135 +static int netdump_target_eth_byte0 = 255;
1136 +static int netdump_target_eth_byte1 = 255;
1137 +static int netdump_target_eth_byte2 = 255;
1138 +static int netdump_target_eth_byte3 = 255;
1139 +static int netdump_target_eth_byte4 = 255;
1140 +static int netdump_target_eth_byte5 = 255;
1141 +
1142 +static int netlog_target_eth_byte0 = 255;
1143 +static int netlog_target_eth_byte1 = 255;
1144 +static int netlog_target_eth_byte2 = 255;
1145 +static int netlog_target_eth_byte3 = 255;
1146 +static int netlog_target_eth_byte4 = 255;
1147 +static int netlog_target_eth_byte5 = 255;
1148 +
1149 +static int syslog_target_eth_byte0 = 255;
1150 +static int syslog_target_eth_byte1 = 255;
1151 +static int syslog_target_eth_byte2 = 255;
1152 +static int syslog_target_eth_byte3 = 255;
1153 +static int syslog_target_eth_byte4 = 255;
1154 +static int syslog_target_eth_byte5 = 255;
1155 +
1156 +MODULE_PARM(netdump_target_ip, "i");
1157 +MODULE_PARM_DESC(netdump_target_ip,
1158 +       "remote netdump IP address as a native (not network) endian integer");
1159 +MODULE_PARM(netlog_target_ip, "i");
1160 +MODULE_PARM_DESC(netlog_target_ip,
1161 +       "remote netlog IP address as a native (not network) endian integer");
1162 +MODULE_PARM(syslog_target_ip, "i");
1163 +MODULE_PARM_DESC(syslog_target_ip,
1164 +       "remote syslog IP address as a native (not network) endian integer");
1165 +
1166 +MODULE_PARM(source_port, "h");
1167 +MODULE_PARM_DESC(source_port,
1168 +       "local port from which to send netdump packets");
1169 +
1170 +MODULE_PARM(netdump_target_port, "h");
1171 +MODULE_PARM_DESC(netdump_target_port,
1172 +       "remote port to which to send netdump packets");
1173 +MODULE_PARM(netlog_target_port, "h");
1174 +MODULE_PARM_DESC(netlog_target_port,
1175 +       "remote port to which to send netlog packets");
1176 +MODULE_PARM(syslog_target_port, "h");
1177 +MODULE_PARM_DESC(syslog_target_port,
1178 +       "remote port to which to send syslog packets");
1179 +
1180 +#define ETH_BYTE(name,nr) \
1181 +       MODULE_PARM(name##_target_eth_byte##nr, "i"); \
1182 +       MODULE_PARM_DESC(name##_target_eth_byte##nr, \
1183 +               "byte "#nr" of the netdump server MAC address")
1184 +
1185 +#define ETH_BYTES(name) \
1186 +       ETH_BYTE(name, 0); ETH_BYTE(name, 1); ETH_BYTE(name, 2); \
1187 +       ETH_BYTE(name, 3); ETH_BYTE(name, 4); ETH_BYTE(name, 5);
1188 +
1189 +ETH_BYTES(netdump);
1190 +ETH_BYTES(netlog);
1191 +ETH_BYTES(syslog);
1192 +
1193 +MODULE_PARM(magic1, "i");
1194 +MODULE_PARM_DESC(magic1,
1195 +       "lower 32 bits of magic cookie shared between client and server");
1196 +MODULE_PARM(magic2, "i");
1197 +MODULE_PARM_DESC(magic2,
1198 +       "upper 32 bits of magic cookie shared between client and server");
1199 +MODULE_PARM(dev, "s");
1200 +MODULE_PARM_DESC(dev,
1201 +       "name of the device from which to send netdump and syslog packets");
1202 +MODULE_PARM(mhz, "i");
1203 +MODULE_PARM_DESC(mhz,
1204 +       "one second wall clock time takes this many million CPU cycles");
1205 +MODULE_PARM(idle_timeout, "i");
1206 +MODULE_PARM_DESC(idle_timeout,
1207 +       "reboot system after this many idle seconds");
1208 +
1209 +static struct console netconsole =
1210 +        { flags: CON_ENABLED, write: write_netconsole_msg };
1211 +static int init_netconsole(void)
1212 +{
1213 +       struct net_device *ndev = NULL;
1214 +       struct in_device *in_dev;
1215 +       struct irqaction *action;
1216 +       int rc = 0;
1217 +
1218 +       printk(KERN_INFO "netlog: using network device <%s>\n", dev);
1219 +       // this will be valid once the device goes up.
1220 +       if (dev)
1221 +               ndev = dev_get_by_name(dev);
1222 +       if (!ndev) {
1223 +               printk(KERN_ERR "netlog: network device %s does not exist, aborting.\n", dev);
1224 +               return -1;
1225 +       }
1226 +       in_dev = in_dev_get(ndev);
1227 +       if (!in_dev) {
1228 +               printk(KERN_ERR "netlog: network device %s is not an IP protocol device, aborting.\n", dev);
1229 +               return -1;
1230 +       }
1231 +
1232 +       if (!magic1 || !magic2) {
1233 +               printk(KERN_ERR "netlog: magic cookie (magic1,magic2) not specified.\n");
1234 +               return -1;
1235 +       }
1236 +       netconsole_magic = magic1 + (((u64)magic2)<<32);
1237 +
1238 +       source_ip = ntohl(in_dev->ifa_list->ifa_local);
1239 +       if (!source_ip) {
1240 +               printk(KERN_ERR "netlog: network device %s has no local address, aborting.\n", dev);
1241 +               return -1;
1242 +       }
1243 +#define IP(x) ((unsigned char *)&source_ip)[x]
1244 +       printk(KERN_INFO "netlog: using source IP %u.%u.%u.%u\n",
1245 +               IP(3), IP(2), IP(1), IP(0));
1246 +#undef IP
1247 +       source_ip = htonl(source_ip);
1248 +       if (!source_port) {
1249 +               printk(KERN_ERR "netlog: source_port parameter not specified, aborting.\n");
1250 +               return -1;
1251 +       }
1252 +       printk(KERN_INFO "netlog: using source UDP port: %u\n", source_port);
1253 +       source_port = htons(source_port);
1254 +
1255 +       if (!netdump_target_ip && !netlog_target_ip && !syslog_target_ip) {
1256 +               printk(KERN_ERR "netlog: target_ip parameter not specified, aborting.\n");
1257 +               return -1;
1258 +#define IP(x) ((unsigned char *)&netdump_target_ip)[x]
1259 +               printk(KERN_INFO "netlog: using netdump target IP %u.%u.%u.%u\n",
1260 +                       IP(3), IP(2), IP(1), IP(0));
1261 +#undef IP
1262 +               netdump_target_ip = htonl(netdump_target_ip);
1263 +       }
1264 +       if (netlog_target_ip) {
1265 +#define IP(x) ((unsigned char *)&netlog_target_ip)[x]
1266 +               printk(KERN_INFO "netlog: using netlog target IP %u.%u.%u.%u\n",
1267 +                       IP(3), IP(2), IP(1), IP(0));
1268 +#undef IP
1269 +               netlog_target_ip = htonl(netlog_target_ip);
1270 +       }
1271 +       if (syslog_target_ip) {
1272 +               if (!syslog_target_port)
1273 +                       syslog_target_port = 514;
1274 +#define IP(x) ((unsigned char *)&syslog_target_ip)[x]
1275 +               printk("netlog: using syslog target IP %u.%u.%u.%u, port: %d\n", IP(3), IP(2), IP(1), IP(0), syslog_target_port);
1276 +#undef IP
1277 +               syslog_target_ip = htonl(syslog_target_ip);
1278 +               syslog_target_port = htons(syslog_target_port);
1279 +       }
1280 +       if (!netdump_target_port && !netlog_target_port && !syslog_target_port) {
1281 +               printk(KERN_ERR "netlog: target_port parameter not specified, aborting.\n");
1282 +               return -1;
1283 +       }
1284 +       if (netdump_target_port) {
1285 +               printk(KERN_INFO "netlog: using target UDP port: %u\n", netdump_target_port);
1286 +               netdump_target_port = htons(netdump_target_port);
1287 +       }
1288 +       if (netlog_target_port) {
1289 +               printk(KERN_INFO "netlog: using target UDP port: %u\n", netlog_target_port);
1290 +               netlog_target_port = htons(netlog_target_port);
1291 +       }
1292 +
1293 +       netdump_daddr[0] = netdump_target_eth_byte0;
1294 +       netdump_daddr[1] = netdump_target_eth_byte1;
1295 +       netdump_daddr[2] = netdump_target_eth_byte2;
1296 +       netdump_daddr[3] = netdump_target_eth_byte3;
1297 +       netdump_daddr[4] = netdump_target_eth_byte4;
1298 +       netdump_daddr[5] = netdump_target_eth_byte5;
1299 +
1300 +       if ((netdump_daddr[0] & netdump_daddr[1] & netdump_daddr[2] & netdump_daddr[3] & netdump_daddr[4] & netdump_daddr[5]) == 255)
1301 +               printk(KERN_INFO "netlog: using broadcast ethernet frames to send netdump packets.\n");
1302 +       else
1303 +               printk(KERN_INFO "netlog: using netdump target ethernet address %02x:%02x:%02x:%02x:%02x:%02x.\n",
1304 +                               netdump_daddr[0], netdump_daddr[1], netdump_daddr[2], netdump_daddr[3], netdump_daddr[4], netdump_daddr[5]);
1305 +
1306 +       netlog_daddr[0] = netlog_target_eth_byte0;
1307 +       netlog_daddr[1] = netlog_target_eth_byte1;
1308 +       netlog_daddr[2] = netlog_target_eth_byte2;
1309 +       netlog_daddr[3] = netlog_target_eth_byte3;
1310 +       netlog_daddr[4] = netlog_target_eth_byte4;
1311 +       netlog_daddr[5] = netlog_target_eth_byte5;
1312 +
1313 +       if ((netlog_daddr[0] & netlog_daddr[1] & netlog_daddr[2] & netlog_daddr[3] & netlog_daddr[4] & netlog_daddr[5]) == 255)
1314 +               printk(KERN_INFO "netlog: using broadcast ethernet frames to send netdump packets.\n");
1315 +       else
1316 +               printk(KERN_INFO "netlog: using netdump target ethernet address %02x:%02x:%02x:%02x:%02x:%02x.\n",
1317 +                               netlog_daddr[0], netlog_daddr[1], netlog_daddr[2], netlog_daddr[3], netlog_daddr[4], netlog_daddr[5]);
1318 +       syslog_daddr[0] = syslog_target_eth_byte0;
1319 +       syslog_daddr[1] = syslog_target_eth_byte1;
1320 +       syslog_daddr[2] = syslog_target_eth_byte2;
1321 +       syslog_daddr[3] = syslog_target_eth_byte3;
1322 +       syslog_daddr[4] = syslog_target_eth_byte4;
1323 +       syslog_daddr[5] = syslog_target_eth_byte5;
1324 +
1325 +       if ((syslog_daddr[0] & syslog_daddr[1] & syslog_daddr[2] & syslog_daddr[3] & syslog_daddr[4] & syslog_daddr[5]) == 255)
1326 +               printk(KERN_INFO "netlog: using broadcast ethernet frames to send syslog packets.\n");
1327 +       else
1328 +               printk(KERN_INFO "netlog: using syslog target ethernet address %02x:%02x:%02x:%02x:%02x:%02x.\n",
1329 +                               syslog_daddr[0], syslog_daddr[1], syslog_daddr[2], syslog_daddr[3], syslog_daddr[4], syslog_daddr[5]);
1330 +
1331 +       mhz_cycles = (unsigned long long)mhz * 1000000ULL;
1332 +       jiffy_cycles = (unsigned long long)mhz * (1000000/HZ);
1333 +       
1334 +       ndev->rx_hook = netconsole_rx_hook;
1335 +       netdump_func = netconsole_netdump;
1336 +       netconsole_dev = ndev;
1337 +       /* find irq function of the ndev*/
1338 +       action=find_irq_action(ndev->irq, ndev);
1339 +        if (!action) {
1340 +               printk(KERN_ERR "couldn't find irq handler for <%s>", dev);
1341 +               return -1;
1342 +       }
1343 +       irqfunc = action->handler;
1344 +
1345 +       stop_sysrq_thread = 0;
1346 +       INIT_LIST_HEAD(&request_list);
1347 +       init_waitqueue_head(&sysrq_thread_queue);
1348 +       init_waitqueue_head(&sysrq_thread_waiter_queue);
1349 +       if ((rc = kernel_thread(netconsole_sysrq_schedule, NULL, 0)) < 0 ){
1350 +              printk(KERN_ERR "Can not start netconsole sysrq thread: rc %d\n", rc); 
1351 +             return -1; 
1352 +       }
1353 +
1354 +#define STARTUP_MSG "[...network console startup...]\n"
1355 +       write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG));
1356 +
1357 +       register_console(&netconsole);
1358 +       printk(KERN_INFO "netlog: network logging started up successfully!\n");
1359 +       return 0;
1360 +}
1361 +
1362 +static void cleanup_netconsole(void)
1363 +{
1364 +       stop_sysrq_thread = 1;
1365 +       
1366 +       wake_up(&sysrq_thread_queue);
1367 +       wait_event(sysrq_thread_waiter_queue, thread_stopped); 
1368 +       printk(KERN_INFO"netlog: network logging shut down.\n");
1369 +       unregister_console(&netconsole);
1370 +
1371 +#define SHUTDOWN_MSG "[...network console shutdown...]\n"
1372 +       write_netconsole_msg(NULL, SHUTDOWN_MSG, strlen(SHUTDOWN_MSG));
1373 +       netconsole_dev->rx_hook = NULL;
1374 +       netconsole_dev = NULL;
1375 +}
1376 +
1377 +module_init(init_netconsole);
1378 +module_exit(cleanup_netconsole);
1379 +
1380 +MODULE_LICENSE("GPL");
1381 +
1382 Index: linux-2.4.24/drivers/net/netconsole.h
1383 ===================================================================
1384 --- linux-2.4.24.orig/drivers/net/netconsole.h  2003-01-30 18:24:37.000000000 +0800
1385 +++ linux-2.4.24/drivers/net/netconsole.h       2004-06-09 14:14:54.000000000 +0800
1386 @@ -0,0 +1,102 @@
1387 +/*
1388 + *  linux/drivers/net/netconsole.h
1389 + *
1390 + *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
1391 + *
1392 + *  This file contains the implementation of an IRQ-safe, crash-safe
1393 + *  kernel console implementation that outputs kernel messages to the
1394 + *  network.
1395 + *
1396 + * Modification history:
1397 + *
1398 + * 2001-09-17    started by Ingo Molnar.
1399 + */
1400 +
1401 +/****************************************************************
1402 + *      This program is free software; you can redistribute it and/or modify
1403 + *      it under the terms of the GNU General Public License as published by
1404 + *      the Free Software Foundation; either version 2, or (at your option)
1405 + *      any later version.
1406 + *
1407 + *      This program is distributed in the hope that it will be useful,
1408 + *      but WITHOUT ANY WARRANTY; without even the implied warranty of
1409 + *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1410 + *      GNU General Public License for more details.
1411 + *
1412 + *      You should have received a copy of the GNU General Public License
1413 + *      along with this program; if not, write to the Free Software
1414 + *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1415 + *
1416 + ****************************************************************/
1417 +
1418 +#define NETCONSOLE_VERSION 0x03
1419 +
1420 +enum netdump_commands {
1421 +       COMM_NONE = 0,
1422 +       COMM_SEND_MEM = 1,
1423 +       COMM_EXIT = 2,
1424 +       COMM_REBOOT = 3,
1425 +       COMM_HELLO = 4,
1426 +       COMM_GET_NR_PAGES = 5,
1427 +       COMM_GET_PAGE_SIZE = 6,
1428 +       COMM_START_NETDUMP_ACK = 7,
1429 +       COMM_GET_REGS = 8,
1430 +       COMM_SHOW_STATE = 9,
1431 +       COMM_START_WRITE_NETDUMP_ACK = 10,
1432 +        COMM_SYSRQ = 11,
1433 +};
1434 +
1435 +#define NETDUMP_REQ_SIZE (8+4*4)
1436 +
1437 +typedef struct netdump_req_s {
1438 +       u64 magic;
1439 +       u32 nr;
1440 +       u32 command;
1441 +       u32 from;
1442 +       u32 to;
1443 +       struct list_head list; 
1444 +} req_t;
1445 +
1446 +enum netdump_replies {
1447 +       REPLY_NONE = 0,
1448 +       REPLY_ERROR = 1,
1449 +       REPLY_LOG = 2,
1450 +       REPLY_MEM = 3,
1451 +       REPLY_RESERVED = 4,
1452 +       REPLY_HELLO = 5,
1453 +       REPLY_NR_PAGES = 6,
1454 +       REPLY_PAGE_SIZE = 7,
1455 +       REPLY_START_NETDUMP = 8,
1456 +       REPLY_END_NETDUMP = 9,
1457 +       REPLY_REGS = 10,
1458 +       REPLY_MAGIC = 11,
1459 +       REPLY_SHOW_STATE = 12,
1460 +       REPLY_SYSRQ = 13,
1461 +};
1462 +
1463 +typedef struct netdump_reply_s {
1464 +       u32 nr;
1465 +       u32 code;
1466 +       u32 info;
1467 +} reply_t;
1468 +
1469 +#define HEADER_LEN (1 + sizeof(reply_t))
1470 +/* for netconsole */
1471 +static inline void get_current_regs(struct pt_regs *regs)
1472 +{
1473 +       __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
1474 +       __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
1475 +       __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
1476 +       __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
1477 +       __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
1478 +       __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
1479 +       __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
1480 +       __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
1481 +       __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
1482 +       __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
1483 +       __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
1484 +       __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
1485 +       __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
1486 +       regs->eip = (unsigned long)current_text_addr();
1487 +}
1488 +               
1489 Index: linux-2.4.24/drivers/net/Makefile
1490 ===================================================================
1491 --- linux-2.4.24.orig/drivers/net/Makefile      2003-11-29 02:26:20.000000000 +0800
1492 +++ linux-2.4.24/drivers/net/Makefile   2004-06-09 14:16:14.000000000 +0800
1493 @@ -250,6 +250,8 @@
1494  obj-y          += ../acorn/net/acorn-net.o
1495  endif
1496  
1497 +obj-$(CONFIG_NETCONSOLE) += netconsole.o
1498 +
1499  #
1500  # HIPPI adapters
1501  #
1502 Index: linux-2.4.24/drivers/net/Config.in
1503 ===================================================================
1504 --- linux-2.4.24.orig/drivers/net/Config.in     2003-11-29 02:26:20.000000000 +0800
1505 +++ linux-2.4.24/drivers/net/Config.in  2004-06-09 14:17:33.000000000 +0800
1506 @@ -294,7 +294,7 @@
1507     fi
1508     dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
1509  fi
1510 -
1511 +tristate 'Network logging support' CONFIG_NETCONSOLE
1512  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
1513     if [ "$CONFIG_INET" = "y" ]; then
1514        bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
1515 Index: linux-2.4.24/arch/i386/kernel/traps.c
1516 ===================================================================
1517 --- linux-2.4.24.orig/arch/i386/kernel/traps.c  2004-06-09 14:10:04.000000000 +0800
1518 +++ linux-2.4.24/arch/i386/kernel/traps.c       2004-06-09 14:29:00.000000000 +0800
1519 @@ -279,6 +279,8 @@
1520  bug:
1521         printk("Kernel BUG\n");
1522  }
1523 +void (*netdump_func) (struct pt_regs *regs) = NULL;
1524 +int netdump_mode = 0;
1525  
1526  spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
1527  
1528 @@ -290,6 +292,8 @@
1529         handle_BUG(regs);
1530         printk("%s: %04lx\n", str, err & 0xffff);
1531         show_registers(regs);
1532 +        if (netdump_func)
1533 +                netdump_func(regs);
1534         bust_spinlocks(0);
1535         spin_unlock_irq(&die_lock);
1536         do_exit(SIGSEGV);
1537 @@ -1039,5 +1043,7 @@
1538         return -ENOSYS;
1539  }
1540  
1541 +EXPORT_SYMBOL_GPL(netdump_func);
1542 +EXPORT_SYMBOL_GPL(netdump_mode);
1543  EXPORT_SYMBOL_GPL(is_kernel_text_address);
1544  EXPORT_SYMBOL_GPL(lookup_symbol);
1545 Index: linux-2.4.24/arch/i386/kernel/irq.c
1546 ===================================================================
1547 --- linux-2.4.24.orig/arch/i386/kernel/irq.c    2004-06-09 14:09:59.000000000 +0800
1548 +++ linux-2.4.24/arch/i386/kernel/irq.c 2004-06-09 14:53:34.000000000 +0800
1549 @@ -1048,6 +1048,21 @@
1550         return 0;
1551  }
1552  
1553 +struct irqaction *find_irq_action(unsigned int irq, void *dev_id)
1554 +{
1555 +       struct irqaction *a, *r=0;
1556 +                                                                                                                                                                                                     
1557 +       spin_lock_irq(&irq_desc[irq].lock);
1558 +       for(a=irq_desc[irq].action; a; a=a->next) {
1559 +               if(a->dev_id == dev_id) {
1560 +                       r=a;
1561 +                       break;
1562 +               }
1563 +       }
1564 +       spin_unlock_irq(&irq_desc[irq].lock);
1565 +       return r;
1566 +}
1567 +
1568  static struct proc_dir_entry * root_irq_dir;
1569  static struct proc_dir_entry * irq_dir [NR_IRQS];
1570  
1571 Index: linux-2.4.24/arch/i386/kernel/i386_ksyms.c
1572 ===================================================================
1573 --- linux-2.4.24.orig/arch/i386/kernel/i386_ksyms.c     2003-11-29 02:26:19.000000000 +0800
1574 +++ linux-2.4.24/arch/i386/kernel/i386_ksyms.c  2004-06-09 14:55:11.000000000 +0800
1575 @@ -66,6 +66,7 @@
1576  EXPORT_SYMBOL(iounmap);
1577  EXPORT_SYMBOL(enable_irq);
1578  EXPORT_SYMBOL(disable_irq);
1579 +EXPORT_SYMBOL(find_irq_action);
1580  EXPORT_SYMBOL(disable_irq_nosync);
1581  EXPORT_SYMBOL(probe_irq_mask);
1582  EXPORT_SYMBOL(kernel_thread);
1583 Index: linux-2.4.24/arch/x86_64/kernel/traps.c
1584 ===================================================================
1585 --- linux-2.4.24.orig/arch/x86_64/kernel/traps.c        2003-11-29 02:26:19.000000000 +0800
1586 +++ linux-2.4.24/arch/x86_64/kernel/traps.c     2004-06-09 14:30:02.000000000 +0800
1587 @@ -80,7 +80,7 @@
1588  extern char iret_address[];
1589  
1590  struct notifier_block *die_chain;
1591 -
1592 +void (*netdump_func) (struct pt_regs *regs) = NULL;
1593  int kstack_depth_to_print = 12;
1594  
1595  #ifdef CONFIG_KALLSYMS
1596 Index: linux-2.4.24/arch/x86_64/kernel/x8664_ksyms.c
1597 ===================================================================
1598 --- linux-2.4.24.orig/arch/x86_64/kernel/x8664_ksyms.c  2003-11-29 02:26:19.000000000 +0800
1599 +++ linux-2.4.24/arch/x86_64/kernel/x8664_ksyms.c       2004-06-09 14:32:14.000000000 +0800
1600 @@ -40,7 +40,7 @@
1601  extern struct drive_info_struct drive_info;
1602  EXPORT_SYMBOL(drive_info);
1603  #endif
1604 -
1605 +int netdump_mode = 0;
1606  /* platform dependent support */
1607  EXPORT_SYMBOL(boot_cpu_data);
1608  EXPORT_SYMBOL(dump_fpu);
1609 @@ -226,6 +226,9 @@
1610  extern void int_ret_from_sys_call(void);
1611  EXPORT_SYMBOL_NOVERS(int_ret_from_sys_call); 
1612  
1613 +EXPORT_SYMBOL_GPL(netdump_func);
1614 +EXPORT_SYMBOL_GPL(netdump_mode);
1615 +
1616  EXPORT_SYMBOL(touch_nmi_watchdog);
1617  
1618  EXPORT_SYMBOL(do_fork);
1619 Index: linux-2.4.24/include/linux/netdevice.h
1620 ===================================================================
1621 --- linux-2.4.24.orig/include/linux/netdevice.h 2004-06-09 14:20:33.000000000 +0800
1622 +++ linux-2.4.24/include/linux/netdevice.h      2004-06-09 18:40:24.000000000 +0800
1623 @@ -435,6 +435,7 @@
1624                                                      unsigned char *haddr);
1625         int                     (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
1626         int                     (*accept_fastpath)(struct net_device *, struct dst_entry*);
1627 +        int                     (*rx_hook)(struct sk_buff *skb);
1628  
1629         /* open/release and usage marking */
1630         struct module *owner;
1631 Index: linux-2.4.24/include/linux/kernel.h
1632 ===================================================================
1633 --- linux-2.4.24.orig/include/linux/kernel.h    2004-06-09 14:20:33.000000000 +0800
1634 +++ linux-2.4.24/include/linux/kernel.h 2004-06-09 18:39:18.000000000 +0800
1635 @@ -105,6 +105,9 @@
1636  extern void bust_spinlocks(int yes);
1637  extern int oops_in_progress;           /* If set, an oops, panic(), BUG() or die() is in progress */
1638  
1639 +extern void (*netdump_func) (struct pt_regs *regs);
1640 +extern int netdump_mode;
1641 +
1642  extern int tainted;
1643  extern const char *print_tainted(void);
1644  
1645 Index: linux-2.4.24/include/asm-i386/irq.h
1646 ===================================================================
1647 --- linux-2.4.24.orig/include/asm-i386/irq.h    2004-06-09 14:20:33.000000000 +0800
1648 +++ linux-2.4.24/include/asm-i386/irq.h 2004-06-09 14:54:04.000000000 +0800
1649 @@ -38,7 +38,7 @@
1650  extern void disable_irq_nosync(unsigned int);
1651  extern void enable_irq(unsigned int);
1652  extern void release_x86_irqs(struct task_struct *);
1653 -
1654 +extern struct irqaction *find_irq_action(unsigned int irq, void *dev_id);
1655  #ifdef CONFIG_X86_LOCAL_APIC
1656  #define ARCH_HAS_NMI_WATCHDOG          /* See include/linux/nmi.h */
1657  #endif
1658 Index: linux-2.4.24/net/core/dev.c
1659 ===================================================================
1660 --- linux-2.4.24.orig/net/core/dev.c    2003-11-29 02:26:21.000000000 +0800
1661 +++ linux-2.4.24/net/core/dev.c 2004-06-09 14:50:03.000000000 +0800
1662 @@ -1287,7 +1287,13 @@
1663         queue = &softnet_data[this_cpu];
1664  
1665         local_irq_save(flags);
1666 -
1667 +        if (unlikely(skb->dev->rx_hook != NULL)) {
1668 +                int ret;
1669 +                                                                                                                                                                                                     
1670 +                ret = skb->dev->rx_hook(skb);
1671 +                if (ret == NET_RX_DROP)
1672 +                        goto drop;
1673 +        }
1674         netdev_rx_stat[this_cpu].total++;
1675         if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
1676                 if (queue->input_pkt_queue.qlen) {