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
7 + * linux/drivers/net/netconsole.c
9 + * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com>
10 + * Copyright (C) 2002 Red Hat, Inc.
12 + * This file contains the implementation of an IRQ-safe, crash-safe
13 + * kernel console implementation that outputs kernel messages to the
16 + * Modification history:
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>
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.
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.
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.
39 + ****************************************************************/
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>
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"
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} ;
71 +static unsigned int mhz = 500, idle_timeout;
72 +static unsigned long long mhz_cycles, jiffy_cycles;
75 +#define MAX_UDP_CHUNK 1460
76 +#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
80 +# define Dprintk(x...) printk(KERN_INFO x)
82 +# define Dprintk(x...)
85 + * We maintain a small pool of fully-sized skbs,
86 + * to make sure the message gets out even in
87 + * extreme OOM situations.
89 +#define MAX_NETCONSOLE_SKBS 128
91 +static spinlock_t netconsole_lock = SPIN_LOCK_UNLOCKED;
92 +static int nr_netconsole_skbs;
93 +static struct sk_buff *netconsole_skbs;
95 +#define MAX_SKB_SIZE \
96 + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
97 + sizeof(struct iphdr) + sizeof(struct ethhdr))
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;
103 +static void send_netconsole_arp(struct net_device *dev);
105 +static void __refill_netconsole_skbs(void)
107 + struct sk_buff *skb;
108 + unsigned long flags;
110 + spin_lock_irqsave(&netconsole_lock, flags);
111 + while (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS) {
112 + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
115 + if (netconsole_skbs)
116 + skb->next = netconsole_skbs;
119 + netconsole_skbs = skb;
120 + nr_netconsole_skbs++;
122 + spin_unlock_irqrestore(&netconsole_lock, flags);
125 +static struct sk_buff * get_netconsole_skb(void)
127 + struct sk_buff *skb;
129 + unsigned long flags;
131 + spin_lock_irqsave(&netconsole_lock, flags);
132 + skb = netconsole_skbs;
134 + netconsole_skbs = skb->next;
136 + nr_netconsole_skbs--;
138 + spin_unlock_irqrestore(&netconsole_lock, flags);
143 +static unsigned long long t0;
147 + * - zap completed output skbs.
148 + * - send ARPs if requested
149 + * - reboot the box if inactive for more than N seconds.
151 +static void zap_completion_queue(void)
153 + unsigned long long t1;
154 + int cpu = smp_processor_id();
156 + if (softnet_data[cpu].completion_queue) {
157 + struct sk_buff *clist;
159 + local_irq_disable();
160 + clist = softnet_data[cpu].completion_queue;
161 + softnet_data[cpu].completion_queue = NULL;
162 + local_irq_enable();
164 + while (clist != NULL) {
165 + struct sk_buff *skb = clist;
166 + clist = clist->next;
172 + Dprintk("got ARP req - sending reply.\n");
174 + send_netconsole_arp(netconsole_dev);
178 + if (idle_timeout) {
180 + if (((t1 - t0) >> 20) > mhz_cycles * (unsigned long long)idle_timeout) {
182 + printk("netdump idle timeout - rebooting in 3 seconds.\n");
184 + machine_restart(NULL);
188 + /* maintain jiffies in a polling fashion, based on rdtsc. */
190 + static unsigned long long prev_tick;
192 + if (t1 - prev_tick >= jiffy_cycles) {
193 + prev_tick += jiffy_cycles;
198 +void (*irqfunc)(int, void *, struct pt_regs *);
200 +static void netdump_poll(struct net_device *dev)
204 + disable_irq(dev->irq);
206 + irqfunc(dev->irq, dev, 0);
208 + if(dev->poll && test_bit(__LINK_STATE_RX_SCHED, &dev->state))
209 + dev->poll(dev, &budget);
211 + enable_irq(dev->irq);
215 +static struct sk_buff * alloc_netconsole_skb(struct net_device *dev, int len, int reserve)
219 + struct sk_buff *skb = NULL;
222 + zap_completion_queue();
223 + if (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS)
224 + __refill_netconsole_skbs();
226 + skb = alloc_skb(len, GFP_ATOMIC);
228 + skb = get_netconsole_skb();
231 + if (once && (count == 1000000)) {
232 + printk("possibly FATAL: out of netconsole skbs!!! will keep retrying.\n");
235 + Dprintk("alloc skb: polling controller ...\n");
241 + atomic_set(&skb->users, 1);
242 + skb_reserve(skb, reserve);
246 +static void transmit_raw_skb(struct sk_buff *skb, struct net_device *dev)
250 + spin_lock(&dev->xmit_lock);
251 + dev->xmit_lock_owner = smp_processor_id();
253 + if (netif_queue_stopped(dev)) {
254 + dev->xmit_lock_owner = -1;
255 + spin_unlock(&dev->xmit_lock);
257 + Dprintk("xmit skb: polling controller ...\n");
259 + zap_completion_queue();
263 + dev->hard_start_xmit(skb, dev);
265 + dev->xmit_lock_owner = -1;
266 + spin_unlock(&dev->xmit_lock);
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)
274 + struct udphdr *udph;
276 + struct ethhdr *eth;
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);
284 + iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
289 + iph->tot_len = htons(ip_len);
293 + iph->protocol = IPPROTO_UDP;
295 + iph->saddr = source_ip;
296 + iph->daddr = target_ip;
297 + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
299 + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
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);
305 + transmit_raw_skb(skb, dev);
308 +static void send_netconsole_arp(struct net_device *dev)
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;
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;
320 + skb = alloc_netconsole_skb(dev, total_len, total_len - arp_data_len);
324 + memcpy(arp, dev->dev_addr, ETH_ALEN);
327 + memcpy(arp, &source_ip, 4);
330 + memcpy(arp, arp_sha, ETH_ALEN);
333 + memcpy(arp, &arp_sip, 4);
336 + skb->len += 2*4 + 2*ETH_ALEN;
338 + arph = (struct arphdr *)skb_push(skb, sizeof(*arph));
340 + arph->ar_hrd = htons(dev->type);
341 + arph->ar_pro = __constant_htons(ETH_P_IP);
342 + arph->ar_hln = ETH_ALEN;
344 + arph->ar_op = __constant_htons(ARPOP_REPLY);
346 + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
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);
352 + transmit_raw_skb(skb, dev);
355 +static void send_netdump_skb(struct net_device *dev, const char *msg, unsigned int msg_len, reply_t *reply)
357 + int total_len, ip_len, udp_len;
358 + struct sk_buff *skb;
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;
364 + skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - HEADER_LEN);
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));
371 + memcpy(skb->data + HEADER_LEN, msg, msg_len);
372 + skb->len += msg_len + HEADER_LEN;
374 + transmit_netconsole_skb(skb, dev, ip_len, udp_len,
375 + source_port, netdump_target_port, source_ip, netdump_target_ip, netdump_daddr);
378 +#define SYSLOG_HEADER_LEN 4
380 +static void send_netlog_skb(struct net_device *dev, const char *msg, unsigned int msg_len, reply_t *reply)
382 + int total_len, ip_len, udp_len;
383 + struct sk_buff *skb;
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;
389 + skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - HEADER_LEN);
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));
396 + memcpy(skb->data + HEADER_LEN, msg, msg_len);
397 + skb->len += msg_len + HEADER_LEN;
399 + transmit_netconsole_skb(skb, dev, ip_len, udp_len,
400 + source_port, netlog_target_port, source_ip, netlog_target_ip, netlog_daddr);
403 +#define SYSLOG_HEADER_LEN 4
405 +static void send_syslog_skb(struct net_device *dev, const char *msg, unsigned int msg_len, int pri)
407 + int total_len, ip_len, udp_len;
408 + struct sk_buff *skb;
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;
414 + skb = alloc_netconsole_skb(dev, total_len, total_len - msg_len - SYSLOG_HEADER_LEN);
416 + skb->data[0] = '<';
417 + skb->data[1] = pri + '0';
421 + memcpy(skb->data + SYSLOG_HEADER_LEN, msg, msg_len);
422 + skb->len += msg_len + SYSLOG_HEADER_LEN;
424 + transmit_netconsole_skb(skb, dev, ip_len, udp_len, source_port,
425 + syslog_target_port, source_ip, syslog_target_ip, syslog_daddr);
428 +#define MAX_SYSLOG_CHARS 1000
430 +static spinlock_t syslog_lock = SPIN_LOCK_UNLOCKED;
431 +static int syslog_chars;
432 +static unsigned char syslog_line [MAX_SYSLOG_CHARS + 10];
435 + * We feed kernel messages char by char, and send the UDP packet
436 + * one linefeed. We buffer all characters received.
438 +static inline void feed_syslog_char(struct net_device *dev, const unsigned char c)
440 + if (syslog_chars == MAX_SYSLOG_CHARS)
442 + syslog_line[syslog_chars] = c;
445 + send_syslog_skb(dev, syslog_line, syslog_chars, 5);
450 +static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
451 +static unsigned int log_offset;
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;
464 +#define SEND_MSG_BUFFER(buf, len) \
468 + unsigned int flags; \
469 + __save_flags(flags); \
471 + reply.code = REPLY_LOG; \
474 + spin_lock(&sequence_lock); \
475 + send_netlog_skb(dev, buf, len, &reply); \
476 + spin_unlock(&sequence_lock); \
477 + __restore_flags(flags); \
480 +void netconsole_do_sysrq(req_t *req)
482 + struct pt_regs regs;
483 + struct net_device *dev = netconsole_dev;
488 + get_current_regs(®s);
489 + handle_sysrq((int)req->from, ®s, 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;
497 + Clear_Sysrq_mode();
499 +static void write_netconsole_msg(struct console *con, const char *msg0, unsigned int msg_len)
502 + struct net_device *dev;
503 + const char *msg = msg0;
506 + dev = netconsole_dev;
507 + if (!dev || netdump_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;
521 + memcpy(send_cache + send_cache_pos, msg + (msg_len -left_len), left_len);
522 + send_cache_pos += left_len;
525 + }else if (netif_running(dev)) {
526 + unsigned long flags;
528 + __save_flags(flags);
531 + if (netlog_target_ip) {
533 + if (left > MAX_PRINT_CHUNK)
534 + len = MAX_PRINT_CHUNK;
537 + reply.code = REPLY_LOG;
539 + spin_lock(&sequence_lock);
540 + reply.info = log_offset;
542 + spin_unlock(&sequence_lock);
543 + send_netlog_skb(dev, msg, len, &reply);
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);
555 + __restore_flags(flags);
559 +static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
561 + return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
564 +static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
565 + unsigned short ulen, u32 saddr, u32 daddr)
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))
573 + skb->ip_summed = CHECKSUM_NONE;
575 + if (skb->ip_summed != CHECKSUM_UNNECESSARY)
576 + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP,
578 + /* Probably, we should checksum udp header (it should be in cache
579 + * in any case) and data in tiny packets (< rx copybreak).
584 +static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
586 + return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
589 +static __inline__ int udp_checksum_complete(struct sk_buff *skb)
591 + return skb->ip_summed != CHECKSUM_UNNECESSARY &&
592 + __udp_checksum_complete(skb);
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.
601 +static u64 netconsole_magic;
602 +static u32 magic1, magic2;
604 +static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
605 +static int nr_req = 0;
606 +static LIST_HEAD(request_list);
608 +static void add_new_req(req_t *req)
610 + unsigned long flags;
612 + spin_lock_irqsave(&req_lock, flags);
613 + list_add_tail(&req->list, &request_list);
615 + Dprintk("pending requests: %d.\n", nr_req);
616 + spin_unlock_irqrestore(&req_lock, flags);
621 +static req_t *get_new_req(void)
624 + unsigned long flags;
626 + spin_lock_irqsave(&req_lock, flags);
628 + req = list_entry(request_list.next, req_t, list);
629 + list_del(&req->list);
632 + spin_unlock_irqrestore(&req_lock, flags);
637 +static req_t *alloc_req(void)
641 + req = (req_t *) kmalloc(sizeof(*req), GFP_ATOMIC);
645 +static int netconsole_rx_hook(struct sk_buff *skb)
650 + __u32 len, saddr, daddr, ulen;
653 + struct net_device *dev;
657 + static int packet_count;
658 + Dprintk(" %d\r", ++packet_count);
662 + if (dev->type != ARPHRD_ETHER)
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));
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));
672 + if (skb->pkt_type == PACKET_OTHERHOST)
674 + if (skb_shared(skb))
676 + if (proto == ETH_P_ARP) {
677 + struct arphdr *arp;
678 + unsigned char *arp_ptr;
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))
684 + if (htons(dev->type) != arp->ar_hrd)
686 + if (arp->ar_pro != __constant_htons(ETH_P_IP))
688 + if (arp->ar_hln != ETH_ALEN)
690 + if (arp->ar_pln != 4)
692 + if (arp->ar_op != __constant_htons(ARPOP_REQUEST))
695 + * ARP header looks ok so far, extract fields:
697 + arp_ptr = (unsigned char *)(arp + 1);
699 + memcpy(arp_sha, arp_ptr, ETH_ALEN);
700 + arp_ptr += ETH_ALEN;
702 + memcpy(&arp_sip, arp_ptr, 4);
705 + memcpy(arp_tha, arp_ptr, ETH_ALEN);
706 + arp_ptr += ETH_ALEN;
708 + memcpy(&arp_tip, arp_ptr, 4);
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));
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));
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));
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));
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));
726 + if (LOOPBACK(arp_tip) || MULTICAST(arp_tip))
729 + if (arp_tip != source_ip)
734 + if (proto != ETH_P_IP)
737 + * IP header correctness testing:
739 + iph = (struct iphdr *)skb->data;
740 + if (!pskb_may_pull(skb, sizeof(struct iphdr)))
742 + Dprintk("... IP ihl*4: %d, version: %d.\n", iph->ihl*4, iph->version);
743 + if (iph->ihl < 5 || iph->version != 4)
745 + if (!pskb_may_pull(skb, iph->ihl*4))
747 + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
749 + len = ntohs(iph->tot_len);
750 + Dprintk("... IP len: %d.\n", len);
751 + if (skb->len < len || len < iph->ihl*4)
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)
759 + Dprintk("... netdump src: %08x, dst: %08x.\n", source_ip, netlog_target_ip);
760 + if (source_ip != daddr)
762 + if (netlog_target_ip != saddr)
765 + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
766 + ulen = ntohs(uh->len);
767 + Dprintk("... UDP len: %d (left %d).\n", ulen, len);
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");
774 + if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) {
775 + Dprintk("... UDP, hm, checksum init not ok.\n");
778 + if (udp_checksum_complete(skb)) {
779 + Dprintk("... UDP, hm, checksum complete not ok.\n");
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)
786 + if (netlog_target_port != uh->dest)
788 + __req = (req_t *)(uh + 1);
789 + Dprintk("... UDP netdump packet OK!\n");
793 + printk("no more RAM to allocate request - dropping it.\n");
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);
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);
810 + else if (req->command == COMM_SYSRQ){
812 + wake_up(&sysrq_thread_queue);
813 + return NET_RX_DROP;
817 + return NET_RX_SUCCESS;
818 + return NET_RX_DROP;
821 +#define INVALID_PAGE "page is not valid!\n"
823 +static void send_netdump_mem (struct net_device *dev, req_t *req)
829 + unsigned long nr = req->from;
830 + int nr_chunks = PAGE_SIZE/1024;
835 + reply.nr = req->nr;
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);
843 + page = mem_map + nr;
844 + if (PageReserved(page))
845 + page = ZERO_PAGE(0);
847 +// kaddr = (char *)kmap_atomic(page, KM_NETDUMP);
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);
856 +// kunmap_atomic(kaddr, KM_NETDUMP);
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.
866 + * (The client can test the success of the handshake via the HELLO
867 + * command, and send ACKs until we enter netdump mode.)
869 +static void netdump_startup_handshake(struct net_device *dev)
879 + sprintf(tmp, "NETDUMP start, waiting for start-ACK.\n");
880 + reply.code = REPLY_START_NETDUMP;
883 + send_netdump_skb(dev, tmp, strlen(tmp), &reply);
885 + for (i = 0; i < 10000; i++) {
888 + Dprintk("handshake: polling controller ...\n");
890 + zap_completion_queue();
891 + req = get_new_req();
897 + if (req->command != COMM_START_NETDUMP_ACK) {
903 + printk("NETDUMP START!\n");
908 +static inline void print_status (req_t *req)
910 + static int count = 0;
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;
922 +static inline void print_status (req_t *req)
924 + static int count = 0;
925 + static int prev_jiffies = 0;
927 + if (jiffies/HZ != prev_jiffies/HZ) {
928 + prev_jiffies = jiffies;
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;
944 +static void freeze_cpu (void * dummy)
946 + printk("CPU#%d is frozen.\n", smp_processor_id());
955 +static void netconsole_netdump (struct pt_regs *regs)
959 + unsigned long flags;
960 + struct net_device *dev = netconsole_dev;
963 + struct pt_regs myregs;
966 + __save_flags(flags);
968 +#if CONFIG_X86_LOCAL_APIC
969 + //nmi_watchdog = 0;
972 + smp_call_function(freeze_cpu, NULL, 1, 0);
976 + * Just in case we are crashing within the networking code
977 + * ... attempt to fix up.
979 + spin_lock_init(&dev->xmit_lock);
981 + esp = (unsigned long) ((char *)regs + sizeof (struct pt_regs));
983 + if (regs->xcs & 3) {
985 + ss = regs->xss & 0xffff;
989 + myregs.xss = (myregs.xss & 0xffff0000) | ss;
993 + printk("< netdump activated - performing handshake with the client. >\n");
994 + netdump_startup_handshake(dev);
996 + printk("< handshake completed - listening for dump requests. >\n");
998 + while (netdump_mode) {
1000 + Dprintk("main netdump loop: polling controller ...\n");
1001 + netdump_poll(dev);
1002 + zap_completion_queue();
1006 + req = get_new_req();
1009 + Dprintk("got new req, command %d.\n", req->command);
1010 + print_status(req);
1011 + switch (req->command) {
1013 + Dprintk("got NO command.\n");
1016 + case COMM_SEND_MEM:
1017 + Dprintk("got MEM command.\n");
1018 + // send ->from ->to.
1019 + send_netdump_mem(dev, req);
1023 + Dprintk("got EXIT command.\n");
1028 + Dprintk("got REBOOT command.\n");
1029 + printk("netdump: rebooting in 3 seconds.\n");
1031 + machine_restart(NULL);
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);
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);
1050 + case COMM_GET_REGS:
1053 + elf_gregset_t elf_regs;
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);
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);
1073 + case COMM_SHOW_STATE:
1076 + //show_regs(regs);
1080 + reply.code = REPLY_SHOW_STATE;
1081 + reply.nr = req->nr;
1083 + send_netdump_skb(dev, tmp, strlen(tmp), &reply);
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);
1098 + sprintf(tmp, "NETDUMP end.\n");
1099 + reply.code = REPLY_END_NETDUMP;
1102 + send_netdump_skb(dev, tmp, strlen(tmp), &reply);
1103 + printk("NETDUMP END!\n");
1104 + __restore_flags(flags);
1106 +static int netconsole_sysrq_schedule(void *arg)
1108 + struct task_struct *tsk = current;
1110 + sprintf(tsk->comm, "sysrq_schedule");
1111 + sigfillset(&tsk->blocked);
1114 + thread_stopped = 0;
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);
1124 + if (stop_sysrq_thread)
1126 + wake_up(&sysrq_thread_waiter_queue);
1128 + thread_stopped = 1;
1129 + wake_up(&sysrq_thread_waiter_queue);
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;
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;
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;
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");
1166 +MODULE_PARM(source_port, "h");
1167 +MODULE_PARM_DESC(source_port,
1168 + "local port from which to send netdump packets");
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");
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")
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);
1189 +ETH_BYTES(netdump);
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");
1209 +static struct console netconsole =
1210 + { flags: CON_ENABLED, write: write_netconsole_msg };
1211 +static int init_netconsole(void)
1213 + struct net_device *ndev = NULL;
1214 + struct in_device *in_dev;
1215 + struct irqaction *action;
1218 + printk(KERN_INFO "netlog: using network device <%s>\n", dev);
1219 + // this will be valid once the device goes up.
1221 + ndev = dev_get_by_name(dev);
1223 + printk(KERN_ERR "netlog: network device %s does not exist, aborting.\n", dev);
1226 + in_dev = in_dev_get(ndev);
1228 + printk(KERN_ERR "netlog: network device %s is not an IP protocol device, aborting.\n", dev);
1232 + if (!magic1 || !magic2) {
1233 + printk(KERN_ERR "netlog: magic cookie (magic1,magic2) not specified.\n");
1236 + netconsole_magic = magic1 + (((u64)magic2)<<32);
1238 + source_ip = ntohl(in_dev->ifa_list->ifa_local);
1240 + printk(KERN_ERR "netlog: network device %s has no local address, aborting.\n", dev);
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));
1247 + source_ip = htonl(source_ip);
1248 + if (!source_port) {
1249 + printk(KERN_ERR "netlog: source_port parameter not specified, aborting.\n");
1252 + printk(KERN_INFO "netlog: using source UDP port: %u\n", source_port);
1253 + source_port = htons(source_port);
1255 + if (!netdump_target_ip && !netlog_target_ip && !syslog_target_ip) {
1256 + printk(KERN_ERR "netlog: target_ip parameter not specified, aborting.\n");
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));
1262 + netdump_target_ip = htonl(netdump_target_ip);
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));
1269 + netlog_target_ip = htonl(netlog_target_ip);
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);
1277 + syslog_target_ip = htonl(syslog_target_ip);
1278 + syslog_target_port = htons(syslog_target_port);
1280 + if (!netdump_target_port && !netlog_target_port && !syslog_target_port) {
1281 + printk(KERN_ERR "netlog: target_port parameter not specified, aborting.\n");
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);
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);
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;
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");
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]);
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;
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");
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;
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");
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]);
1331 + mhz_cycles = (unsigned long long)mhz * 1000000ULL;
1332 + jiffy_cycles = (unsigned long long)mhz * (1000000/HZ);
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);
1340 + printk(KERN_ERR "couldn't find irq handler for <%s>", dev);
1343 + irqfunc = action->handler;
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);
1354 +#define STARTUP_MSG "[...network console startup...]\n"
1355 + write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG));
1357 + register_console(&netconsole);
1358 + printk(KERN_INFO "netlog: network logging started up successfully!\n");
1362 +static void cleanup_netconsole(void)
1364 + stop_sysrq_thread = 1;
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);
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;
1377 +module_init(init_netconsole);
1378 +module_exit(cleanup_netconsole);
1380 +MODULE_LICENSE("GPL");
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
1388 + * linux/drivers/net/netconsole.h
1390 + * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com>
1392 + * This file contains the implementation of an IRQ-safe, crash-safe
1393 + * kernel console implementation that outputs kernel messages to the
1396 + * Modification history:
1398 + * 2001-09-17 started by Ingo Molnar.
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.
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.
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.
1416 + ****************************************************************/
1418 +#define NETCONSOLE_VERSION 0x03
1420 +enum netdump_commands {
1422 + COMM_SEND_MEM = 1,
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,
1435 +#define NETDUMP_REQ_SIZE (8+4*4)
1437 +typedef struct netdump_req_s {
1443 + struct list_head list;
1446 +enum netdump_replies {
1451 + REPLY_RESERVED = 4,
1453 + REPLY_NR_PAGES = 6,
1454 + REPLY_PAGE_SIZE = 7,
1455 + REPLY_START_NETDUMP = 8,
1456 + REPLY_END_NETDUMP = 9,
1459 + REPLY_SHOW_STATE = 12,
1463 +typedef struct netdump_reply_s {
1469 +#define HEADER_LEN (1 + sizeof(reply_t))
1470 +/* for netconsole */
1471 +static inline void get_current_regs(struct pt_regs *regs)
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();
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
1494 obj-y += ../acorn/net/acorn-net.o
1497 +obj-$(CONFIG_NETCONSOLE) += netconsole.o
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
1508 dep_tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
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
1521 printk("Kernel BUG\n");
1523 +void (*netdump_func) (struct pt_regs *regs) = NULL;
1524 +int netdump_mode = 0;
1526 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
1530 printk("%s: %04lx\n", str, err & 0xffff);
1531 show_registers(regs);
1533 + netdump_func(regs);
1535 spin_unlock_irq(&die_lock);
1537 @@ -1039,5 +1043,7 @@
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 @@
1553 +struct irqaction *find_irq_action(unsigned int irq, void *dev_id)
1555 + struct irqaction *a, *r=0;
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) {
1564 + spin_unlock_irq(&irq_desc[irq].lock);
1568 static struct proc_dir_entry * root_irq_dir;
1569 static struct proc_dir_entry * irq_dir [NR_IRQS];
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
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
1588 extern char iret_address[];
1590 struct notifier_block *die_chain;
1592 +void (*netdump_func) (struct pt_regs *regs) = NULL;
1593 int kstack_depth_to_print = 12;
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
1601 extern struct drive_info_struct drive_info;
1602 EXPORT_SYMBOL(drive_info);
1605 +int netdump_mode = 0;
1606 /* platform dependent support */
1607 EXPORT_SYMBOL(boot_cpu_data);
1608 EXPORT_SYMBOL(dump_fpu);
1610 extern void int_ret_from_sys_call(void);
1611 EXPORT_SYMBOL_NOVERS(int_ret_from_sys_call);
1613 +EXPORT_SYMBOL_GPL(netdump_func);
1614 +EXPORT_SYMBOL_GPL(netdump_mode);
1616 EXPORT_SYMBOL(touch_nmi_watchdog);
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
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);
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
1636 extern void bust_spinlocks(int yes);
1637 extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */
1639 +extern void (*netdump_func) (struct pt_regs *regs);
1640 +extern int netdump_mode;
1643 extern const char *print_tainted(void);
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
1650 extern void disable_irq_nosync(unsigned int);
1651 extern void enable_irq(unsigned int);
1652 extern void release_x86_irqs(struct task_struct *);
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 */
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];
1665 local_irq_save(flags);
1667 + if (unlikely(skb->dev->rx_hook != NULL)) {
1670 + ret = skb->dev->rx_hook(skb);
1671 + if (ret == NET_RX_DROP)
1674 netdev_rx_stat[this_cpu].total++;
1675 if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
1676 if (queue->input_pkt_queue.qlen) {