--- /dev/null
+Index: linux-2.4.20-rh/drivers/net/netconsole.c
+===================================================================
+--- linux-2.4.20-rh.orig/drivers/net/netconsole.c 2003-07-22 16:02:23.000000000 +0800
++++ linux-2.4.20-rh/drivers/net/netconsole.c 2003-11-11 07:42:33.000000000 +0800
+@@ -12,6 +12,8 @@
+ *
+ * 2001-09-17 started by Ingo Molnar.
+ * 2002-03-14 simultaneous syslog packet option by Michael K. Johnson
++ * 2003-10-30 Add sysrq command processing by Wangdi <wangdi@clusterfs.com>
++ *
+ */
+
+ /****************************************************************
+@@ -51,6 +53,7 @@
+ #include <linux/tty_driver.h>
+ #include <linux/etherdevice.h>
+ #include <linux/elf.h>
++#include "netconsole.h"
+
+ static struct net_device *netconsole_dev;
+ static u16 source_port, netdump_target_port, netlog_target_port, syslog_target_port;
+@@ -62,12 +65,11 @@
+ static unsigned int mhz = 500, idle_timeout;
+ static unsigned long long mhz_cycles, jiffy_cycles;
+
+-#include "netconsole.h"
+
+ #define MAX_UDP_CHUNK 1460
+ #define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
+
+-#define DEBUG 0
++#define DEBUG 0
+ #if DEBUG
+ # define Dprintk(x...) printk(KERN_INFO x)
+ #else
+@@ -187,6 +189,22 @@
+ }
+ }
+ }
++void (*irqfunc)(int, void *, struct pt_regs *);
++
++static void netdump_poll(struct net_device *dev)
++{
++ int budget = 1;
++
++ disable_irq(dev->irq);
++
++ irqfunc(dev->irq, dev, 0);
++
++ if(dev->poll && test_bit(__LINK_STATE_RX_SCHED, &dev->state))
++ dev->poll(dev, &budget);
++
++ enable_irq(dev->irq);
++
++}
+
+ static struct sk_buff * alloc_netconsole_skb(struct net_device *dev, int len, int reserve)
+ {
+@@ -209,7 +227,7 @@
+ once = 0;
+ }
+ Dprintk("alloc skb: polling controller ...\n");
+- dev->poll_controller(dev);
++ netdump_poll(dev);
+ goto repeat;
+ }
+ }
+@@ -231,7 +249,7 @@
+ spin_unlock(&dev->xmit_lock);
+
+ Dprintk("xmit skb: polling controller ...\n");
+- dev->poll_controller(dev);
++ netdump_poll(dev);
+ zap_completion_queue();
+ goto repeat_poll;
+ }
+@@ -426,18 +444,79 @@
+ static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
+ static unsigned int log_offset;
+
++static int thread_stopped = 0;
++/*Interrupt function for netdump */
++static int sysrq_mode = 0;
++static int stop_sysrq_thread = 0;
++#define Set_Sysrq_mode() (sysrq_mode = 1)
++#define Clear_Sysrq_mode() (sysrq_mode = 0)
++static char send_cache[MAX_PRINT_CHUNK];
++static unsigned int send_cache_pos = 0;
++wait_queue_head_t sysrq_thread_queue;
++wait_queue_head_t sysrq_thread_waiter_queue;
++
++#define SEND_MSG_BUFFER(buf, len) \
++do \
++{ \
++ reply_t reply; \
++ unsigned int flags; \
++ __save_flags(flags); \
++ __cli(); \
++ reply.code = REPLY_LOG; \
++ reply.nr = 0; \
++ reply.info = 0; \
++ spin_lock(&sequence_lock); \
++ send_netlog_skb(dev, buf, len, &reply); \
++ spin_unlock(&sequence_lock); \
++ __restore_flags(flags); \
++}while(0);
++
++void netconsole_do_sysrq(req_t *req)
++{
++ struct pt_regs regs;
++ struct net_device *dev = netconsole_dev;
++
++ if (!dev)
++ return;
++ Set_Sysrq_mode();
++ get_current_regs(®s);
++ handle_sysrq((int)req->from, ®s, NULL);
++
++ if (send_cache_pos != 0){
++ SEND_MSG_BUFFER(send_cache, send_cache_pos);
++ memset(send_cache, 0, MAX_PRINT_CHUNK);
++ send_cache_pos = 0;
++ }
++
++ Clear_Sysrq_mode();
++}
+ static void write_netconsole_msg(struct console *con, const char *msg0, unsigned int msg_len)
+ {
+ int len, left, i;
+ struct net_device *dev;
+ const char *msg = msg0;
+ reply_t reply;
+-
++
+ dev = netconsole_dev;
+ if (!dev || netdump_mode)
+ return;
+-
+- if (dev->poll_controller && netif_running(dev)) {
++ if (sysrq_mode){
++ unsigned long total_len = send_cache_pos + msg_len;
++ unsigned long left_len = msg_len;
++ while (total_len >= MAX_PRINT_CHUNK){
++ unsigned long send_len = MAX_PRINT_CHUNK - send_cache_pos;
++ memcpy(send_cache + send_cache_pos, msg, send_len);
++ SEND_MSG_BUFFER(send_cache, MAX_PRINT_CHUNK);
++ send_cache_pos = 0;
++ total_len -= MAX_PRINT_CHUNK;
++ left_len -= send_len;
++ }
++ if (left_len > 0){
++ memcpy(send_cache + send_cache_pos, msg + (msg_len -left_len), left_len);
++ send_cache_pos += left_len;
++ }
++ return;
++ }else if (netif_running(dev)) {
+ unsigned long flags;
+
+ __save_flags(flags);
+@@ -567,8 +646,6 @@
+ req_t *req;
+ struct net_device *dev;
+
+- if (!netdump_mode)
+- return NET_RX_SUCCESS;
+ #if DEBUG
+ {
+ static int packet_count;
+@@ -722,8 +799,16 @@
+ Dprintk("... netdump from: %08x.\n", req->from);
+ Dprintk("... netdump to: %08x.\n", req->to);
+
+- add_new_req(req);
++ if (netdump_mode)
++ add_new_req(req);
++ else if (req->command == COMM_SYSRQ){
++ add_new_req(req);
++ wake_up(&sysrq_thread_queue);
++ return NET_RX_DROP;
++ }
+ out:
++ if (!netdump_mode)
++ return NET_RX_SUCCESS;
+ return NET_RX_DROP;
+ }
+
+@@ -763,6 +848,7 @@
+ kunmap_atomic(kaddr, KM_NETDUMP);
+ }
+
++
+ /*
+ * This function waits for the client to acknowledge the receipt
+ * of the netdump startup reply, with the possibility of packets
+@@ -792,7 +878,7 @@
+ // wait 1 sec.
+ udelay(100);
+ Dprintk("handshake: polling controller ...\n");
+- dev->poll_controller(dev);
++ netdump_poll(dev);
+ zap_completion_queue();
+ req = get_new_req();
+ if (req)
+@@ -904,7 +990,7 @@
+ while (netdump_mode) {
+ __cli();
+ Dprintk("main netdump loop: polling controller ...\n");
+- dev->poll_controller(dev);
++ netdump_poll(dev);
+ zap_completion_queue();
+ #if !CLI
+ __sti();
+@@ -1009,6 +1095,32 @@
+ printk("NETDUMP END!\n");
+ __restore_flags(flags);
+ }
++static int netconsole_sysrq_schedule(void *arg)
++{
++ struct task_struct *tsk = current;
++
++ sprintf(tsk->comm, "sysrq_schedule");
++ sigfillset(&tsk->blocked);
++
++ /* main loop */
++ thread_stopped = 0;
++ for (;;) {
++ wait_event_interruptible(sysrq_thread_queue,
++ !list_empty(&request_list) || stop_sysrq_thread);
++ while (!list_empty(&request_list)) {
++ req_t *req = get_new_req();
++ if (req->command == COMM_SYSRQ)
++ netconsole_do_sysrq(req);
++ }
++ if (stop_sysrq_thread)
++ break;
++ wake_up(&sysrq_thread_waiter_queue);
++ }
++ thread_stopped = 1;
++ wake_up(&sysrq_thread_waiter_queue);
++ return 0;
++}
++
+
+ static char *dev;
+ static int netdump_target_eth_byte0 = 255;
+@@ -1087,11 +1199,12 @@
+
+ static struct console netconsole =
+ { flags: CON_ENABLED, write: write_netconsole_msg };
+-
+ static int init_netconsole(void)
+ {
+ struct net_device *ndev = NULL;
+ struct in_device *in_dev;
++ struct irqaction *action;
++ int rc = 0;
+
+ printk(KERN_INFO "netlog: using network device <%s>\n", dev);
+ // this will be valid once the device goes up.
+@@ -1101,10 +1214,6 @@
+ printk(KERN_ERR "netlog: network device %s does not exist, aborting.\n", dev);
+ return -1;
+ }
+- if (!ndev->poll_controller) {
+- printk(KERN_ERR "netlog: %s's network driver does not implement netlogging yet, aborting.\n", dev);
+- return -1;
+- }
+ in_dev = in_dev_get(ndev);
+ if (!in_dev) {
+ printk(KERN_ERR "netlog: network device %s is not an IP protocol device, aborting.\n", dev);
+@@ -1137,8 +1246,6 @@
+ if (!netdump_target_ip && !netlog_target_ip && !syslog_target_ip) {
+ printk(KERN_ERR "netlog: target_ip parameter not specified, aborting.\n");
+ return -1;
+- }
+- if (netdump_target_ip) {
+ #define IP(x) ((unsigned char *)&netdump_target_ip)[x]
+ printk(KERN_INFO "netlog: using netdump target IP %u.%u.%u.%u\n",
+ IP(3), IP(2), IP(1), IP(0));
+@@ -1214,12 +1321,27 @@
+
+ mhz_cycles = (unsigned long long)mhz * 1000000ULL;
+ jiffy_cycles = (unsigned long long)mhz * (1000000/HZ);
+-
+- INIT_LIST_HEAD(&request_list);
+-
++
+ ndev->rx_hook = netconsole_rx_hook;
+ netdump_func = netconsole_netdump;
+ netconsole_dev = ndev;
++ /* find irq function of the ndev*/
++ action=find_irq_action(ndev->irq, ndev);
++ if (!action) {
++ printk(KERN_ERR "couldn't find irq handler for <%s>", dev);
++ return -1;
++ }
++ irqfunc = action->handler;
++
++ stop_sysrq_thread = 0;
++ INIT_LIST_HEAD(&request_list);
++ init_waitqueue_head(&sysrq_thread_queue);
++ init_waitqueue_head(&sysrq_thread_waiter_queue);
++ if ((rc = kernel_thread(netconsole_sysrq_schedule, NULL, 0)) < 0 ){
++ printk(KERN_ERR "Can not start netconsole sysrq thread: rc %d\n", rc);
++ return -1;
++ }
++
+ #define STARTUP_MSG "[...network console startup...]\n"
+ write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG));
+
+@@ -1230,7 +1352,11 @@
+
+ static void cleanup_netconsole(void)
+ {
+- printk(KERN_INFO "netlog: network logging shut down.\n");
++ stop_sysrq_thread = 1;
++
++ wake_up(&sysrq_thread_queue);
++ wait_event(sysrq_thread_waiter_queue, thread_stopped);
++ printk(KERN_INFO"netlog: network logging shut down.\n");
+ unregister_console(&netconsole);
+
+ #define SHUTDOWN_MSG "[...network console shutdown...]\n"
+Index: linux-2.4.20-rh/drivers/net/netconsole.h
+===================================================================
+--- linux-2.4.20-rh.orig/drivers/net/netconsole.h 2003-07-22 16:02:23.000000000 +0800
++++ linux-2.4.20-rh/drivers/net/netconsole.h 2003-10-30 01:48:45.000000000 +0800
+@@ -29,7 +29,7 @@
+ *
+ ****************************************************************/
+
+-#define NETCONSOLE_VERSION 0x04
++#define NETCONSOLE_VERSION 0x03
+
+ enum netdump_commands {
+ COMM_NONE = 0,
+@@ -42,6 +42,8 @@
+ COMM_START_NETDUMP_ACK = 7,
+ COMM_GET_REGS = 8,
+ COMM_SHOW_STATE = 9,
++ COMM_START_WRITE_NETDUMP_ACK = 10,
++ COMM_SYSRQ = 11,
+ };
+
+ #define NETDUMP_REQ_SIZE (8+4*4)
+@@ -69,6 +71,7 @@
+ REPLY_REGS = 10,
+ REPLY_MAGIC = 11,
+ REPLY_SHOW_STATE = 12,
++ REPLY_SYSRQ = 13,
+ };
+
+ typedef struct netdump_reply_s {
+@@ -78,4 +81,22 @@
+ } reply_t;
+
+ #define HEADER_LEN (1 + sizeof(reply_t))
+-
++/* for netconsole */
++static inline void get_current_regs(struct pt_regs *regs)
++{
++ __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
++ __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
++ __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
++ __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
++ __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
++ __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
++ __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
++ __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
++ __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
++ __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
++ __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
++ __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
++ __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
++ regs->eip = (unsigned long)current_text_addr();
++}
++
+Index: linux-2.4.20-rh/arch/i386/kernel/irq.c
+===================================================================
+--- linux-2.4.20-rh.orig/arch/i386/kernel/irq.c 2003-10-30 08:29:38.000000000 +0800
++++ linux-2.4.20-rh/arch/i386/kernel/irq.c 2003-10-30 08:30:13.000000000 +0800
+@@ -1043,7 +1043,20 @@
+ register_irq_proc(irq);
+ return 0;
+ }
++struct irqaction *find_irq_action(unsigned int irq, void *dev_id)
++{
++ struct irqaction *a, *r=0;
+
++ spin_lock_irq(&irq_desc[irq].lock);
++ for(a=irq_desc[irq].action; a; a=a->next) {
++ if(a->dev_id == dev_id) {
++ r=a;
++ break;
++ }
++ }
++ spin_unlock_irq(&irq_desc[irq].lock);
++ return r;
++}
+
+ static struct proc_dir_entry * root_irq_dir;
+ static struct proc_dir_entry * irq_dir [NR_IRQS];
+Index: linux-2.4.20-rh/net/core/dev.c
+===================================================================
+--- linux-2.4.20-rh.orig/net/core/dev.c 2003-10-29 01:40:26.000000000 +0800
++++ linux-2.4.20-rh/net/core/dev.c 2003-10-30 01:48:45.000000000 +0800
+@@ -1475,6 +1475,16 @@
+
+ skb_bond(skb);
+
++ if (unlikely(skb->dev->rx_hook != NULL)) {
++ int ret;
++
++ ret = skb->dev->rx_hook(skb);
++ if (ret == NET_RX_DROP){
++ kfree_skb(skb);
++ return ret;
++ }
++ }
++
+ netdev_rx_stat[smp_processor_id()].total++;
+
+ #ifdef CONFIG_NET_FASTROUTE
+Index: linux-2.4.20-rh/include/asm-i386/irq.h
+===================================================================
+--- linux-2.4.20-rh.orig/include/asm-i386/irq.h 2003-10-28 16:18:18.000000000 +0800
++++ linux-2.4.20-rh/include/asm-i386/irq.h 2003-10-30 10:24:49.000000000 +0800
+@@ -38,7 +38,7 @@
+ extern void disable_irq_nosync(unsigned int);
+ extern void enable_irq(unsigned int);
+ extern void release_x86_irqs(struct task_struct *);
+-
++extern struct irqaction *find_irq_action(unsigned int irq, void *dev_id);
+ #ifdef CONFIG_X86_LOCAL_APIC
+ #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */
+ #endif
+Index: linux-2.4.20-rh/arch/i386/kernel/i386_ksyms.c
+===================================================================
+--- linux-2.4.20-rh.orig/arch/i386/kernel/i386_ksyms.c 2003-10-28 19:44:57.000000000 +0800
++++ linux-2.4.20-rh/arch/i386/kernel/i386_ksyms.c 2003-10-30 11:14:55.000000000 +0800
+@@ -68,6 +68,7 @@
+ EXPORT_SYMBOL(iounmap);
+ EXPORT_SYMBOL(enable_irq);
+ EXPORT_SYMBOL(disable_irq);
++EXPORT_SYMBOL(find_irq_action);
+ EXPORT_SYMBOL(disable_irq_nosync);
+ EXPORT_SYMBOL(probe_irq_mask);
+ EXPORT_SYMBOL(kernel_thread);
+@@ -199,7 +200,6 @@
+ EXPORT_SYMBOL(edd);
+ EXPORT_SYMBOL(eddnr);
+ #endif
+-
+ EXPORT_SYMBOL_GPL(show_mem);
+ EXPORT_SYMBOL_GPL(show_state);
+ EXPORT_SYMBOL_GPL(show_regs);
+Index: linux-2.4.20-rh/kernel/panic.c
+===================================================================
+--- linux-2.4.20-rh.orig/kernel/panic.c 2003-10-31 07:25:19.000000000 +0800
++++ linux-2.4.20-rh/kernel/panic.c 2003-10-31 07:25:59.000000000 +0800
+@@ -219,8 +219,6 @@
+ }
+ #endif
+
+- if (netdump_func)
+- BUG();
+ if (in_interrupt())
+ printk(KERN_EMERG "In interrupt handler - not syncing\n");
+ else if (!current->pid)