diff options
| author | Alan Ott <alan@signal11.us> | 2012-09-01 01:57:07 -0400 |
|---|---|---|
| committer | David S. Miller <davem@tempietto.lan> | 2012-09-01 22:48:02 -0400 |
| commit | a2dc375e12334b3d8f787a48b2fb6172ccfb80ae (patch) | |
| tree | 82caa348d85c5470deec9e4505695a9e58f99601 | |
| parent | a437d2744b0a4e5f405f6b9be284eb9e0a2d7741 (diff) | |
6lowpan: handle NETDEV_UNREGISTER event
Before, it was impossible to remove a wpan device which had lowpan
attached to it.
Signed-off-by: Alan Ott <alan@signal11.us>
Signed-off-by: David S. Miller <davem@tempietto.lan>
| -rw-r--r-- | net/ieee802154/6lowpan.c | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index b28ec790c7c8..d5291113584f 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c | |||
| @@ -1063,12 +1063,6 @@ out: | |||
| 1063 | return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK); | 1063 | return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK); |
| 1064 | } | 1064 | } |
| 1065 | 1065 | ||
| 1066 | static void lowpan_dev_free(struct net_device *dev) | ||
| 1067 | { | ||
| 1068 | dev_put(lowpan_dev_info(dev)->real_dev); | ||
| 1069 | free_netdev(dev); | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) | 1066 | static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) |
| 1073 | { | 1067 | { |
| 1074 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; | 1068 | struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; |
| @@ -1118,7 +1112,7 @@ static void lowpan_setup(struct net_device *dev) | |||
| 1118 | dev->netdev_ops = &lowpan_netdev_ops; | 1112 | dev->netdev_ops = &lowpan_netdev_ops; |
| 1119 | dev->header_ops = &lowpan_header_ops; | 1113 | dev->header_ops = &lowpan_header_ops; |
| 1120 | dev->ml_priv = &lowpan_mlme; | 1114 | dev->ml_priv = &lowpan_mlme; |
| 1121 | dev->destructor = lowpan_dev_free; | 1115 | dev->destructor = free_netdev; |
| 1122 | } | 1116 | } |
| 1123 | 1117 | ||
| 1124 | static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) | 1118 | static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) |
| @@ -1244,6 +1238,34 @@ static inline void __init lowpan_netlink_fini(void) | |||
| 1244 | rtnl_link_unregister(&lowpan_link_ops); | 1238 | rtnl_link_unregister(&lowpan_link_ops); |
| 1245 | } | 1239 | } |
| 1246 | 1240 | ||
| 1241 | static int lowpan_device_event(struct notifier_block *unused, | ||
| 1242 | unsigned long event, | ||
| 1243 | void *ptr) | ||
| 1244 | { | ||
| 1245 | struct net_device *dev = ptr; | ||
| 1246 | LIST_HEAD(del_list); | ||
| 1247 | struct lowpan_dev_record *entry, *tmp; | ||
| 1248 | |||
| 1249 | if (dev->type != ARPHRD_IEEE802154) | ||
| 1250 | goto out; | ||
| 1251 | |||
| 1252 | if (event == NETDEV_UNREGISTER) { | ||
| 1253 | list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { | ||
| 1254 | if (lowpan_dev_info(entry->ldev)->real_dev == dev) | ||
| 1255 | lowpan_dellink(entry->ldev, &del_list); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | unregister_netdevice_many(&del_list); | ||
| 1259 | }; | ||
| 1260 | |||
| 1261 | out: | ||
| 1262 | return NOTIFY_DONE; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | static struct notifier_block lowpan_dev_notifier = { | ||
| 1266 | .notifier_call = lowpan_device_event, | ||
| 1267 | }; | ||
| 1268 | |||
| 1247 | static struct packet_type lowpan_packet_type = { | 1269 | static struct packet_type lowpan_packet_type = { |
| 1248 | .type = __constant_htons(ETH_P_IEEE802154), | 1270 | .type = __constant_htons(ETH_P_IEEE802154), |
| 1249 | .func = lowpan_rcv, | 1271 | .func = lowpan_rcv, |
| @@ -1258,6 +1280,12 @@ static int __init lowpan_init_module(void) | |||
| 1258 | goto out; | 1280 | goto out; |
| 1259 | 1281 | ||
| 1260 | dev_add_pack(&lowpan_packet_type); | 1282 | dev_add_pack(&lowpan_packet_type); |
| 1283 | |||
| 1284 | err = register_netdevice_notifier(&lowpan_dev_notifier); | ||
| 1285 | if (err < 0) { | ||
| 1286 | dev_remove_pack(&lowpan_packet_type); | ||
| 1287 | lowpan_netlink_fini(); | ||
| 1288 | } | ||
| 1261 | out: | 1289 | out: |
| 1262 | return err; | 1290 | return err; |
| 1263 | } | 1291 | } |
| @@ -1270,6 +1298,8 @@ static void __exit lowpan_cleanup_module(void) | |||
| 1270 | 1298 | ||
| 1271 | dev_remove_pack(&lowpan_packet_type); | 1299 | dev_remove_pack(&lowpan_packet_type); |
| 1272 | 1300 | ||
| 1301 | unregister_netdevice_notifier(&lowpan_dev_notifier); | ||
| 1302 | |||
| 1273 | /* Now 6lowpan packet_type is removed, so no new fragments are | 1303 | /* Now 6lowpan packet_type is removed, so no new fragments are |
| 1274 | * expected on RX, therefore that's the time to clean incomplete | 1304 | * expected on RX, therefore that's the time to clean incomplete |
| 1275 | * fragments. | 1305 | * fragments. |
