1 /* This program is free software; you can redistribute it and/or modify 2 * it under the terms of the GNU General Public License version 2 3 * as published by the Free Software Foundation. 4 * 5 * This program is distributed in the hope that it will be useful, 6 * but WITHOUT ANY WARRANTY; without even the implied warranty of 7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8 * GNU General Public License for more details. 9 * 10 * Authors: 11 * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> 12 */ 13 14 #include <linux/module.h> 15 16 #include <net/6lowpan.h> 17 18 #include "6lowpan_i.h" 19 20 int lowpan_register_netdevice(struct net_device *dev, 21 enum lowpan_lltypes lltype) 22 { 23 int i, ret; 24 25 dev->addr_len = EUI64_ADDR_LEN; 26 dev->type = ARPHRD_6LOWPAN; 27 dev->mtu = IPV6_MIN_MTU; 28 dev->priv_flags |= IFF_NO_QUEUE; 29 30 lowpan_dev(dev)->lltype = lltype; 31 32 spin_lock_init(&lowpan_dev(dev)->ctx.lock); 33 for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) 34 lowpan_dev(dev)->ctx.table[i].id = i; 35 36 ret = register_netdevice(dev); 37 if (ret < 0) 38 return ret; 39 40 ret = lowpan_dev_debugfs_init(dev); 41 if (ret < 0) 42 unregister_netdevice(dev); 43 44 return ret; 45 } 46 EXPORT_SYMBOL(lowpan_register_netdevice); 47 48 int lowpan_register_netdev(struct net_device *dev, 49 enum lowpan_lltypes lltype) 50 { 51 int ret; 52 53 rtnl_lock(); 54 ret = lowpan_register_netdevice(dev, lltype); 55 rtnl_unlock(); 56 return ret; 57 } 58 EXPORT_SYMBOL(lowpan_register_netdev); 59 60 void lowpan_unregister_netdevice(struct net_device *dev) 61 { 62 unregister_netdevice(dev); 63 lowpan_dev_debugfs_exit(dev); 64 } 65 EXPORT_SYMBOL(lowpan_unregister_netdevice); 66 67 void lowpan_unregister_netdev(struct net_device *dev) 68 { 69 rtnl_lock(); 70 lowpan_unregister_netdevice(dev); 71 rtnl_unlock(); 72 } 73 EXPORT_SYMBOL(lowpan_unregister_netdev); 74 75 static int lowpan_event(struct notifier_block *unused, 76 unsigned long event, void *ptr) 77 { 78 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 79 int i; 80 81 if (dev->type != ARPHRD_6LOWPAN) 82 return NOTIFY_DONE; 83 84 switch (event) { 85 case NETDEV_DOWN: 86 for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) 87 clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, 88 &lowpan_dev(dev)->ctx.table[i].flags); 89 break; 90 default: 91 return NOTIFY_DONE; 92 } 93 94 return NOTIFY_OK; 95 } 96 97 static struct notifier_block lowpan_notifier = { 98 .notifier_call = lowpan_event, 99 }; 100 101 static int __init lowpan_module_init(void) 102 { 103 int ret; 104 105 ret = lowpan_debugfs_init(); 106 if (ret < 0) 107 return ret; 108 109 ret = register_netdevice_notifier(&lowpan_notifier); 110 if (ret < 0) { 111 lowpan_debugfs_exit(); 112 return ret; 113 } 114 115 request_module_nowait("ipv6"); 116 117 request_module_nowait("nhc_dest"); 118 request_module_nowait("nhc_fragment"); 119 request_module_nowait("nhc_hop"); 120 request_module_nowait("nhc_ipv6"); 121 request_module_nowait("nhc_mobility"); 122 request_module_nowait("nhc_routing"); 123 request_module_nowait("nhc_udp"); 124 125 return 0; 126 } 127 128 static void __exit lowpan_module_exit(void) 129 { 130 lowpan_debugfs_exit(); 131 unregister_netdevice_notifier(&lowpan_notifier); 132 } 133 134 module_init(lowpan_module_init); 135 module_exit(lowpan_module_exit); 136 137 MODULE_LICENSE("GPL"); 138