diff -X dontdiff -urN linux-2.4.18ac2/Documentation/Configure.help linux-2.4.18ac2-stefan/Documentation/Configure.help --- linux-2.4.18ac2/Documentation/Configure.help Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/Documentation/Configure.help Sun Mar 24 20:12:08 2002 @@ -24594,6 +24594,15 @@ information: http://www.candelatech.com/~greear/vlan.html If unsure, you can safely say 'N'. +Device link state notification +CONFIG_LINKWATCH + When this option is enabled, the kernel will forward changes in the + operative ("RUNNING") state of an interface via the netlink socket. + This is most useful when running linux as a router. Note that currently + not many drivers maintain an administrative state, a few even break this + option. Compliant drivers change the RUNNING flag in ifconfig output + depending on operative state. If unsure, say 'N'. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -X dontdiff -urN linux-2.4.18ac2/include/linux/netdevice.h linux-2.4.18ac2-stefan/include/linux/netdevice.h --- linux-2.4.18ac2/include/linux/netdevice.h Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/include/linux/netdevice.h Mon Mar 25 23:29:37 2002 @@ -208,6 +208,12 @@ __LINK_STATE_NOCARRIER }; +/* This gets called by netif_carrier_on()/_off() whenever + * state of an interface changes + */ +#ifdef CONFIG_LINKWATCH +extern void wake_linkwatch_thread(void); +#endif /* * This structure holds at boot time configured netdevice settings. They @@ -611,14 +617,24 @@ static inline void netif_carrier_on(struct net_device *dev) { +#ifdef CONFIG_LINKWATCH + if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) + wake_linkwatch_thread(); +#else clear_bit(__LINK_STATE_NOCARRIER, &dev->state); +#endif if (netif_running(dev)) __netdev_watchdog_up(dev); } static inline void netif_carrier_off(struct net_device *dev) { +#ifdef CONFIG_LINKWATCH + if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) + wake_linkwatch_thread(); +#else set_bit(__LINK_STATE_NOCARRIER, &dev->state); +#endif } /* Hot-plugging. */ diff -X dontdiff -urN linux-2.4.18ac2/net/Config.in linux-2.4.18ac2-stefan/net/Config.in --- linux-2.4.18ac2/net/Config.in Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/net/Config.in Sun Mar 24 19:58:20 2002 @@ -46,6 +46,7 @@ fi dep_tristate '802.1Q VLAN Support (EXPERIMENTAL)' CONFIG_VLAN_8021Q $CONFIG_EXPERIMENTAL + bool 'Device link state notification (EXPERIMENTAL)' CONFIG_LINKWATCH fi diff -X dontdiff -urN linux-2.4.18ac2/net/core/dev.c linux-2.4.18ac2-stefan/net/core/dev.c --- linux-2.4.18ac2/net/core/dev.c Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/net/core/dev.c Wed Mar 27 00:32:17 2002 @@ -719,6 +719,12 @@ */ dev->flags |= IFF_UP; + if (netif_carrier_ok(dev)) { + dev->flags |= IFF_RUNNING; + } else { + dev->flags &= ~IFF_RUNNING; + } + set_bit(__LINK_STATE_START, &dev->state); /* @@ -812,7 +818,7 @@ * Device is now down. */ - dev->flags &= ~IFF_UP; + dev->flags &= ~(IFF_UP | IFF_RUNNING); #ifdef CONFIG_NET_FASTROUTE dev_clear_fastroute(dev); #endif @@ -2740,7 +2746,9 @@ #ifdef CONFIG_NET_DIVERT extern void dv_init(void); #endif /* CONFIG_NET_DIVERT */ - +#ifdef CONFIG_LINKWATCH +extern void linkwatch_init(void); +#endif /* CONFIG_LINKWATCH */ /* * Callers must hold the rtnl semaphore. See the comment at the @@ -2877,6 +2885,10 @@ */ net_device_init(); + +#ifdef CONFIG_LINKWATCH + linkwatch_init(); +#endif /* CONFIG_LINKWATCH */ return 0; } diff -X dontdiff -urN linux-2.4.18ac2/net/core/link_watch.c linux-2.4.18ac2-stefan/net/core/link_watch.c --- linux-2.4.18ac2/net/core/link_watch.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.18ac2-stefan/net/core/link_watch.c Thu Mar 28 00:18:43 2002 @@ -0,0 +1,106 @@ +/* + * Linux network device state notifaction + * + * Author: + * Stefan Rompf + * + * 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 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Used by wake_linkwatch_thread() */ +static wait_queue_head_t linkwatch_wqh; +static unsigned long linkwatch_nowait; + +static int linkwatch_thread(void *dummy) +{ + struct net_device *dev; + DECLARE_WAITQUEUE(linkwatch_wq, current); + + daemonize(); + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + strcpy(current->comm, "linkwatchd"); + + while(1) { + clear_bit(0, &linkwatch_nowait); + rtnl_lock(); + for (dev=dev_base; dev; dev = dev->next) { + + /* State of netif_carrier_ok() is reflected + into dev_flags by this loop, and a netlink + message is omitted whenever the state + changes */ + + if (!(dev->flags & IFF_UP)) continue; + + if (dev->flags & IFF_RUNNING) { + if (!netif_carrier_ok(dev)) { + write_lock(&dev_base_lock); + dev->flags &= ~IFF_RUNNING; + write_unlock(&dev_base_lock); + netdev_state_change(dev); + } + } else { + if (netif_carrier_ok(dev)) { + write_lock(&dev_base_lock); + dev->flags |= IFF_RUNNING; + write_unlock(&dev_base_lock); + netdev_state_change(dev); + } + } + } + rtnl_unlock(); + + /* Prevent runaway on rapid state changes */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + set_current_state(TASK_INTERRUPTIBLE); + if (test_bit(0, &linkwatch_nowait)) { + set_current_state(TASK_RUNNING); + } else { + add_wait_queue(&linkwatch_wqh, &linkwatch_wq); + schedule(); + remove_wait_queue(&linkwatch_wqh, &linkwatch_wq); + } + } + + return 0; /* Not reached */ +} + + +void wake_linkwatch_thread() { + set_bit(0, &linkwatch_nowait); + wake_up(&linkwatch_wqh); +} + + +void __init linkwatch_init(void) { + pid_t me; + + init_waitqueue_head(&linkwatch_wqh); + linkwatch_nowait = 0; + me = kernel_thread(linkwatch_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + + if (!me) { + printk(KERN_INFO "Failed to init linkwatch thread, continuing without\n"); + } +} + diff -X dontdiff -urN linux-2.4.18ac2/net/netsyms.c linux-2.4.18ac2-stefan/net/netsyms.c --- linux-2.4.18ac2/net/netsyms.c Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/net/netsyms.c Mon Mar 25 21:55:34 2002 @@ -588,4 +588,8 @@ EXPORT_SYMBOL(net_call_rx_atomic); EXPORT_SYMBOL(softnet_data); +#ifdef CONFIG_LINKWATCH +EXPORT_SYMBOL(wake_linkwatch_thread); +#endif + #endif /* CONFIG_NET */ --- linux-2.4.18ac2/net/core/Makefile Wed Mar 27 00:06:54 2002 +++ linux-2.4.18ac2-stefan/net/core/Makefile Mon Mar 25 21:54:26 2002 @@ -27,4 +27,6 @@ obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PROFILE) += profile.o +obj-$(CONFIG_LINKWATCH) += link_watch.o + include $(TOPDIR)/Rules.make