diff options
Diffstat (limited to 'net/ieee802154/6lowpan.c')
-rw-r--r-- | net/ieee802154/6lowpan.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 6a095225148e..6d42c17af96b 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[]) |
@@ -1133,6 +1127,8 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
1133 | static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | 1127 | static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, |
1134 | struct packet_type *pt, struct net_device *orig_dev) | 1128 | struct packet_type *pt, struct net_device *orig_dev) |
1135 | { | 1129 | { |
1130 | struct sk_buff *local_skb; | ||
1131 | |||
1136 | if (!netif_running(dev)) | 1132 | if (!netif_running(dev)) |
1137 | goto drop; | 1133 | goto drop; |
1138 | 1134 | ||
@@ -1144,7 +1140,12 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1144 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ | 1140 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ |
1145 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ | 1141 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ |
1146 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ | 1142 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ |
1147 | lowpan_process_data(skb); | 1143 | local_skb = skb_clone(skb, GFP_ATOMIC); |
1144 | if (!local_skb) | ||
1145 | goto drop; | ||
1146 | lowpan_process_data(local_skb); | ||
1147 | |||
1148 | kfree_skb(skb); | ||
1148 | break; | 1149 | break; |
1149 | default: | 1150 | default: |
1150 | break; | 1151 | break; |
@@ -1237,6 +1238,34 @@ static inline void __init lowpan_netlink_fini(void) | |||
1237 | rtnl_link_unregister(&lowpan_link_ops); | 1238 | rtnl_link_unregister(&lowpan_link_ops); |
1238 | } | 1239 | } |
1239 | 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 | |||
1240 | static struct packet_type lowpan_packet_type = { | 1269 | static struct packet_type lowpan_packet_type = { |
1241 | .type = __constant_htons(ETH_P_IEEE802154), | 1270 | .type = __constant_htons(ETH_P_IEEE802154), |
1242 | .func = lowpan_rcv, | 1271 | .func = lowpan_rcv, |
@@ -1251,6 +1280,12 @@ static int __init lowpan_init_module(void) | |||
1251 | goto out; | 1280 | goto out; |
1252 | 1281 | ||
1253 | 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 | } | ||
1254 | out: | 1289 | out: |
1255 | return err; | 1290 | return err; |
1256 | } | 1291 | } |
@@ -1263,6 +1298,8 @@ static void __exit lowpan_cleanup_module(void) | |||
1263 | 1298 | ||
1264 | dev_remove_pack(&lowpan_packet_type); | 1299 | dev_remove_pack(&lowpan_packet_type); |
1265 | 1300 | ||
1301 | unregister_netdevice_notifier(&lowpan_dev_notifier); | ||
1302 | |||
1266 | /* Now 6lowpan packet_type is removed, so no new fragments are | 1303 | /* Now 6lowpan packet_type is removed, so no new fragments are |
1267 | * expected on RX, therefore that's the time to clean incomplete | 1304 | * expected on RX, therefore that's the time to clean incomplete |
1268 | * fragments. | 1305 | * fragments. |