1 /* 2 * Linux network device link state notification 3 * 4 * Author: 5 * Stefan Rompf <sux@loplof.de> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 11 * 12 */ 13 14 #include <linux/module.h> 15 #include <linux/netdevice.h> 16 #include <linux/if.h> 17 #include <net/sock.h> 18 #include <net/pkt_sched.h> 19 #include <linux/rtnetlink.h> 20 #include <linux/jiffies.h> 21 #include <linux/spinlock.h> 22 #include <linux/list.h> 23 #include <linux/slab.h> 24 #include <linux/workqueue.h> 25 #include <linux/bitops.h> 26 #include <asm/types.h> 27 28 29 enum lw_bits { 30 LW_RUNNING = 0, 31 LW_SE_USED 32 }; 33 34 static unsigned long linkwatch_flags; 35 static unsigned long linkwatch_nextevent; 36 37 static void linkwatch_event(struct work_struct *dummy); 38 static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); 39 40 static LIST_HEAD(lweventlist); 41 static DEFINE_SPINLOCK(lweventlist_lock); 42 43 struct lw_event { 44 struct list_head list; 45 struct net_device *dev; 46 }; 47 48 /* Avoid kmalloc() for most systems */ 49 static struct lw_event singleevent; 50 51 static unsigned char default_operstate(const struct net_device *dev) 52 { 53 if (!netif_carrier_ok(dev)) 54 return (dev->ifindex != dev->iflink ? 55 IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); 56 57 if (netif_dormant(dev)) 58 return IF_OPER_DORMANT; 59 60 return IF_OPER_UP; 61 } 62 63 64 static void rfc2863_policy(struct net_device *dev) 65 { 66 unsigned char operstate = default_operstate(dev); 67 68 if (operstate == dev->operstate) 69 return; 70 71 write_lock_bh(&dev_base_lock); 72 73 switch(dev->link_mode) { 74 case IF_LINK_MODE_DORMANT: 75 if (operstate == IF_OPER_UP) 76 operstate = IF_OPER_DORMANT; 77 break; 78 79 case IF_LINK_MODE_DEFAULT: 80 default: 81 break; 82 }; 83 84 dev->operstate = operstate; 85 86 write_unlock_bh(&dev_base_lock); 87 } 88 89 90 /* Must be called with the rtnl semaphore held */ 91 void linkwatch_run_queue(void) 92 { 93 struct list_head head, *n, *next; 94 95 spin_lock_irq(&lweventlist_lock); 96 list_replace_init(&lweventlist, &head); 97 spin_unlock_irq(&lweventlist_lock); 98 99 list_for_each_safe(n, next, &head) { 100 struct lw_event *event = list_entry(n, struct lw_event, list); 101 struct net_device *dev = event->dev; 102 103 if (event == &singleevent) { 104 clear_bit(LW_SE_USED, &linkwatch_flags); 105 } else { 106 kfree(event); 107 } 108 109 /* We are about to handle this device, 110 * so new events can be accepted 111 */ 112 clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); 113 114 rfc2863_policy(dev); 115 if (dev->flags & IFF_UP) { 116 if (netif_carrier_ok(dev)) { 117 WARN_ON(dev->qdisc_sleeping == &noop_qdisc); 118 dev_activate(dev); 119 } else 120 dev_deactivate(dev); 121 122 netdev_state_change(dev); 123 } 124 125 dev_put(dev); 126 } 127 } 128 129 130 static void linkwatch_event(struct work_struct *dummy) 131 { 132 /* Limit the number of linkwatch events to one 133 * per second so that a runaway driver does not 134 * cause a storm of messages on the netlink 135 * socket 136 */ 137 linkwatch_nextevent = jiffies + HZ; 138 clear_bit(LW_RUNNING, &linkwatch_flags); 139 140 rtnl_lock(); 141 linkwatch_run_queue(); 142 rtnl_unlock(); 143 } 144 145 146 void linkwatch_fire_event(struct net_device *dev) 147 { 148 if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { 149 unsigned long flags; 150 struct lw_event *event; 151 152 if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) { 153 event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC); 154 155 if (unlikely(event == NULL)) { 156 clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); 157 return; 158 } 159 } else { 160 event = &singleevent; 161 } 162 163 dev_hold(dev); 164 event->dev = dev; 165 166 spin_lock_irqsave(&lweventlist_lock, flags); 167 list_add_tail(&event->list, &lweventlist); 168 spin_unlock_irqrestore(&lweventlist_lock, flags); 169 170 if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { 171 unsigned long delay = linkwatch_nextevent - jiffies; 172 173 /* If we wrap around we'll delay it by at most HZ. */ 174 if (delay > HZ) 175 delay = 0; 176 schedule_delayed_work(&linkwatch_work, delay); 177 } 178 } 179 } 180 181 EXPORT_SYMBOL(linkwatch_fire_event); 182