diff -Naur linux-2.4.22/drivers/net/Config.in.orig linux-2.4.22/drivers/net/Config.in
--- linux-2.4.22/drivers/net/Config.in.orig	2006-02-26 11:49:28.000000000 -0600
+++ linux-2.4.22/drivers/net/Config.in	2006-02-26 11:40:31.000000000 -0600
@@ -338,6 +338,8 @@
    dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
 fi
 
+dep_tristate 'Network logging support' CONFIG_NETCONSOLE
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
diff -Naur linux-2.4.22/drivers/net/Makefile.orig linux-2.4.22/drivers/net/Makefile
--- linux-2.4.22/drivers/net/Makefile.orig	2006-02-26 11:49:45.000000000 -0600
+++ linux-2.4.22/drivers/net/Makefile	2006-02-26 11:38:58.000000000 -0600
@@ -272,6 +272,8 @@
 obj-y		+= ../acorn/net/acorn-net.o
 endif
 
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
+
 #
 # HIPPI adapters
 #
diff -Naur linux-2.4.22/drivers/net/netconsole.c.orig linux-2.4.22/drivers/net/netconsole.c
--- linux-2.4.22/drivers/net/netconsole.c.orig	2006-07-02 23:40:44.597695500 -0500
+++ linux-2.4.22/drivers/net/netconsole.c	2006-07-10 15:58:44.000000000 -0500
@@ -0,0 +1,353 @@
+/*  linux/drivers/net/netconsole.c
+ *
+ *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
+ *
+ *  This file contains the implementation of an IRQ-safe, crash-safe
+ *  kernel console implementation that outputs kernel messages to the
+ *  network.
+ *
+ * Modification history:
+ *
+ * 2001-09-17    started by Ingo Molnar.
+ * 2006-02-26    very minor modifications to suit the NSLU2 w/Unslung -- Mike Westerhof.
+ * 2006-07-10    usability mods for Unslung (text only, and IP addrs) -- Mike Westerhof.
+ */
+
+/****************************************************************
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2, or (at your option)
+ *      any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************/
+
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+#include <linux/console.h>
+#include <linux/smp_lock.h>
+#include <linux/netdevice.h>
+#include <linux/tty_driver.h>
+#include <linux/etherdevice.h>
+
+static struct net_device *netconsole_dev;
+static u16 source_port, target_port;
+static u32 source_ip, target_ip, target_ipaddr;
+static unsigned char daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
+
+#define NETCONSOLE_VERSION 0x01
+/* HEADER_LEN was "5" -- it's zero for Unslung; makes it work better with netcat */
+#define HEADER_LEN 0
+
+#define MAX_UDP_CHUNK 1460
+#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
+
+/*
+ * We maintain a small pool of fully-sized skbs,
+ * to make sure the message gets out even in
+ * extreme OOM situations.
+ */
+/* Was 32, lowered to 16 for Unslung (to save memory) */
+#define MAX_NETCONSOLE_SKBS 16
+
+
+static spinlock_t netconsole_lock = SPIN_LOCK_UNLOCKED;
+static int nr_netconsole_skbs;
+static struct sk_buff *netconsole_skbs;
+
+#define MAX_SKB_SIZE \
+		(MAX_UDP_CHUNK + sizeof(struct udphdr) + \
+				sizeof(struct iphdr) + sizeof(struct ethhdr))
+
+static void __refill_netconsole_skbs(void)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&netconsole_lock, flags);
+	while (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS) {
+		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
+		if (!skb)
+			break;
+		if (netconsole_skbs)
+			skb->next = netconsole_skbs;
+		else
+			skb->next = NULL;
+		netconsole_skbs = skb;
+		nr_netconsole_skbs++;
+	}
+	spin_unlock_irqrestore(&netconsole_lock, flags);
+}
+
+static struct sk_buff * get_netconsole_skb(void)
+{
+	struct sk_buff *skb;
+
+	unsigned long flags;
+
+	spin_lock_irqsave(&netconsole_lock, flags);
+	skb = netconsole_skbs;
+	if (skb)
+		netconsole_skbs = skb->next;
+	skb->next = NULL;
+	nr_netconsole_skbs--;
+	spin_unlock_irqrestore(&netconsole_lock, flags);
+
+	return skb;
+}
+
+static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int offset;
+
+static void send_netconsole_skb(struct net_device *dev, const char *msg, unsigned int msg_len)
+{
+	int total_len, eth_len, ip_len, udp_len;
+	unsigned long flags;
+	struct sk_buff *skb;
+	struct udphdr *udph;
+	struct iphdr *iph;
+	struct ethhdr *eth;
+
+	udp_len = msg_len + HEADER_LEN + sizeof(*udph);
+	ip_len = eth_len = udp_len + sizeof(*iph);
+	total_len = eth_len + ETH_HLEN;
+
+	if (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS)
+		__refill_netconsole_skbs();
+
+	skb = alloc_skb(total_len, GFP_ATOMIC);
+	if (!skb) {
+		skb = get_netconsole_skb();
+		if (!skb)
+			/* tough! */
+			return;
+	}
+
+	atomic_set(&skb->users, 1);
+	skb_reserve(skb, total_len - msg_len - HEADER_LEN);
+/* Header data removed for Unslung -- its presence makes netcat less useful
+ *	skb->data[0] = NETCONSOLE_VERSION;
+ *
+ *	spin_lock_irqsave(&sequence_lock, flags);
+ *	put_unaligned(htonl(offset), (u32 *) (skb->data + 1));
+ *	offset += msg_len;
+ *	spin_unlock_irqrestore(&sequence_lock, flags);
+ */
+	memcpy(skb->data + HEADER_LEN, msg, msg_len);
+	skb->len += msg_len + HEADER_LEN;
+
+	udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+	udph->source = source_port;
+	udph->dest = target_port;
+	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    = source_ip;
+        iph->daddr    = target_ip;
+	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, dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, daddr, dev->addr_len);
+
+repeat:
+	spin_lock(&dev->xmit_lock);
+	dev->xmit_lock_owner = smp_processor_id();
+
+	if (netif_queue_stopped(dev)) {
+		dev->xmit_lock_owner = -1;
+		spin_unlock(&dev->xmit_lock);
+
+		dev->poll_controller(dev);
+		goto repeat;
+	}
+
+	dev->hard_start_xmit(skb, dev);
+
+	dev->xmit_lock_owner = -1;
+	spin_unlock(&dev->xmit_lock);
+}
+
+static void write_netconsole_msg(struct console *con, const char *msg, unsigned int msg_len)
+{
+	int len, left;
+	struct net_device *dev;
+
+	dev = netconsole_dev;
+	if (!dev)
+		return;
+
+	if (dev->poll_controller && netif_running(dev)) {
+		unsigned long flags;
+
+		__save_flags(flags);
+		__cli();
+		left = msg_len;
+repeat:
+		if (left > MAX_PRINT_CHUNK)
+			len = MAX_PRINT_CHUNK;
+		else
+			len = left;
+		send_netconsole_skb(dev, msg, len);
+		msg += len;
+		left -= len;
+		if (left)
+			goto repeat;
+		__restore_flags(flags);
+	}
+}
+
+static char *dev;
+static int target_eth_byte0 = 255;
+static int target_eth_byte1 = 255;
+static int target_eth_byte2 = 255;
+static int target_eth_byte3 = 255;
+static int target_eth_byte4 = 255;
+static int target_eth_byte5 = 255;
+
+MODULE_AUTHOR("Ingo Molnar <mingo@redhat.com>");
+MODULE_DESCRIPTION("kernel network console implementation");
+MODULE_LICENSE("GPL");
+MODULE_PARM(target_ip, "i");
+MODULE_PARM(target_ipaddr, "s");
+MODULE_PARM(target_eth_byte0, "i");
+MODULE_PARM(target_eth_byte1, "i");
+MODULE_PARM(target_eth_byte2, "i");
+MODULE_PARM(target_eth_byte3, "i");
+MODULE_PARM(target_eth_byte4, "i");
+MODULE_PARM(target_eth_byte5, "i");
+MODULE_PARM(source_port, "h");
+MODULE_PARM(target_port, "h");
+MODULE_PARM(dev, "s");
+
+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;
+
+	// Set some reasonable defaults, at least for the NSLU2 device
+	if (!target_port)
+		target_port = 6666;
+	if (!source_port)
+		source_port = 6665;
+	if (!dev)
+		dev = "ixp0";
+
+	printk(KERN_INFO "netconsole: using network device <%s>\n", dev);
+	// this will be valid once the device goes up.
+	if (dev)
+		ndev = dev_get_by_name(dev);
+	if (!ndev) {
+		printk(KERN_ERR "netconsole: network device %s does not exist, aborting.\n", dev);
+		return -1;
+	}
+	if (!ndev->poll_controller) {
+		printk(KERN_ERR "netconsole: %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 "netconsole: network device %s is not an IP protocol device, aborting.\n", dev);
+		return -1;
+	}
+	source_ip = ntohl(in_dev->ifa_list->ifa_local);
+	if (!source_ip) {
+		printk(KERN_ERR "netconsole: network device %s has no local address, aborting.\n", dev);
+		return -1;
+	}
+	source_ip = htonl(source_ip);
+#define IP(x) ((char *)&source_ip)[x]
+	printk(KERN_INFO "netconsole: using source IP %i.%i.%i.%i\n",
+		IP(0), IP(1), IP(2), IP(3));
+#undef IP
+	if (!target_ipaddr) {
+		if (!target_ip) {
+			printk(KERN_ERR "netconsole: neither target_ipaddr nor target_ip parameter not specified, aborting.\n");
+			return -1;
+		} else {
+			target_ip = htonl(target_ip);
+		}
+	} else {
+		target_ip = in_aton(target_ipaddr);
+	}
+#define IP(x) ((char *)&target_ip)[x]
+	printk(KERN_INFO "netconsole: using target IP %i.%i.%i.%i\n",
+		IP(0), IP(1), IP(2), IP(3));
+#undef IP
+	if (!source_port) {
+		printk(KERN_ERR "netconsole: source_port parameter not specified, aborting.\n");
+		return -1;
+	}
+	printk(KERN_INFO "netconsole: using source UDP port: %i\n", source_port);
+	source_port = htons(source_port);
+	if (!target_port) {
+		printk(KERN_ERR "netconsole: target_port parameter not specified, aborting.\n");
+		return -1;
+	}
+	printk(KERN_INFO "netconsole: using target UDP port: %i\n", target_port);
+	target_port = htons(target_port);
+
+	daddr[0] = target_eth_byte0;
+	daddr[1] = target_eth_byte1;
+	daddr[2] = target_eth_byte2;
+	daddr[3] = target_eth_byte3;
+	daddr[4] = target_eth_byte4;
+	daddr[5] = target_eth_byte5;
+
+	if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] & daddr[5]) == 255)
+		printk(KERN_INFO "netconsole: using broadcast ethernet frames to send packets.\n");
+	else
+		printk(KERN_INFO "netconsole: using target ethernet address %02x:%02x:%02x:%02x:%02x:%02x.\n", daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
+		
+	netconsole_dev = ndev;
+#define STARTUP_MSG "[...network console startup...]\n"
+	write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG));
+
+	register_console(&netconsole);
+	printk(KERN_INFO "netconsole: network logging started up successfully!\n");
+	return 0;
+}
+
+static void cleanup_netconsole(void)
+{
+	printk(KERN_INFO "netconsole: network logging shut down.\n");
+	unregister_console(&netconsole);
+
+#define SHUTDOWN_MSG "[...network console shutdown...]\n"
+	write_netconsole_msg(NULL, SHUTDOWN_MSG, strlen(SHUTDOWN_MSG));
+	netconsole_dev = NULL;
+}
+
+module_init(init_netconsole);
+module_exit(cleanup_netconsole);
+
+int dummy = MAX_SKB_SIZE;
diff -Naur linux-2.4.22/include/linux/netdevice.h.orig linux-2.4.22/include/linux/netdevice.h
--- linux-2.4.22/include/linux/netdevice.h.orig	2006-02-26 11:50:24.000000000 -0600
+++ linux-2.4.22/include/linux/netdevice.h	2006-02-26 11:37:14.000000000 -0600
@@ -428,6 +428,9 @@
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
 
+#define HAVE_POLL_CONTROLLER
+	void			(*poll_controller)(struct net_device *dev);
+
 	/* open/release and usage marking */
 	struct module *owner;