--- /dev/null
+Index: linux-2.6.0-test1/arch/i386/kernel/kgdb_stub.c
+===================================================================
+--- linux-2.6.0-test1.orig/arch/i386/kernel/kgdb_stub.c 2003-09-02 14:16:10.000000000 +0800
++++ linux-2.6.0-test1/arch/i386/kernel/kgdb_stub.c 2003-09-02 14:32:02.000000000 +0800
+@@ -30,6 +30,7 @@
+ *
+ * Written by: Glenn Engel $
+ * Updated by: David Grothe <dave@gcom.com>
++ * Updated by: Robert Walsh <rjwalsh@durables.org>
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+@@ -112,6 +113,7 @@
+ #include <asm/processor.h>
+ #include <linux/irq.h>
+ #include <asm/desc.h>
++#include <linux/inet.h>
+
+ /************************************************************************
+ *
+@@ -122,8 +124,16 @@
+ /* Thread reference */
+ typedef unsigned char threadref[8];
+
+-extern void putDebugChar(int); /* write a single character */
+-extern int getDebugChar(void); /* read and return a single char */
++extern int tty_putDebugChar(int); /* write a single character */
++extern int tty_getDebugChar(void); /* read and return a single char */
++extern void tty_flushDebugChar(void); /* flush pending characters */
++extern int eth_putDebugChar(int); /* write a single character */
++extern int eth_getDebugChar(void); /* read and return a single char */
++extern void eth_flushDebugChar(void); /* flush pending characters */
++extern void gdb_eth_set_trapmode(int);
++extern void gdb_eth_reply_arp(void); /*send arp request */
++extern int gdb_eth_is_initializing;
++
+
+ /************************************************************************/
+ /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+@@ -264,6 +274,35 @@
+ }
+
+ /*
++ * I/O dispatch functions...
++ * Based upon gdb_eth, either call the ethernet
++ * handler or the serial one..
++ */
++void putDebugChar(int c)
++{
++ if (gdb_eth == -1)
++ tty_putDebugChar(c);
++ else
++ eth_putDebugChar(c);
++}
++
++int getDebugChar(void)
++{
++ if (gdb_eth == -1)
++ return tty_getDebugChar();
++ else
++ return eth_getDebugChar();
++}
++
++void flushDebugChar(void)
++{
++ if (gdb_eth == -1)
++ tty_flushDebugChar();
++ else
++ eth_flushDebugChar();
++}
++
++/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function. The
+ * whole assumption in GDB is that we are on a different stack than the
+@@ -389,7 +428,6 @@
+ xmitcsum = -1;
+
+ count = 0;
+-
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+@@ -429,6 +467,7 @@
+
+ if (remote_debug)
+ printk("R:%s\n", buffer);
++ flushDebugChar();
+ }
+
+ /* send the packet in buffer. */
+@@ -441,25 +480,64 @@
+ char ch;
+
+ /* $<packet info>#<checksum>. */
+- do {
+- if (remote_debug)
+- printk("T:%s\n", buffer);
+- putDebugChar('$');
+- checksum = 0;
+- count = 0;
+-
+- while ((ch = buffer[count])) {
+- putDebugChar(ch);
+- checksum += ch;
+- count += 1;
+- }
+
+- putDebugChar('#');
+- putDebugChar(hexchars[checksum >> 4]);
+- putDebugChar(hexchars[checksum % 16]);
+-
+- } while ((getDebugChar() & 0x7f) != '+');
++ if (gdb_eth == -1){
++ do {
++ if (remote_debug)
++ printk("T:%s\n", buffer);
++ putDebugChar('$');
++ checksum = 0;
++ count = 0;
++
++ while ((ch = buffer[count])) {
++ putDebugChar(ch);
++ checksum += ch;
++ count += 1;
++ }
++
++ putDebugChar('#');
++ putDebugChar(hexchars[checksum >> 4]);
++ putDebugChar(hexchars[checksum % 16]);
++ flushDebugChar();
++
++ } while ((getDebugChar() & 0x7f) != '+');
++ }else{
++
++ /*for udp, we can not transfer too much bytes once */
++ /*we only transfer MAX_SEND_COUNT size byts each time */
++#define MAX_SEND_COUNT 30
++ int send_count=0, i=0;
++ char send_buf[30];
+
++ do {
++ if (remote_debug)
++ printk("T:%s\n", buffer);
++ putDebugChar('$');
++ checksum = 0;
++ count = 0;
++ send_count = 0;
++ while ((ch = buffer[count])) {
++ if (send_count >= MAX_SEND_COUNT){
++ for(i=0; i < MAX_SEND_COUNT; i++){
++ putDebugChar(send_buf[i]);
++ }
++ flushDebugChar();
++ send_count = 0;
++ }else{
++ send_buf[send_count] = ch;
++ checksum += ch;
++ count ++;
++ send_count++;
++ }
++ }
++ for(i=0; i < send_count; i++)
++ putDebugChar(send_buf[i]);
++ putDebugChar('#');
++ putDebugChar(hexchars[checksum >> 4]);
++ putDebugChar(hexchars[checksum % 16]);
++ flushDebugChar();
++ } while ((getDebugChar() & 0x7f) != '+');
++ }
+ }
+
+ static char remcomInBuffer[BUFMAX];
+@@ -1143,6 +1221,13 @@
+ print_regs(®s);
+ return (0);
+ }
++ /*
++ * If we're using eth mode, set the 'mode' in the netdevice.
++ */
++
++ if(gdb_eth != -1) {
++ gdb_eth_set_trapmode(1);
++ }
+
+ kgdb_local_irq_save(flags);
+
+@@ -1156,8 +1241,8 @@
+ * NMI and will wait there for the following spin locks to be
+ * released.
+ */
++
+ #ifdef CONFIG_SMP
+-
+ #if 0
+ if (cpu_callout_map & ~MAX_CPU_MASK) {
+ printk("kgdb : too many cpus, possibly not mapped"
+@@ -1372,6 +1457,7 @@
+ gdb_i386vector = exceptionVector;
+ gdb_i386errcode = err_code;
+ kgdb_info.called_from = __builtin_return_address(0);
++
+ #ifdef CONFIG_SMP
+ /*
+ * OK, we can now communicate, lets tell gdb about the sync.
+@@ -1400,8 +1486,13 @@
+ remcomOutBuffer[2] = hexchars[signo % 16];
+ remcomOutBuffer[3] = 0;
+
+- putpacket(remcomOutBuffer);
++ if (gdb_eth_is_initializing) {
++ gdb_eth_is_initializing = 0;
++ } else {
++ putpacket(remcomOutBuffer);
++ }
+
++ gdb_eth_reply_arp();
+ while (1 == 1) {
+ error = 0;
+ remcomOutBuffer[0] = 0;
+@@ -1419,7 +1510,9 @@
+ remote_debug ? "on" : "off");
+ break;
+ case 'g': /* return the value of the CPU registers */
++
+ get_gdb_regs(usethread, ®s, gdb_regs);
++
+ mem2hex((char *) gdb_regs,
+ remcomOutBuffer, NUMREGBYTES, 0);
+ break;
+@@ -1536,6 +1629,10 @@
+
+ newPC = regs.eip;
+
++ if (gdb_eth != -1) {
++ gdb_eth_set_trapmode(0);
++ }
++
+ /* clear the trace bit */
+ regs.eflags &= 0xfffffeff;
+
+@@ -1856,9 +1953,7 @@
+ kgdb_local_irq_restore(flags);
+ return (0);
+ }
+-#if 0
+-exit_just_unlock:
+-#endif
++ exit_just_unlock:
+ #endif
+ /* Release kgdb spinlock */
+ KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+@@ -2213,3 +2308,72 @@
+ typedef int gdb_debug_hook(int exceptionVector,
+ int signo, int err_code, struct pt_regs *linux_regs);
+ gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */
++
++static int __init kgdb_opt_gdbeth(char *str)
++{
++ gdb_eth = simple_strtoul(str,NULL,10);
++ return 1;
++}
++
++static int __init kgdb_opt_gdbeth_remote(char *str)
++{
++ gdb_ethremote = in_aton(str);
++ return 1;
++}
++
++static int __init kgdb_opt_gdbeth_listen(char *str)
++{
++ gdb_listenport = simple_strtoul(str,NULL,10);
++ return 1;
++}
++
++static int __init kgdb_opt_gdbeth_hwaddr(char *str)
++{
++ int i;
++ char *p;
++
++ p = str;
++ i = 0;
++ while(1)
++ {
++ unsigned int c;
++ sscanf(p, "%x:", &c);
++ gdb_sendhwaddr[i++] = c;
++ while((*p != 0) && (*p != ':'))
++ p++;
++ if (*p == 0)
++ break;
++ p++;
++ }
++
++ return 1;
++}
++static int __init kgdb_opt_gdbeth_rchwaddr(char *str)
++{
++ int i;
++ char *p;
++
++ p = str;
++ i = 0;
++ while(1)
++ {
++ unsigned int c;
++ sscanf(p, "%x:", &c);
++ gdb_receivehwaddr[i++] = c;
++ while((*p != 0) && (*p != ':'))
++ p++;
++ if (*p == 0)
++ break;
++ p++;
++ }
++
++ return 1;
++}
++
++
++__setup("gdbeth=", kgdb_opt_gdbeth);
++__setup("gdbeth_remote=", kgdb_opt_gdbeth_remote);
++__setup("gdbeth_listenport=", kgdb_opt_gdbeth_listen);
++__setup("gdbeth_sendhwaddr=", kgdb_opt_gdbeth_hwaddr);
++__setup("gdbeth_receivehwaddr=", kgdb_opt_gdbeth_rchwaddr);
++
+Index: linux-2.6.0-test1/arch/i386/lib/kgdb_serial.c
+===================================================================
+--- linux-2.6.0-test1.orig/arch/i386/lib/kgdb_serial.c 2003-09-02 14:16:11.000000000 +0800
++++ linux-2.6.0-test1/arch/i386/lib/kgdb_serial.c 2003-09-02 14:32:02.000000000 +0800
+@@ -155,12 +155,12 @@
+ * It will receive a limited number of characters of input
+ * from the gdb host machine and save them up in a buffer.
+ *
+- * When the gdb stub routine getDebugChar() is called it
++ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+- * since the stubs do all of that via putDebugChar() which
++ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+@@ -226,7 +226,7 @@
+ /*
+ * Hook an IRQ for KGDB.
+ *
+- * This routine is called from putDebugChar, below.
++ * This routine is called from tty_putDebugChar, below.
+ */
+ static int ints_disabled = 1;
+ int
+@@ -331,7 +331,7 @@
+ }
+
+ /*
+- * getDebugChar
++ * tty_getDebugChar
+ *
+ * This is a GDB stub routine. It waits for a character from the
+ * serial interface and then returns it. If there is no serial
+@@ -345,11 +345,11 @@
+ /* Caller takes needed protections */
+
+ int
+-getDebugChar(void)
++tty_getDebugChar(void)
+ {
+ volatile int chr, dum, time, end_time;
+
+- dbprintk(("getDebugChar(port %x): ", gdb_async_info->port));
++ dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+ if (gdb_async_info == NULL) {
+ gdb_hook_interrupt(&local_info, 0);
+@@ -375,7 +375,7 @@
+ dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+ return (chr);
+
+-} /* getDebugChar */
++} /* tty_getDebugChar */
+
+ static int count = 3;
+ static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+@@ -383,6 +383,9 @@
+ static int __init
+ kgdb_enable_ints(void)
+ {
++ if (gdb_eth != -1) {
++ return 0;
++ }
+ if (gdb_async_info == NULL) {
+ gdb_hook_interrupt(&local_info, 1);
+ }
+@@ -444,7 +447,7 @@
+ }
+
+ /*
+- * putDebugChar
++ * tty_putDebugChar
+ *
+ * This is a GDB stub routine. It waits until the interface is ready
+ * to transmit a char and then sends it. If there is no serial
+@@ -452,9 +455,9 @@
+ * pretended to send the char. Caller takes needed protections.
+ */
+ void
+-putDebugChar(int chr)
++tty_putDebugChar(int chr)
+ {
+- dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
++ dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+ gdb_async_info->port,
+ chr,
+ chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+@@ -480,6 +483,14 @@
+ }
+ }
+
+-} /* putDebugChar */
++} /* tty_putDebugChar */
++
++/*
++ * This does nothing for the serial port, since it doesn't buffer.
++ */
++
++void tty_flushDebugChar(void)
++{
++}
+
+ module_init(kgdb_enable_ints);
+Index: linux-2.6.0-test1/include/linux/netdevice.h
+===================================================================
+--- linux-2.6.0-test1.orig/include/linux/netdevice.h 2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/include/linux/netdevice.h 2003-09-02 14:32:02.000000000 +0800
+@@ -469,6 +469,11 @@
+
+ /* statistics sub-directory */
+ struct kobject stats_kobj;
++
++#ifdef CONFIG_KGDB
++ int kgdb_is_trapped;
++ void (*kgdb_net_poll_rx)(struct net_device *);
++#endif
+ };
+
+ #define SET_MODULE_OWNER(dev) do { } while (0)
+@@ -524,6 +529,11 @@
+ extern struct net_device *dev_get_by_index(int ifindex);
+ extern struct net_device *__dev_get_by_index(int ifindex);
+ extern int dev_restart(struct net_device *dev);
++#ifdef CONFIG_KGDB
++int gdb_eth_is_trapped(void);
++int gdb_net_interrupt(struct sk_buff *skb);
++void gdb_send_arp_request(void);
++#endif
+
+ typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len);
+ extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf);
+@@ -582,12 +592,20 @@
+
+ static inline void netif_wake_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++ if (gdb_eth_is_trapped())
++ return;
++#endif
+ if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+ __netif_schedule(dev);
+ }
+
+ static inline void netif_stop_queue(struct net_device *dev)
+ {
++#ifdef CONFIG_KGDB
++ if (gdb_eth_is_trapped())
++ return;
++#endif
+ set_bit(__LINK_STATE_XOFF, &dev->state);
+ }
+
+Index: linux-2.6.0-test1/include/asm-i386/kgdb.h
+===================================================================
+--- linux-2.6.0-test1.orig/include/asm-i386/kgdb.h 2003-09-02 14:16:20.000000000 +0800
++++ linux-2.6.0-test1/include/asm-i386/kgdb.h 2003-09-02 14:32:03.000000000 +0800
+@@ -18,6 +18,16 @@
+ #ifndef BREAKPOINT
+ #define BREAKPOINT asm(" int $3")
+ #endif
++
++extern int gdb_eth;
++extern unsigned gdb_ethremote;
++extern unsigned short gdb_listenport;
++extern unsigned char gdb_sendhwaddr[6];
++extern unsigned char gdb_receivehwaddr[6];
++
++extern int gdb_tty_hook(void);
++extern int gdb_eth_hook(void);
++
+ /*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+@@ -34,6 +44,7 @@
+ extern int kgdb_handle_exception(int trapno,
+ int signo, int err_code, struct pt_regs *regs);
+ extern int in_kgdb(struct pt_regs *regs);
++extern void kgdb_null(void);
+
+ #ifdef CONFIG_KGDB_TS
+ void kgdb_tstamp(int line, char *source, int data0, int data1);
+Index: linux-2.6.0-test1/drivers/net/e100/e100_main.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/e100/e100_main.c 2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/e100/e100_main.c 2003-09-02 14:32:03.000000000 +0800
+@@ -567,6 +567,15 @@
+ }
+ #endif
+
++#ifdef CONFIG_KGDB
++static void e100_rx_poll(struct net_device *dev)
++{
++ disable_irq(dev->irq);
++ e100intr(dev->irq, (void *)dev, 0);
++ enable_irq(dev->irq);
++}
++#endif
++
+ static int __devinit
+ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+ {
+@@ -662,7 +671,9 @@
+ dev->set_multicast_list = &e100_set_multi;
+ dev->set_mac_address = &e100_set_mac;
+ dev->do_ioctl = &e100_ioctl;
+-
++#ifdef CONFIG_KGDB
++ dev->kgdb_net_poll_rx = e100_rx_poll;
++#endif
+ if (bdp->flags & USE_IPCB)
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+Index: linux-2.6.0-test1/drivers/net/3c59x.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/3c59x.c 2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/3c59x.c 2003-09-02 14:32:03.000000000 +0800
+@@ -1063,6 +1063,22 @@
+ return rc;
+ }
+
++#ifdef CONFIG_KGDB
++static void vortex_rx_poll(struct net_device *dev)
++{
++ disable_irq(dev->irq);
++ vortex_interrupt(dev->irq, (void *)dev, 0);
++ enable_irq(dev->irq);
++}
++
++static void boomerang_rx_poll(struct net_device *dev)
++{
++ disable_irq(dev->irq);
++ boomerang_interrupt(dev->irq, (void *)dev, 0);
++ enable_irq(dev->irq);
++}
++#endif
++
+ /*
+ * Start up the PCI/EISA device which is described by *gendev.
+ * Return 0 on success.
+@@ -1449,6 +1465,14 @@
+ dev->set_multicast_list = set_rx_mode;
+ dev->tx_timeout = vortex_tx_timeout;
+ dev->watchdog_timeo = (watchdog * HZ) / 1000;
++#ifdef CONFIG_KGDB
++ if (vp->full_bus_master_tx) {
++ dev->kgdb_net_poll_rx = boomerang_rx_poll;
++ } else {
++ dev->kgdb_net_poll_rx = vortex_rx_poll;
++ }
++#endif
++
+ #ifdef HAVE_POLL_CONTROLLER
+ dev->poll_controller = &vorboom_poll;
+ #endif
+Index: linux-2.6.0-test1/drivers/net/Makefile
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/Makefile 2003-07-14 11:32:32.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/Makefile 2003-09-02 14:32:03.000000000 +0800
+@@ -32,6 +32,8 @@
+
+ obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
+
++obj-$(CONFIG_KGDB) += kgdb_eth.o
++
+ obj-$(CONFIG_DGRS) += dgrs.o
+ obj-$(CONFIG_RCPCI) += rcpci.o
+ obj-$(CONFIG_VORTEX) += 3c59x.o
+Index: linux-2.6.0-test1/drivers/net/kgdb_eth.c
+===================================================================
+--- linux-2.6.0-test1.orig/drivers/net/kgdb_eth.c 2003-09-02 14:32:02.000000000 +0800
++++ linux-2.6.0-test1/drivers/net/kgdb_eth.c 2003-09-02 21:41:42.000000000 +0800
+@@ -0,0 +1,547 @@
++/*
++ * Network interface GDB stub
++ *
++ * Written by San Mehat (nettwerk@biodome.org)
++ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
++ * and Scott Foehner (sfoehner@engr.sgi.com)
++ *
++ * Twiddled for 2.5 by Robert Walsh (rjwalsh@durables.org)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/config.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <linux/workqueue.h>
++#include <asm/kgdb.h>
++#include <linux/if_ether.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/delay.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/segment.h>
++#include <asm/bitops.h>
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/atomic.h>
++
++#undef PRNT /* define for debug printing */
++
++#define GDB_BUF_SIZE 512 /* power of 2, please */
++
++static char gdb_buf[GDB_BUF_SIZE] ;
++static int gdb_buf_in_inx ;
++static atomic_t gdb_buf_in_cnt ;
++static int gdb_buf_out_inx ;
++
++extern void set_debug_traps(void) ; /* GDB routine */
++extern void breakpoint(void);
++
++unsigned int gdb_ethremote = 0;
++unsigned short gdb_listenport = 6443;
++unsigned short gdb_sendport= 6442;
++int gdb_eth = -1; /* Default tty mode */
++unsigned char gdb_sendhwaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++unsigned char gdb_receivehwaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++int gdb_eth_is_initializing = 0;
++int gdb_eth_debug = 0;
++
++struct net_device *gdb_netdevice = NULL;
++
++//static int initialized = -1;
++//static struct work_struct irq_bp;
++
++static void bpwork_func(void *p)
++{
++ udelay(500);
++ BREAKPOINT;
++}
++
++static struct workqueue_struct *irq_bp;
++DECLARE_WORK(bpwork, bpwork_func, NULL);
++
++/*
++ * Get a char if available, return -1 if nothing available.
++ * Empty the receive buffer first, then look at the interface hardware.
++ */
++static int read_char(void)
++{
++
++ if (atomic_read(&gdb_buf_in_cnt) != 0) /* intr routine has q'd chars */
++ {
++ int chr ;
++
++ chr = gdb_buf[gdb_buf_out_inx++] ;
++ gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
++ atomic_dec(&gdb_buf_in_cnt) ;
++ return chr;
++ }
++ return -1; // no data
++} /* read_char */
++
++//static unsigned char daddr[6] = {0x00,0x06,0x25,0xA9,0x9F,0x6A};
++//static unsigned char daddr[6] = {0x00,0x50,0xFC,0xB8,0x22,0x03};
++//static unsigned char daddr[6] = {0x00,0x08,0x74,0x96,0x6D,0x9B};
++//static unsigned char daddr[6] = {0x00,0x07,0xE9,0xD4,0xBE,0x85};
++//static unsigned char daddr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
++
++/*
++ * Wait until the interface can accept a char, then write it.
++ */
++static void write_buffer(char *buf, int len)
++{
++ int total_len, eth_len, ip_len, udp_len;
++ struct in_device *in_dev;
++ struct sk_buff *skb;
++ struct udphdr *udph;
++ struct iphdr *iph;
++ struct ethhdr *eth;
++
++ if (!(in_dev = (struct in_device *) gdb_netdevice->ip_ptr))
++ panic("No in_device available for interface!\n");
++ if (!(in_dev->ifa_list))
++ panic("No interface address set for interface!\n");
++ udp_len = len + sizeof(struct udphdr);
++ ip_len = eth_len = udp_len + sizeof(struct iphdr);
++ total_len = eth_len + ETH_HLEN;
++
++ if (!(skb = alloc_skb(total_len, GFP_ATOMIC)))
++ return;
++
++ atomic_set(&skb->users, 1);
++ skb_reserve(skb, total_len - 1);
++
++ memcpy(skb->data , (unsigned char *) buf, len);
++ skb->len += len;
++
++ udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++ udph->source = htons(gdb_listenport);
++ udph->dest = htons(gdb_sendport);
++ udph->len = htons(udp_len);
++ udph->check = 0;
++
++ iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++ iph->version = 4;
++ iph->ihl = 5;
++ iph->tos = 0;
++ iph->tot_len = htons(ip_len);
++ iph->id = 0;
++ iph->frag_off= 0;
++ iph->ttl = 64;
++ iph->protocol= IPPROTO_UDP;
++ iph->check = 0;
++ iph->saddr = in_dev->ifa_list->ifa_address;
++ iph->daddr = gdb_ethremote;
++ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++
++ eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
++ eth->h_proto = htons(ETH_P_IP);
++ memcpy(eth->h_source, gdb_sendhwaddr, gdb_netdevice->addr_len);
++// memcpy(eth->h_dest, daddr, gdb_netdevice->addr_len);
++ memcpy(eth->h_dest, gdb_receivehwaddr, gdb_netdevice->addr_len);
++
++#if 0
++repeat_poll:
++#endif
++ spin_lock(&gdb_netdevice->xmit_lock);
++ gdb_netdevice->xmit_lock_owner = smp_processor_id();
++#if 0
++ if (netif_queue_stopped(gdb_netdevice))
++ {
++ gdb_netdevice->xmit_lock_owner = -1;
++ spin_unlock(&gdb_netdevice->xmit_lock);
++ gdb_netdevice->poll_controller(gdb_netdevice);
++ zap_completion_queue();
++ goto repeat_poll;
++ }
++#endif
++ gdb_netdevice->hard_start_xmit(skb, gdb_netdevice);
++ gdb_netdevice->xmit_lock_owner = -1;
++ spin_unlock(&gdb_netdevice->xmit_lock);
++
++ // kfree_skb(skb);
++} /* write_char */
++/* in interrupt state the target machine will not response the arp request */
++
++static struct sk_buff *send_skb = NULL;
++void gdb_eth_reply_arp(void)
++{
++ if (send_skb){
++#if 0
++repeat_poll:
++#endif
++ spin_lock(&gdb_netdevice->xmit_lock);
++ gdb_netdevice->xmit_lock_owner = smp_processor_id();
++#if 0
++ if (netif_queue_stopped(gdb_netdevice)){
++ gdb_netdevice->xmit_lock_owner = -1;
++ spin_unlock(&gdb_netdevice->xmit_lock);
++ gdb_netdevice->poll_controller(gdb_netdevice);
++ zap_completion_queue();
++ goto repeat_poll;
++ }
++#endif
++ gdb_netdevice->hard_start_xmit(send_skb, gdb_netdevice);
++ gdb_netdevice->xmit_lock_owner = -1;
++ spin_unlock(&gdb_netdevice->xmit_lock);
++ send_skb = NULL;
++
++ }
++}
++static int make_arp_request( struct sk_buff *skb)
++{
++ struct arphdr *arp;
++ unsigned char *arp_ptr;
++ int type = ARPOP_REPLY;
++ int ptype = ETH_P_ARP;
++ u32 sip, tip;
++ unsigned char *sha, *tha;
++ struct in_device *in_dev = (struct in_device *) gdb_netdevice->ip_ptr;
++ /*
++ * No arp on this interface.
++ */
++ if (gdb_netdevice->flags &IFF_NOARP)
++ return 0;
++ if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
++ (2 * gdb_netdevice->addr_len) +
++ (2 * sizeof(u32)))))
++ return 0;
++
++ skb->h.raw = skb->nh.raw = skb->data;
++ arp = skb->nh.arph;
++
++ if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
++ arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
++ arp->ar_pro != htons(ETH_P_IP))
++ return 0;
++
++/* Understand only these message types */
++
++ if (arp->ar_op != htons(ARPOP_REQUEST))
++ return 0;
++/*
++ * Extract fields
++ */
++ arp_ptr= (unsigned char *)(arp+1);
++ sha = arp_ptr;
++ arp_ptr += gdb_netdevice->addr_len;
++ memcpy(&sip, arp_ptr, 4);
++ arp_ptr += 4;
++ tha = arp_ptr;
++ arp_ptr += gdb_netdevice->addr_len;
++ memcpy(&tip, arp_ptr, 4);
++ if (tip != in_dev->ifa_list->ifa_address){
++ return 0;
++ }
++ if (gdb_ethremote != sip){
++ return 0;
++ }
++/*
++ * Check for bad requests for 127.x.x.x and requests for multicast
++ * addresses. If this is one such, delete it.
++ */
++
++ if (LOOPBACK(tip) || MULTICAST(tip))
++ return 0;
++
++/*
++ * reply the arp request
++ */
++ send_skb = alloc_skb(sizeof(struct arphdr)+ 2*(gdb_netdevice->addr_len+4)
++ + LL_RESERVED_SPACE(gdb_netdevice), GFP_ATOMIC);
++ if (send_skb == NULL)
++ return 0;
++
++ skb_reserve(send_skb, LL_RESERVED_SPACE(gdb_netdevice));
++ send_skb->nh.raw = send_skb->data;
++ arp = (struct arphdr *) skb_put(send_skb,sizeof(struct arphdr) + 2*(gdb_netdevice->addr_len+4));
++ send_skb->dev = gdb_netdevice;
++ send_skb->protocol = htons(ETH_P_ARP);
++
++ /*
++ * Fill the device header for the ARP frame
++ */
++ if (gdb_netdevice->hard_header &&
++ gdb_netdevice->hard_header(send_skb, gdb_netdevice, ptype, gdb_receivehwaddr, gdb_sendhwaddr, send_skb->len) < 0){
++ kfree_skb(send_skb);
++ return 0;
++ }
++ /*
++ * Fill out the arp protocol part.
++ *
++ * we only support ethernet device type,
++ * which (according to RFC 1390) should always equal 1 (Ethernet).
++ */
++ arp->ar_hrd = htons(gdb_netdevice->type);
++ arp->ar_pro = htons(ETH_P_IP);
++
++ arp->ar_hln = gdb_netdevice->addr_len;
++ arp->ar_pln = 4;
++ arp->ar_op = htons(type);
++
++ arp_ptr=(unsigned char *)(arp+1);
++
++ memcpy(arp_ptr, gdb_netdevice->dev_addr, gdb_netdevice->addr_len);
++ arp_ptr += gdb_netdevice->addr_len;
++ memcpy(arp_ptr, &tip, 4);
++ arp_ptr += 4;
++ memcpy(arp_ptr, gdb_sendhwaddr, gdb_netdevice->addr_len);
++ arp_ptr+=gdb_netdevice->addr_len;
++ memcpy(arp_ptr, &sip, 4);
++ return 0;
++}
++/*
++ * Accept an skbuff from net_device layer and
++ * add the payload onto gdb buffer
++ *
++ * When the gdb stub routine getDebugChar() is called it
++ * draws characters out of the buffer until it is empty and
++ * then reads directly from the serial port.
++ *
++ * We do not attempt to write chars from the interrupt routine
++ * since the stubs do all of that via putDebugChar() which
++ * writes one byte after waiting for the interface to become
++ * ready.
++ *
++ * The debug stubs like to run with interrupts disabled since,
++ * after all, they run as a consequence of a breakpoint in
++ * the kernel.
++ *
++ * NOTE: Return value of 1 means it was for us and is an
++ * indication to the calling driver to destroy the sk_buff
++ * and not send it up the stack
++ */
++
++int gdb_net_interrupt(struct sk_buff *skb)
++{
++ unsigned char chr;
++ struct iphdr *iph = (struct iphdr*)skb->data;
++ struct udphdr *udph= (struct udphdr*)(skb->data+(iph->ihl<<2));
++ unsigned char *data = (unsigned char *) udph + sizeof(struct udphdr);
++ int len;
++ int i;
++
++ if ((gdb_eth != -1) && (!gdb_netdevice) &&
++ (iph->protocol == IPPROTO_UDP) &&
++ (be16_to_cpu(udph->dest) == gdb_listenport)) {
++ gdb_sendport = be16_to_cpu(udph->source);
++
++ while(gdb_eth_is_initializing);
++ if(!gdb_netdevice)
++ gdb_eth_hook();
++ if (!gdb_netdevice) {
++ /* Lets not even try again. */
++ gdb_eth = -1;
++ return 0;
++ }
++ }
++ if (!gdb_netdevice) {
++ return 0;
++ }
++ if (skb->protocol == __constant_htons(ETH_P_ARP) && !send_skb){
++ make_arp_request(skb);
++ return 0;
++ }
++ if (iph->protocol != IPPROTO_UDP)
++ return 0;
++
++ if (be16_to_cpu(udph->dest) != gdb_listenport)
++ return 0;
++
++ len = be16_to_cpu(iph->tot_len) - (sizeof(struct udphdr) +
++ sizeof(struct iphdr));
++ for (i = 0; i < len; i++)
++ {
++ chr = *data++;
++ if (chr == 3)
++ {
++ queue_work(irq_bp, &bpwork);
++// flush_workqueue(irq_bp);
++ continue;
++/*
++ if (!in_interrupt())
++ {
++ breakpoint();
++ }
++ else
++ {
++ schedule_work(&irq_bp); // XXX: is this really necessary??
++ }
++ continue;
++*/
++ }
++ if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE)
++ { /* buffer overflow, clear it */
++ gdb_buf_in_inx = 0 ;
++ atomic_set(&gdb_buf_in_cnt, 0) ;
++ gdb_buf_out_inx = 0 ;
++ break ;
++ }
++ gdb_buf[gdb_buf_in_inx++] = chr ;
++ gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
++ atomic_inc(&gdb_buf_in_cnt) ;
++ }
++
++ return 1;
++} /* gdb_interrupt */
++
++
++int gdb_eth_hook(void)
++{
++ char gdb_netdev[16];
++ extern void kgdb_respond_ok(void);
++
++ if (gdb_sendhwaddr[0] == 0xff)
++ panic("ERROR! 'gdbeth_sendhwaddr' option not set!\n");
++ if (gdb_receivehwaddr[0] == 0xff)
++ panic("ERROR! 'gdbeth_receivehwaddr' option not set!\n");
++ if (gdb_ethremote == 0)
++ panic("ERROR! 'gdbeth_remote' option not set!\n");
++
++ sprintf(gdb_netdev,"eth%d",gdb_eth);
++
++#ifdef CONFIG_SMP
++ if (num_online_cpus() > CONFIG_NO_KGDB_CPUS){
++ printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
++ return -1;
++ }
++#endif
++ for (gdb_netdevice = dev_base;
++ gdb_netdevice != NULL;
++ gdb_netdevice = gdb_netdevice->next){
++ if (strncmp(gdb_netdevice->name, gdb_netdev, IFNAMSIZ) == 0)
++ break;
++ }
++ if (!gdb_netdevice){
++ printk("KGDB NET : Unable to find interface %s\n",gdb_netdev);
++ return -ENODEV;
++ }
++
++ /*
++ * Call GDB routine to setup the exception vectors for the debugger
++ */
++ set_debug_traps() ;
++
++ /*
++ * Call the breakpoint() routine in GDB to start the debugging
++ * session.
++ */
++ if (gdb_eth_debug){
++ printk(KERN_INFO "Waiting for remote gdb connection from %x on local port %d\n",
++ gdb_ethremote, gdb_listenport);
++ printk(KERN_INFO "We are sending on port %d to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++ gdb_sendport,
++ gdb_sendhwaddr[0],
++ gdb_sendhwaddr[1],
++ gdb_sendhwaddr[2],
++ gdb_sendhwaddr[3],
++ gdb_sendhwaddr[4],
++ gdb_sendhwaddr[5]);
++ printk("Connected.\n");
++ }
++ gdb_eth_is_initializing = 1;
++ queue_work(irq_bp, &bpwork);
++ return 0;
++} /* gdb_hook_interrupt2 */
++
++/*
++ * getDebugChar
++ *
++ * This is a GDB stub routine. It waits for a character from the
++ * serial interface and then returns it. If there is no serial
++ * interface connection then it returns a bogus value which will
++ * almost certainly cause the system to hang.
++ */
++int eth_getDebugChar(void)
++{
++ volatile int chr ;
++
++ while((chr = read_char()) < 0)
++ {
++ if (send_skb){
++ gdb_eth_reply_arp();
++ }
++ if (gdb_netdevice->kgdb_net_poll_rx)
++ gdb_netdevice->kgdb_net_poll_rx(gdb_netdevice);
++ else
++ {
++ printk("KGDB NET: Error - Device %s is not supported!\n",
++ gdb_netdevice->name);
++ panic("Please add support for kgdb net to this driver");
++ }
++ }
++ return chr;
++
++} /* eth_getDebugChar */
++
++#define ETH_QUEUE_SIZE 256
++static char eth_queue[ETH_QUEUE_SIZE];
++static int outgoing_queue;
++
++void eth_flushDebugChar(void)
++{
++ if(outgoing_queue) {
++ write_buffer(eth_queue, outgoing_queue);
++
++ outgoing_queue = 0;
++ }
++}
++
++static void put_char_on_queue(int chr)
++{
++ eth_queue[outgoing_queue++] = chr;
++ if(outgoing_queue == ETH_QUEUE_SIZE)
++ {
++ eth_flushDebugChar();
++ }
++}
++
++/*
++ * eth_putDebugChar
++ *
++ * This is a GDB stub routine. It waits until the interface is ready
++ * to transmit a char and then sends it.
++ */
++void eth_putDebugChar(int chr)
++{
++ if (gdb_eth_debug)
++ printk(KERN_INFO "eth_putDebugChar: chr=%02x '%c'\n", chr,
++ chr > ' ' && chr < 0x7F ? chr : ' ') ;
++ put_char_on_queue(chr) ; /* this routine will wait */
++} /* putDebugChar */
++
++void gdb_eth_set_trapmode(int mode)
++{
++ if (!gdb_netdevice)
++ return;
++ gdb_netdevice->kgdb_is_trapped = mode;
++}
++
++int gdb_eth_is_trapped()
++{
++ if (!gdb_netdevice)
++ return 0;
++ return gdb_netdevice->kgdb_is_trapped;
++}
++
++static int __init
++kgdb_eth_init(void)
++{
++ irq_bp = create_workqueue("kgdb");
++ return 0;
++}
++
++module_init(kgdb_eth_init);
+Index: linux-2.6.0-test1/net/core/dev.c
+===================================================================
+--- linux-2.6.0-test1.orig/net/core/dev.c 2003-09-02 14:29:27.000000000 +0800
++++ linux-2.6.0-test1/net/core/dev.c 2003-09-02 14:32:03.000000000 +0800
+@@ -188,7 +188,9 @@
+ extern int netdev_sysfs_init(void);
+ extern int netdev_register_sysfs(struct net_device *);
+ extern void netdev_unregister_sysfs(struct net_device *);
+-
++#ifdef CONFIG_KGDB
++extern int gdb_net_interrupt(struct sk_buff *skb);
++#endif
+
+ /*******************************************************************************
+
+@@ -1349,6 +1351,21 @@
+ struct softnet_data *queue;
+ unsigned long flags;
+
++#ifdef CONFIG_KGDB
++ /* See if kgdb_eth wants this packet */
++ if (!gdb_net_interrupt(skb)) {
++ /* No.. if we're 'trapped' then junk it */
++ if (gdb_eth_is_trapped()) {
++ kfree_skb(skb);
++ return NET_RX_DROP;
++ }
++ } else {
++ /* kgdb_eth ate the packet... drop it silently */
++ kfree_skb(skb);
++ return NET_RX_DROP;
++ }
++#endif
++
+
+ /*
+ * The code is rearranged so that the path is the most