diff -NurpP --minimal linux-2.4.24/Documentation/Configure.help linux-2.4.24-netconsole/Documentation/Configure.help --- linux-2.4.24/Documentation/Configure.help Fri Nov 28 19:26:19 2003 +++ linux-2.4.24-netconsole/Documentation/Configure.help Sun Jan 18 08:55:45 2004 @@ -13206,6 +13206,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.24/Documentation/networking/netconsole.txt linux-2.4.24-netconsole/Documentation/networking/netconsole.txt --- linux-2.4.24/Documentation/networking/netconsole.txt Thu Jan 1 01:00:00 1970 +++ linux-2.4.24-netconsole/Documentation/networking/netconsole.txt Sun Jan 18 07:32:55 2004 @@ -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.24/drivers/net/3c503.c linux-2.4.24-netconsole/drivers/net/3c503.c --- linux-2.4.24/drivers/net/3c503.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/3c503.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", diff -NurpP --minimal linux-2.4.24/drivers/net/3c59x.c linux-2.4.24-netconsole/drivers/net/3c59x.c --- linux-2.4.24/drivers/net/3c59x.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/3c59x.c Sun Jan 18 06:43:49 2004 @@ -874,6 +874,7 @@ static void set_rx_mode(struct net_devic static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void vortex_tx_timeout(struct net_device *dev); static void acpi_set_WOL(struct net_device *dev); +static void vorboom_poll(struct net_device *dev); static struct ethtool_ops vortex_ethtool_ops; /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ @@ -1343,6 +1344,9 @@ static int __devinit vortex_probe1(struc dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = &vorboom_poll; +#endif if (pdev && vp->enable_wol) { vp->pm_state_valid = 1; pci_save_state(vp->pdev, vp->power_state); @@ -2321,6 +2325,27 @@ static void boomerang_interrupt(int irq, handler_exit: spin_unlock(&vp->lock); } + +#ifdef HAVE_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 vorboom_poll (struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + disable_irq(dev->irq); + if (vp->full_bus_master_tx) + boomerang_interrupt(dev->irq, dev, NULL); + else + vortex_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static int vortex_rx(struct net_device *dev) { diff -NurpP --minimal linux-2.4.24/drivers/net/8139too.c linux-2.4.24-netconsole/drivers/net/8139too.c --- linux-2.4.24/drivers/net/8139too.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/8139too.c Sun Jan 18 06:43:49 2004 @@ -618,6 +618,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 (struct net_device *dev); #ifdef USE_IO_OPS @@ -969,6 +970,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 HAVE_POLL_CONTROLLER + dev->poll_controller = rtl8139_poll; +#endif /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -2393,6 +2397,22 @@ static struct net_device_stats *rtl8139_ return &tp->stats; } + +#ifdef HAVE_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 (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.24/drivers/net/8390.c linux-2.4.24-netconsole/drivers/net/8390.c --- linux-2.4.24/drivers/net/8390.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/8390.c Sun Jan 18 07:17:44 2004 @@ -526,6 +526,22 @@ void ei_interrupt(int irq, void *dev_id, return; } +#ifdef HAVE_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(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 HAVE_POLL_CONTROLLER +EXPORT_SYMBOL(ei_poll); +#endif EXPORT_SYMBOL(ei_tx_timeout); EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); diff -NurpP --minimal linux-2.4.24/drivers/net/8390.h linux-2.4.24-netconsole/drivers/net/8390.h --- linux-2.4.24/drivers/net/8390.h Sun Jan 18 06:54:14 2004 +++ linux-2.4.24-netconsole/drivers/net/8390.h Sun Jan 18 08:16:47 2004 @@ -45,6 +45,10 @@ extern void autoirq_setup(int waittime); extern unsigned long autoirq_report(int waittime); #endif +#ifdef HAVE_POLL_CONTROLLER +extern void ei_poll(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.24/drivers/net/Config.in linux-2.4.24-netconsole/drivers/net/Config.in --- linux-2.4.24/drivers/net/Config.in Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/Config.in Sun Jan 18 06:43:49 2004 @@ -295,6 +295,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.24/drivers/net/Makefile linux-2.4.24-netconsole/drivers/net/Makefile --- linux-2.4.24/drivers/net/Makefile Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/Makefile Sun Jan 18 06:43:49 2004 @@ -250,6 +250,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.24/drivers/net/ac3200.c linux-2.4.24-netconsole/drivers/net/ac3200.c --- linux-2.4.24/drivers/net/ac3200.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/ac3200.c Sun Jan 18 07:17:44 2004 @@ -246,6 +246,9 @@ static int __init ac_probe1(int ioaddr, dev->open = &ac_open; dev->stop = &ac_close_card; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out2: diff -NurpP --minimal linux-2.4.24/drivers/net/apne.c linux-2.4.24-netconsole/drivers/net/apne.c --- linux-2.4.24/drivers/net/apne.c Mon Aug 25 13:44:42 2003 +++ linux-2.4.24-netconsole/drivers/net/apne.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ diff -NurpP --minimal linux-2.4.24/drivers/net/e100/e100_main.c linux-2.4.24-netconsole/drivers/net/e100/e100_main.c --- linux-2.4.24/drivers/net/e100/e100_main.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/e100/e100_main.c Sun Jan 18 06:43:49 2004 @@ -539,6 +539,22 @@ e100_trigger_SWI(struct e100_private *bd readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ } +#ifdef HAVE_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 e100_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + e100intr(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) { @@ -557,6 +573,9 @@ e100_found1(struct pci_dev *pcid, const SET_MODULE_OWNER(dev); +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = &e100_poll; +#endif if (first_time) { first_time = false; printk(KERN_NOTICE "%s - version %s\n", diff -NurpP --minimal linux-2.4.24/drivers/net/e1000/e1000_main.c linux-2.4.24-netconsole/drivers/net/e1000/e1000_main.c --- linux-2.4.24/drivers/net/e1000/e1000_main.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/e1000/e1000_main.c Sun Jan 18 06:43:49 2004 @@ -165,6 +165,7 @@ static void e1000_leave_82542_rst(struct static inline void e1000_rx_checksum(struct e1000_adapter *adapter, struct e1000_rx_desc *rx_desc, struct sk_buff *skb); +static void e1000_poll(struct net_device *dev); static void e1000_tx_timeout(struct net_device *dev); static void e1000_tx_timeout_task(struct net_device *dev); static void e1000_smartspeed(struct e1000_adapter *adapter); @@ -441,6 +442,9 @@ e1000_probe(struct pci_dev *pdev, adapter->bd_number = cards_found; +#ifdef HAVE_POLL_CONTROLLER + netdev->poll_controller = &e1000_poll; +#endif /* setup the private structure */ if((err = e1000_sw_init(adapter))) @@ -2104,6 +2108,22 @@ e1000_intr(int irq, void *data, struct p adapter->hw.get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } + +#ifdef HAVE_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 e1000_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + e1000_intr(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif #ifdef CONFIG_E1000_NAPI if(netif_rx_schedule_prep(netdev)) { diff -NurpP --minimal linux-2.4.24/drivers/net/e2100.c linux-2.4.24-netconsole/drivers/net/e2100.c --- linux-2.4.24/drivers/net/e2100.c Fri Jun 13 16:51:34 2003 +++ linux-2.4.24-netconsole/drivers/net/e2100.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/eepro100.c linux-2.4.24-netconsole/drivers/net/eepro100.c --- linux-2.4.24/drivers/net/eepro100.c Mon Aug 25 13:44:42 2003 +++ linux-2.4.24-netconsole/drivers/net/eepro100.c Sun Jan 18 06:57:24 2004 @@ -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 (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 HAVE_POLL_CONTROLLER + dev->poll_controller = &speedo_poll; +#endif return 0; } @@ -1660,6 +1664,23 @@ static void speedo_interrupt(int irq, vo clear_bit(0, (void*)&sp->in_interrupt); return; } + +#ifdef HAVE_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 (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) { diff -NurpP --minimal linux-2.4.24/drivers/net/es3210.c linux-2.4.24-netconsole/drivers/net/es3210.c --- linux-2.4.24/drivers/net/es3210.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/es3210.c Sun Jan 18 07:17:44 2004 @@ -269,6 +269,9 @@ static int __init es_probe1(struct net_d dev->open = &es_open; dev->stop = &es_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: diff -NurpP --minimal linux-2.4.24/drivers/net/hp-plus.c linux-2.4.24-netconsole/drivers/net/hp-plus.c --- linux-2.4.24/drivers/net/hp-plus.c Fri Nov 29 00:53:13 2002 +++ linux-2.4.24-netconsole/drivers/net/hp-plus.c Sun Jan 18 07:17:44 2004 @@ -212,6 +212,9 @@ static int __init hpp_probe1(struct net_ dev->open = &hpp_open; dev->stop = &hpp_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ diff -NurpP --minimal linux-2.4.24/drivers/net/hp.c linux-2.4.24-netconsole/drivers/net/hp.c --- linux-2.4.24/drivers/net/hp.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/hp.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = wordmode; diff -NurpP --minimal linux-2.4.24/drivers/net/hydra.c linux-2.4.24-netconsole/drivers/net/hydra.c --- linux-2.4.24/drivers/net/hydra.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/hydra.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_hydra_dev; root_hydra_dev = dev; diff -NurpP --minimal linux-2.4.24/drivers/net/lne390.c linux-2.4.24-netconsole/drivers/net/lne390.c --- linux-2.4.24/drivers/net/lne390.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/lne390.c Sun Jan 18 07:17:44 2004 @@ -270,6 +270,9 @@ static int __init lne390_probe1(struct n dev->open = &lne390_open; dev->stop = &lne390_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; cleanup: diff -NurpP --minimal linux-2.4.24/drivers/net/mac8390.c linux-2.4.24-netconsole/drivers/net/mac8390.c --- linux-2.4.24/drivers/net/mac8390.c Mon Aug 25 13:44:42 2003 +++ linux-2.4.24-netconsole/drivers/net/mac8390.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff -NurpP --minimal linux-2.4.24/drivers/net/ne.c linux-2.4.24-netconsole/drivers/net/ne.c --- linux-2.4.24/drivers/net/ne.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/ne.c Sun Jan 18 07:17:44 2004 @@ -461,6 +461,9 @@ static int __init ne_probe1(struct net_d ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/ne2.c linux-2.4.24-netconsole/drivers/net/ne2.c --- linux-2.4.24/drivers/net/ne2.c Wed Oct 17 06:56:29 2001 +++ linux-2.4.24-netconsole/drivers/net/ne2.c Sun Jan 18 07:17:44 2004 @@ -486,6 +486,9 @@ static int __init ne2_probe1(struct net_ dev->open = &ne_open; dev->stop = &ne_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out: diff -NurpP --minimal linux-2.4.24/drivers/net/ne2k-pci.c linux-2.4.24-netconsole/drivers/net/ne2k-pci.c --- linux-2.4.24/drivers/net/ne2k-pci.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/ne2k-pci.c Sun Jan 18 07:17:44 2004 @@ -356,6 +356,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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); i = register_netdev(dev); diff -NurpP --minimal linux-2.4.24/drivers/net/ne3210.c linux-2.4.24-netconsole/drivers/net/ne3210.c --- linux-2.4.24/drivers/net/ne3210.c Sat Aug 3 02:39:44 2002 +++ linux-2.4.24-netconsole/drivers/net/ne3210.c Sun Jan 18 07:17:44 2004 @@ -257,6 +257,9 @@ static int __init ne3210_probe1(struct n dev->open = &ne3210_open; dev->stop = &ne3210_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out2: diff -NurpP --minimal linux-2.4.24/drivers/net/netconsole.c linux-2.4.24-netconsole/drivers/net/netconsole.c --- linux-2.4.24/drivers/net/netconsole.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.24-netconsole/drivers/net/netconsole.c Sun Jan 18 08:54:59 2004 @@ -0,0 +1,477 @@ +/* + * 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 + + +MODULE_AUTHOR("Maintainer: Herbert Pötzl "); +MODULE_DESCRIPTION("Network console driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(netconsole, "s"); +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 = { + .dev = NULL, + .name = "netconsole", +}; + + +#define NETCONSOLE_VERSION 0x01 +#define HEADER_LEN 5 + +#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. + */ +#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 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); + 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 = 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); + +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 = 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_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); + } +} + + + +# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1) + +int netpoll_parse_options(struct netpoll *np, char *opt) +{ + char *cur=opt, *delim; + + 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 != ',') { + /* parse out dev name */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim=0; + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + cur=delim; + } + cur++; + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + 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; +} + +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; +} + +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 option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("netconsole=", option_setup); + + +static int init_netconsole(void) +{ + 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 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.24/drivers/net/oaknet.c linux-2.4.24-netconsole/drivers/net/oaknet.c --- linux-2.4.24/drivers/net/oaknet.c Wed Oct 17 06:56:29 2001 +++ linux-2.4.24-netconsole/drivers/net/oaknet.c Sun Jan 18 07:17:44 2004 @@ -213,6 +213,9 @@ static int __init oaknet_init(void) dev->open = oaknet_open; dev->stop = oaknet_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, FALSE); diff -NurpP --minimal linux-2.4.24/drivers/net/smc-mca.c linux-2.4.24-netconsole/drivers/net/smc-mca.c --- linux-2.4.24/drivers/net/smc-mca.c Wed Oct 17 06:56:29 2001 +++ linux-2.4.24-netconsole/drivers/net/smc-mca.c Sun Jan 18 07:17:44 2004 @@ -315,6 +315,9 @@ int __init ultramca_probe(struct net_dev dev->open = &ultramca_open; dev->stop = &ultramca_close_card; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/smc-ultra.c linux-2.4.24-netconsole/drivers/net/smc-ultra.c --- linux-2.4.24/drivers/net/smc-ultra.c Fri Nov 29 00:53:14 2002 +++ linux-2.4.24-netconsole/drivers/net/smc-ultra.c Sun Jan 18 07:17:44 2004 @@ -271,6 +291,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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/smc-ultra32.c linux-2.4.24-netconsole/drivers/net/smc-ultra32.c --- linux-2.4.24/drivers/net/smc-ultra32.c Fri Nov 29 00:53:14 2002 +++ linux-2.4.24-netconsole/drivers/net/smc-ultra32.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/stnic.c linux-2.4.24-netconsole/drivers/net/stnic.c --- linux-2.4.24/drivers/net/stnic.c Wed Oct 17 06:56:29 2001 +++ linux-2.4.24-netconsole/drivers/net/stnic.c Sun Jan 18 07:17:44 2004 @@ -132,6 +132,9 @@ int __init stnic_probe(void) dev->irq = IRQ_STNIC; dev->open = &stnic_open; dev->stop = &stnic_close; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#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.24/drivers/net/tg3.c linux-2.4.24-netconsole/drivers/net/tg3.c --- linux-2.4.24/drivers/net/tg3.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/tg3.c Sun Jan 18 06:43:49 2004 @@ -2471,6 +2471,22 @@ static irqreturn_t tg3_interrupt(int irq return IRQ_RETVAL(handled); } +#ifdef HAVE_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 tg3_poll (struct net_device *dev) +{ + disable_irq(dev->irq); + tg3_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); @@ -7628,6 +7644,9 @@ static int __devinit tg3_init_one(struct dev->ethtool_ops = &tg3_ethtool_ops; dev->weight = 64; dev->watchdog_timeo = TG3_TX_TIMEOUT; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = tg3_poll; +#endif dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; diff -NurpP --minimal linux-2.4.24/drivers/net/tlan.c linux-2.4.24-netconsole/drivers/net/tlan.c --- linux-2.4.24/drivers/net/tlan.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/tlan.c Sun Jan 18 06:43:49 2004 @@ -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(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 HAVE_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 (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 HAVE_POLL_CONTROLLER + dev->poll_controller = &TLan_poll; +#endif return 0; diff -NurpP --minimal linux-2.4.24/drivers/net/tulip/tulip_core.c linux-2.4.24-netconsole/drivers/net/tulip/tulip_core.c --- linux-2.4.24/drivers/net/tulip/tulip_core.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/tulip/tulip_core.c Sun Jan 18 06:43:49 2004 @@ -266,6 +266,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(struct net_device *dev); @@ -1728,6 +1729,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 HAVE_POLL_CONTROLLER + dev->poll_controller = &tulip_poll; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1901,6 +1905,21 @@ static void __devexit tulip_remove_one ( /* pci_power_off (pdev, -1); */ } +#ifdef HAVE_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 (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.24/drivers/net/via-rhine.c linux-2.4.24-netconsole/drivers/net/via-rhine.c --- linux-2.4.24/drivers/net/via-rhine.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/via-rhine.c Sun Jan 18 06:43:49 2004 @@ -615,6 +615,22 @@ static void __devinit reload_eeprom(long break; } +#ifdef HAVE_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 via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -783,6 +799,9 @@ static int __devinit via_rhine_init_one dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef HAVE_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; diff -NurpP --minimal linux-2.4.24/drivers/net/wd.c linux-2.4.24-netconsole/drivers/net/wd.c --- linux-2.4.24/drivers/net/wd.c Fri Nov 29 00:53:14 2002 +++ linux-2.4.24-netconsole/drivers/net/wd.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); #if 1 diff -NurpP --minimal linux-2.4.24/drivers/net/zorro8390.c linux-2.4.24-netconsole/drivers/net/zorro8390.c --- linux-2.4.24/drivers/net/zorro8390.c Fri Nov 28 19:26:20 2003 +++ linux-2.4.24-netconsole/drivers/net/zorro8390.c Sun Jan 18 07:17:44 2004 @@ -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 HAVE_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif #ifdef MODULE ei_status.priv = (unsigned long)root_zorro8390_dev; root_zorro8390_dev = dev; diff -NurpP --minimal linux-2.4.24/include/linux/netdevice.h linux-2.4.24-netconsole/include/linux/netdevice.h --- linux-2.4.24/include/linux/netdevice.h Sat Jan 17 05:19:42 2004 +++ linux-2.4.24-netconsole/include/linux/netdevice.h Sun Jan 18 08:16:21 2004 @@ -435,6 +435,8 @@ 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*); +#define HAVE_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); /* open/release and usage marking */ struct module *owner; diff -NurpP --minimal linux-2.4.24/net/core/dev.c linux-2.4.24-netconsole/net/core/dev.c --- linux-2.4.24/net/core/dev.c Fri Nov 28 19:26:21 2003 +++ linux-2.4.24-netconsole/net/core/dev.c Sun Jan 18 06:43:49 2004 @@ -1277,7 +1277,14 @@ int netif_rx(struct sk_buff *skb) int this_cpu = smp_processor_id(); struct softnet_data *queue; unsigned long flags; +#if defined(CONFIG_DUMP_NETDEV) || defined (CONFIG_DUMP_NETDEV_MODULE) + int (*hook)(struct sk_buff *) = skb->dev->rx_hook; + smb_rmb(); + if (hook && unlikely(hook(skb) == NET_RX_DROP)) + goto drop; +#endif + if (skb->stamp.tv_sec == 0) do_gettimeofday(&skb->stamp);