diff -NurpP --minimal linux-2.4.31/Documentation/Configure.help linux-2.4.31-nc0.03/Documentation/Configure.help --- linux-2.4.31/Documentation/Configure.help 2005-04-04 19:27:11 +0200 +++ linux-2.4.31-nc0.03/Documentation/Configure.help 2005-06-30 19:27:03 +0200 @@ -13564,6 +13564,11 @@ CONFIG_SKFP say M here and read . This is recommended. The module will be called skfp.o. +Network console support +CONFIG_NETCONSOLE + If you want to log kernel messages over the network, then say + "M" here. See Documentation/networking/netlogging.txt for details. + HIgh Performance Parallel Interface (HIPPI) support CONFIG_HIPPI HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and diff -NurpP --minimal linux-2.4.31/Documentation/networking/netconsole.txt linux-2.4.31-nc0.03/Documentation/networking/netconsole.txt --- linux-2.4.31/Documentation/networking/netconsole.txt 1970-01-01 01:00:00 +0100 +++ linux-2.4.31-nc0.03/Documentation/networking/netconsole.txt 2005-06-30 19:27:03 +0200 @@ -0,0 +1,56 @@ + +started by Ingo Molnar , 2001.09.17 +updated by Herbert Pötzl , 2004.01.17 +to the new config syntax from Matt Mackall + +This logs kernel printk messages over UDP allowing debugging of +issues where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. diff -NurpP --minimal linux-2.4.31/drivers/net/3c503.c linux-2.4.31-nc0.03/drivers/net/3c503.c --- linux-2.4.31/drivers/net/3c503.c 2003-11-28 19:26:20 +0100 +++ linux-2.4.31-nc0.03/drivers/net/3c503.c 2005-06-30 19:27:03 +0200 @@ -311,6 +311,9 @@ el2_probe1(struct net_device *dev, int i dev->open = &el2_open; dev->stop = &el2_close; dev->ethtool_ops = &netdev_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", diff -NurpP --minimal linux-2.4.31/drivers/net/3c59x.c linux-2.4.31-nc0.03/drivers/net/3c59x.c --- linux-2.4.31/drivers/net/3c59x.c 2005-01-20 11:51:47 +0100 +++ linux-2.4.31-nc0.03/drivers/net/3c59x.c 2005-06-30 20:35:59 +0200 @@ -927,7 +927,8 @@ static void poll_vortex(struct net_devic { struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - local_save_flags(flags); + + local_irq_save(flags); local_irq_disable(); (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); local_irq_restore(flags); diff -NurpP --minimal linux-2.4.31/drivers/net/8139too.c linux-2.4.31-nc0.03/drivers/net/8139too.c --- linux-2.4.31/drivers/net/8139too.c 2004-11-17 12:54:21 +0100 +++ linux-2.4.31-nc0.03/drivers/net/8139too.c 2005-06-30 19:27:03 +0200 @@ -628,6 +628,7 @@ static void rtl8139_set_rx_mode (struct static void __set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); static struct ethtool_ops rtl8139_ethtool_ops; +static void rtl8139_poll_nc (struct net_device *dev); #ifdef USE_IO_OPS @@ -978,6 +979,9 @@ static int __devinit rtl8139_init_one (s dev->ethtool_ops = &rtl8139_ethtool_ops; dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = rtl8139_poll_nc; +#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -2412,6 +2416,22 @@ static struct net_device_stats *rtl8139_ return &tp->stats; } +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* + * Polling 'interrupt' - used by netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void rtl8139_poll_nc (struct net_device *dev) +{ + disable_irq(dev->irq); + rtl8139_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */ diff -NurpP --minimal linux-2.4.31/drivers/net/8390.c linux-2.4.31-nc0.03/drivers/net/8390.c --- linux-2.4.31/drivers/net/8390.c 2005-01-20 11:51:47 +0100 +++ linux-2.4.31-nc0.03/drivers/net/8390.c 2005-06-30 19:27:03 +0200 @@ -526,6 +526,22 @@ void ei_interrupt(int irq, void *dev_id, return; } +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* + * Polling 'interrupt' - used by netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +void ei_poll_nc(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /** * ei_tx_err - handle transmitter error * @dev: network device which threw the exception @@ -1158,6 +1174,9 @@ static void NS8390_trigger_send(struct n EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); +#ifdef CONFIG_NET_POLL_CONTROLLER +EXPORT_SYMBOL(ei_poll_nc); +#endif EXPORT_SYMBOL(ei_tx_timeout); EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); diff -NurpP --minimal linux-2.4.31/drivers/net/8390.h linux-2.4.31-nc0.03/drivers/net/8390.h --- linux-2.4.31/drivers/net/8390.h 2005-05-23 15:18:55 +0200 +++ linux-2.4.31-nc0.03/drivers/net/8390.h 2005-06-30 19:50:05 +0200 @@ -45,6 +45,10 @@ extern void autoirq_setup(int waittime); extern unsigned long autoirq_report(int waittime); #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +extern void ei_poll_nc(struct net_device *dev); +#endif + extern int ethdev_init(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); diff -NurpP --minimal linux-2.4.31/drivers/net/Config.in linux-2.4.31-nc0.03/drivers/net/Config.in --- linux-2.4.31/drivers/net/Config.in 2005-01-20 11:51:47 +0100 +++ linux-2.4.31-nc0.03/drivers/net/Config.in 2005-06-30 19:27:03 +0200 @@ -306,6 +306,8 @@ if [ "$CONFIG_FDDI" = "y" ]; then dep_tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI fi +dep_tristate 'Network console support' CONFIG_NETCONSOLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_INET" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI diff -NurpP --minimal linux-2.4.31/drivers/net/Makefile linux-2.4.31-nc0.03/drivers/net/Makefile --- linux-2.4.31/drivers/net/Makefile 2005-01-20 11:51:47 +0100 +++ linux-2.4.31-nc0.03/drivers/net/Makefile 2005-06-30 19:27:03 +0200 @@ -255,6 +255,8 @@ subdir-y += ../acorn/net obj-y += ../acorn/net/acorn-net.o endif +obj-$(CONFIG_NETCONSOLE) += netconsole.o + # # HIPPI adapters # diff -NurpP --minimal linux-2.4.31/drivers/net/ac3200.c linux-2.4.31-nc0.03/drivers/net/ac3200.c --- linux-2.4.31/drivers/net/ac3200.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/ac3200.c 2005-06-30 19:27:03 +0200 @@ -246,6 +246,9 @@ static int __init ac_probe1(int ioaddr, dev->open = &ac_open; dev->stop = &ac_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; out2: diff -NurpP --minimal linux-2.4.31/drivers/net/apne.c linux-2.4.31-nc0.03/drivers/net/apne.c --- linux-2.4.31/drivers/net/apne.c 2003-08-25 13:44:42 +0200 +++ linux-2.4.31-nc0.03/drivers/net/apne.c 2005-06-30 19:27:03 +0200 @@ -309,6 +309,9 @@ static int __init apne_probe1(struct net ei_status.get_8390_hdr = &apne_get_8390_hdr; dev->open = &apne_open; dev->stop = &apne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ diff -NurpP --minimal linux-2.4.31/drivers/net/e2100.c linux-2.4.31-nc0.03/drivers/net/e2100.c --- linux-2.4.31/drivers/net/e2100.c 2003-06-13 16:51:34 +0200 +++ linux-2.4.31-nc0.03/drivers/net/e2100.c 2005-06-30 19:27:03 +0200 @@ -247,6 +247,9 @@ static int __init e21_probe1(struct net_ ei_status.get_8390_hdr = &e21_get_8390_hdr; dev->open = &e21_open; dev->stop = &e21_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/eepro100.c linux-2.4.31-nc0.03/drivers/net/eepro100.c --- linux-2.4.31/drivers/net/eepro100.c 2005-04-04 19:27:11 +0200 +++ linux-2.4.31-nc0.03/drivers/net/eepro100.c 2005-06-30 19:27:03 +0200 @@ -543,6 +543,7 @@ static void speedo_refill_rx_buffers(str static int speedo_rx(struct net_device *dev); static void speedo_tx_buffer_gc(struct net_device *dev); static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void speedo_poll_nc (struct net_device *dev); static int speedo_close(struct net_device *dev); static struct net_device_stats *speedo_get_stats(struct net_device *dev); static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -879,6 +880,9 @@ static int __devinit speedo_found1(struc dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &speedo_poll_nc; +#endif return 0; } @@ -1661,6 +1665,23 @@ static void speedo_interrupt(int irq, vo return; } +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* + * Polling 'interrupt' - used by netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void speedo_poll_nc (struct net_device *dev) +{ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} + +#endif + static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { struct speedo_private *sp = (struct speedo_private *)dev->priv; diff -NurpP --minimal linux-2.4.31/drivers/net/es3210.c linux-2.4.31-nc0.03/drivers/net/es3210.c --- linux-2.4.31/drivers/net/es3210.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/es3210.c 2005-06-30 19:27:03 +0200 @@ -269,6 +269,9 @@ static int __init es_probe1(struct net_d dev->open = &es_open; dev->stop = &es_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; out1: diff -NurpP --minimal linux-2.4.31/drivers/net/hp-plus.c linux-2.4.31-nc0.03/drivers/net/hp-plus.c --- linux-2.4.31/drivers/net/hp-plus.c 2002-11-29 00:53:13 +0100 +++ linux-2.4.31-nc0.03/drivers/net/hp-plus.c 2005-06-30 19:27:03 +0200 @@ -212,6 +212,9 @@ static int __init hpp_probe1(struct net_ dev->open = &hpp_open; dev->stop = &hpp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ diff -NurpP --minimal linux-2.4.31/drivers/net/hp.c linux-2.4.31-nc0.03/drivers/net/hp.c --- linux-2.4.31/drivers/net/hp.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/hp.c 2005-06-30 19:27:03 +0200 @@ -183,6 +183,9 @@ static int __init hp_probe1(struct net_d dev->base_addr = ioaddr + NIC_OFFSET; dev->open = &hp_open; dev->stop = &hp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif ei_status.name = name; ei_status.word16 = wordmode; diff -NurpP --minimal linux-2.4.31/drivers/net/hydra.c linux-2.4.31-nc0.03/drivers/net/hydra.c --- linux-2.4.31/drivers/net/hydra.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/hydra.c 2005-06-30 19:27:03 +0200 @@ -160,6 +160,9 @@ int __init hydra_init(unsigned long boar ei_status.reg_offset = hydra_offsets; dev->open = &hydra_open; dev->stop = &hydra_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_hydra_dev; root_hydra_dev = dev; diff -NurpP --minimal linux-2.4.31/drivers/net/lne390.c linux-2.4.31-nc0.03/drivers/net/lne390.c --- linux-2.4.31/drivers/net/lne390.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/lne390.c 2005-06-30 19:27:03 +0200 @@ -270,6 +270,9 @@ static int __init lne390_probe1(struct n dev->open = &lne390_open; dev->stop = &lne390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; cleanup: diff -NurpP --minimal linux-2.4.31/drivers/net/mac8390.c linux-2.4.31-nc0.03/drivers/net/mac8390.c --- linux-2.4.31/drivers/net/mac8390.c 2003-08-25 13:44:42 +0200 +++ linux-2.4.31-nc0.03/drivers/net/mac8390.c 2005-06-30 19:27:03 +0200 @@ -435,6 +435,9 @@ int __init mac8390_initdev(struct net_de /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff -NurpP --minimal linux-2.4.31/drivers/net/ne.c linux-2.4.31-nc0.03/drivers/net/ne.c --- linux-2.4.31/drivers/net/ne.c 2005-01-20 11:51:48 +0100 +++ linux-2.4.31-nc0.03/drivers/net/ne.c 2005-06-30 19:27:03 +0200 @@ -478,6 +478,9 @@ static int __init ne_probe1(struct net_d ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/ne2.c linux-2.4.31-nc0.03/drivers/net/ne2.c --- linux-2.4.31/drivers/net/ne2.c 2001-10-17 06:56:29 +0200 +++ linux-2.4.31-nc0.03/drivers/net/ne2.c 2005-06-30 19:27:03 +0200 @@ -486,6 +486,9 @@ static int __init ne2_probe1(struct net_ dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; out: diff -NurpP --minimal linux-2.4.31/drivers/net/ne2k-pci.c linux-2.4.31-nc0.03/drivers/net/ne2k-pci.c --- linux-2.4.31/drivers/net/ne2k-pci.c 2004-11-17 12:54:21 +0100 +++ linux-2.4.31-nc0.03/drivers/net/ne2k-pci.c 2005-06-30 19:27:03 +0200 @@ -359,6 +359,10 @@ static int __devinit ne2k_pci_init_one ( dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; dev->ethtool_ops = &ne2k_pci_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif + NS8390_init(dev, 0); i = register_netdev(dev); diff -NurpP --minimal linux-2.4.31/drivers/net/ne3210.c linux-2.4.31-nc0.03/drivers/net/ne3210.c --- linux-2.4.31/drivers/net/ne3210.c 2002-08-03 02:39:44 +0200 +++ linux-2.4.31-nc0.03/drivers/net/ne3210.c 2005-06-30 19:27:03 +0200 @@ -257,6 +257,9 @@ static int __init ne3210_probe1(struct n dev->open = &ne3210_open; dev->stop = &ne3210_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; out2: diff -NurpP --minimal linux-2.4.31/drivers/net/netconsole.c linux-2.4.31-nc0.03/drivers/net/netconsole.c --- linux-2.4.31/drivers/net/netconsole.c 1970-01-01 01:00:00 +0100 +++ linux-2.4.31-nc0.03/drivers/net/netconsole.c 2005-06-30 20:26:49 +0200 @@ -0,0 +1,489 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * 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. + * 2004-01-17 updated for recent kernel 2.4.24 and + * synced with Matt Mackall's options by + * Herbert Pötzl + * + */ + +/**************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *netconsole[2]={"",""}; + +MODULE_AUTHOR("Maintainer: Herbert Pötzl "); +MODULE_DESCRIPTION("Network console driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(netconsole, "2s"); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +struct netpoll { + struct net_device *dev; + char dev_name[16], *name; + u32 local_ip, remote_ip; + u16 local_port, remote_port; + unsigned char local_mac[6]; + unsigned char remote_mac[6]; +}; + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + + +#define MAX_UDP_CHUNK 1460 + +/* + * We maintain a small pool of fully-sized skbs, + * to make sure the message gets out even in + * extreme OOM situations. + */ +#define MAX_NETCONSOLE_SKBS 32 + +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 void send_netconsole_skb(struct net_device *dev, + const char *msg, unsigned int msg_len) +{ + int total_len, eth_len, ip_len, udp_len; + int status, retries; + struct sk_buff *skb; + struct udphdr *udph; + struct iphdr *iph; + struct ethhdr *eth; + + if (!netif_running(dev)) + return; + + udp_len = msg_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); + + memcpy(skb->data, msg, msg_len); + skb->len += msg_len; + + udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + udph->source = htons(np.local_port); + udph->dest = htons(np.remote_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 = htonl(np.local_ip); + iph->daddr = htonl(np.remote_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, np.local_mac, 6); + memcpy(eth->h_dest, np.remote_mac, 6); + + retries=1000000; +repeat: + if(!--retries) { + __kfree_skb(skb); + return; + } + + 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; + } + + status = dev->hard_start_xmit(skb, dev); + + dev->xmit_lock_owner = -1; + spin_unlock(&dev->xmit_lock); + + if (status) + goto repeat; +} + +static void write_netconsole_msg(struct console *con, const char *msg, unsigned int msg_len) +{ + int len, left; + struct net_device *dev; + + dev = np.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_UDP_CHUNK) + len = MAX_UDP_CHUNK; + else + len = left; + send_netconsole_skb(dev, msg, len); + msg += len; + left -= len; + if (left) + goto repeat; + __restore_flags(flags); + } +} + + + +# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1) + +static int netpoll_parse_options(struct netpoll *np) +{ + char *cur=netconsole[0], *delim; + + if(!netconsole[0] || !netconsole[1]) + goto parse_failed; + + if(*cur != '@') { + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->local_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); + + if(*cur != '/') { + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->local_ip=ntohl(in_aton(cur)); + cur=delim; + + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + cur++; + + if (*cur) + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + cur=netconsole[1]; + + if ( *cur != '@' ) { + /* dst port */ + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->remote_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); + + /* dst ip */ + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->remote_ip=ntohl(in_aton(cur)); + cur=delim+1; + + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + + if( *cur != 0 ) + { + /* MAC address */ + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[0]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[1]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[2]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[3]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[4]=simple_strtol(cur, 0, 16); + cur=delim+1; + np->remote_mac[5]=simple_strtol(cur, 0, 16); + } + + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); + + return 0; + +parse_failed: + printk(KERN_INFO "%s: couldn't parse config at %s!\n", + np->name, cur); + return -1; +} + +static int netpoll_setup(struct netpoll *np) +{ + struct net_device *ndev = NULL; + struct in_device *in_dev; + + if (np->dev_name) + ndev = dev_get_by_name(np->dev_name); + if (!ndev) { + printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", + np->name, np->dev_name); + goto release; + } + if (!ndev->poll_controller) { + printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", + np->name, np->dev_name); + goto release; + } + + if (!(ndev->flags & IFF_UP)) { + unsigned short oflags; + unsigned long jiff; + + printk(KERN_INFO "%s: device %s not up yet, forcing it\n", + np->name, np->dev_name); + + oflags = ndev->flags; + + rtnl_shlock(); + if (dev_change_flags(ndev, oflags | IFF_UP) < 0) { + printk(KERN_ERR "%s: failed to open %s\n", + np->name, np->dev_name); + rtnl_shunlock(); + goto release; + } + rtnl_shunlock(); + + jiff = jiffies + 6*HZ; + while(!netif_carrier_ok(ndev)) { + if (!time_before(jiffies, jiff)) { + printk(KERN_NOTICE + "%s: timeout waiting for carrier\n", + np->name); + break; + } + cond_resched(); + } + + } + + if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr) + memcpy(np->local_mac, ndev->dev_addr, 6); + + if (!np->local_ip) { + in_dev = in_dev_get(ndev); + + if (!in_dev) { + printk(KERN_ERR "%s: no IP address for %s, aborting\n", + np->name, np->dev_name); + goto release; + } + + np->local_ip = ntohl(in_dev->ifa_list->ifa_local); + in_dev_put(in_dev); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + + np->dev = ndev; + return 0; +release: + dev_put(ndev); + return -1; +} + +static void netpoll_cleanup(struct netpoll *np) +{ + dev_put(np->dev); + np->dev = 0; +} + + +static struct console net_console = { + flags: CON_ENABLED, + write: write_netconsole_msg +}; + + +static int __init option_setup(char *opt) +{ + char *delim; + + netconsole[0]=opt; + delim=strchr(opt, ','); + if(delim) + *delim++=0; + netconsole[1]=delim; + return netpoll_parse_options(&np); +} + +__setup("netconsole=", option_setup); + + +static int __init init_netconsole(void) +{ +#ifdef MODULE + if(netpoll_parse_options(&np)) + return 1; +#endif + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + +#define STARTUP_MSG "[...network console startup...]\n" + write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG)); + register_console(&net_console); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void __exit cleanup_netconsole(void) +{ + printk(KERN_INFO "netconsole: network logging shut down.\n"); + unregister_console(&net_console); + +#define SHUTDOWN_MSG "[...network console shutdown...]\n" + write_netconsole_msg(NULL, SHUTDOWN_MSG, strlen(SHUTDOWN_MSG)); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); diff -NurpP --minimal linux-2.4.31/drivers/net/oaknet.c linux-2.4.31-nc0.03/drivers/net/oaknet.c --- linux-2.4.31/drivers/net/oaknet.c 2001-10-17 06:56:29 +0200 +++ linux-2.4.31-nc0.03/drivers/net/oaknet.c 2005-06-30 19:27:03 +0200 @@ -213,6 +213,9 @@ static int __init oaknet_init(void) dev->open = oaknet_open; dev->stop = oaknet_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, FALSE); diff -NurpP --minimal linux-2.4.31/drivers/net/smc-mca.c linux-2.4.31-nc0.03/drivers/net/smc-mca.c --- linux-2.4.31/drivers/net/smc-mca.c 2001-10-17 06:56:29 +0200 +++ linux-2.4.31-nc0.03/drivers/net/smc-mca.c 2005-06-30 19:27:03 +0200 @@ -315,6 +315,9 @@ int __init ultramca_probe(struct net_dev dev->open = &ultramca_open; dev->stop = &ultramca_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/smc-ultra.c linux-2.4.31-nc0.03/drivers/net/smc-ultra.c --- linux-2.4.31/drivers/net/smc-ultra.c 2002-11-29 00:53:14 +0100 +++ linux-2.4.31-nc0.03/drivers/net/smc-ultra.c 2005-06-30 19:27:03 +0200 @@ -271,6 +271,9 @@ static int __init ultra_probe1(struct ne ei_status.reset_8390 = &ultra_reset_8390; dev->open = &ultra_open; dev->stop = &ultra_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/smc-ultra32.c linux-2.4.31-nc0.03/drivers/net/smc-ultra32.c --- linux-2.4.31/drivers/net/smc-ultra32.c 2002-11-29 00:53:14 +0100 +++ linux-2.4.31-nc0.03/drivers/net/smc-ultra32.c 2005-06-30 19:27:03 +0200 @@ -242,6 +242,9 @@ static int __init ultra32_probe1(struct ei_status.reset_8390 = &ultra32_reset_8390; dev->open = &ultra32_open; dev->stop = &ultra32_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/stnic.c linux-2.4.31-nc0.03/drivers/net/stnic.c --- linux-2.4.31/drivers/net/stnic.c 2001-10-17 06:56:29 +0200 +++ linux-2.4.31-nc0.03/drivers/net/stnic.c 2005-06-30 19:27:03 +0200 @@ -132,6 +132,9 @@ int __init stnic_probe(void) dev->irq = IRQ_STNIC; dev->open = &stnic_open; dev->stop = &stnic_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ diff -NurpP --minimal linux-2.4.31/drivers/net/tlan.c linux-2.4.31-nc0.03/drivers/net/tlan.c --- linux-2.4.31/drivers/net/tlan.c 2003-11-28 19:26:20 +0100 +++ linux-2.4.31-nc0.03/drivers/net/tlan.c 2005-06-30 19:27:03 +0200 @@ -296,6 +296,7 @@ static int TLan_ioctl( struct net_device static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent); static void TLan_tx_timeout( struct net_device *dev); static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent); +static void TLan_poll_nc(struct net_device *dev); static u32 TLan_HandleInvalid( struct net_device *, u16 ); static u32 TLan_HandleTxEOF( struct net_device *, u16 ); @@ -452,6 +453,23 @@ static void __devexit tlan_remove_one( s pci_set_drvdata( pdev, NULL ); } +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* + * Polling 'interrupt' - used by netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void TLan_poll_nc (struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} + +#endif + static struct pci_driver tlan_driver = { .name = "tlan", .id_table = tlan_pci_tbl, @@ -893,6 +911,9 @@ static int TLan_Init( struct net_device dev->do_ioctl = &TLan_ioctl; dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_poll_nc; +#endif return 0; diff -NurpP --minimal linux-2.4.31/drivers/net/tulip/tulip_core.c linux-2.4.31-nc0.03/drivers/net/tulip/tulip_core.c --- linux-2.4.31/drivers/net/tulip/tulip_core.c 2005-04-04 19:27:11 +0200 +++ linux-2.4.31-nc0.03/drivers/net/tulip/tulip_core.c 2005-06-30 19:27:03 +0200 @@ -267,6 +267,7 @@ static void tulip_down(struct net_device static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); +static void tulip_poll_nc(struct net_device *dev); @@ -1729,6 +1730,9 @@ static int __devinit tulip_init_one (str dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &tulip_poll_nc; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1902,6 +1906,21 @@ static void __devexit tulip_remove_one ( /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* + * Polling 'interrupt' - used by netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void tulip_poll_nc (struct net_device *dev) +{ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { name: DRV_NAME, diff -NurpP --minimal linux-2.4.31/drivers/net/wd.c linux-2.4.31-nc0.03/drivers/net/wd.c --- linux-2.4.31/drivers/net/wd.c 2005-01-20 11:51:48 +0100 +++ linux-2.4.31-nc0.03/drivers/net/wd.c 2005-06-30 19:27:03 +0200 @@ -301,6 +301,9 @@ static int __init wd_probe1(struct net_d ei_status.get_8390_hdr = &wd_get_8390_hdr; dev->open = &wd_open; dev->stop = &wd_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif NS8390_init(dev, 0); #if 1 diff -NurpP --minimal linux-2.4.31/drivers/net/zorro8390.c linux-2.4.31-nc0.03/drivers/net/zorro8390.c --- linux-2.4.31/drivers/net/zorro8390.c 2003-11-28 19:26:20 +0100 +++ linux-2.4.31-nc0.03/drivers/net/zorro8390.c 2005-06-30 19:27:03 +0200 @@ -229,6 +229,9 @@ static int __init zorro8390_init(struct ei_status.reg_offset = zorro8390_offsets; dev->open = &zorro8390_open; dev->stop = &zorro8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll_nc; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_zorro8390_dev; root_zorro8390_dev = dev; Files linux-2.4.31/include/linux/.spinlock.h.swp and linux-2.4.31-nc0.03/include/linux/.spinlock.h.swp differ diff -NurpP --minimal linux-2.4.31/include/linux/netdevice.h linux-2.4.31-nc0.03/include/linux/netdevice.h --- linux-2.4.31/include/linux/netdevice.h 2005-05-23 15:18:55 +0200 +++ linux-2.4.31-nc0.03/include/linux/netdevice.h 2005-06-30 20:00:40 +0200 @@ -436,6 +436,10 @@ struct net_device unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); +#if defined(CONFIG_NETCONSOLE) || defined(CONFIG_NETCONSOLE_MODULE) +#define CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif /* open/release and usage marking */ struct module *owner; diff -NurpP --minimal linux-2.4.31/net/netsyms.c linux-2.4.31-nc0.03/net/netsyms.c --- linux-2.4.31/net/netsyms.c 2005-04-04 19:27:11 +0200 +++ linux-2.4.31-nc0.03/net/netsyms.c 2005-06-30 19:27:03 +0200 @@ -227,9 +227,13 @@ EXPORT_SYMBOL(make_EII_client); EXPORT_SYMBOL(destroy_EII_client); #endif +/* for 801q VLAN support and netconsole */ +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) || defined(CONFIG_NETCONSOLE) || defined(CONFIG_NETCONSOLE_MODULE) +EXPORT_SYMBOL(dev_change_flags); +#endif + /* for 801q VLAN support */ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -EXPORT_SYMBOL(dev_change_flags); EXPORT_SYMBOL(vlan_ioctl_hook); #endif