Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Authors:
0005  * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
0006  */
0007 
0008 #include <linux/if_arp.h>
0009 #include <linux/module.h>
0010 
0011 #include <net/6lowpan.h>
0012 #include <net/addrconf.h>
0013 
0014 #include "6lowpan_i.h"
0015 
0016 int lowpan_register_netdevice(struct net_device *dev,
0017                   enum lowpan_lltypes lltype)
0018 {
0019     int i, ret;
0020 
0021     switch (lltype) {
0022     case LOWPAN_LLTYPE_IEEE802154:
0023         dev->addr_len = EUI64_ADDR_LEN;
0024         break;
0025 
0026     case LOWPAN_LLTYPE_BTLE:
0027         dev->addr_len = ETH_ALEN;
0028         break;
0029     }
0030 
0031     dev->type = ARPHRD_6LOWPAN;
0032     dev->mtu = IPV6_MIN_MTU;
0033 
0034     lowpan_dev(dev)->lltype = lltype;
0035 
0036     spin_lock_init(&lowpan_dev(dev)->ctx.lock);
0037     for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
0038         lowpan_dev(dev)->ctx.table[i].id = i;
0039 
0040     dev->ndisc_ops = &lowpan_ndisc_ops;
0041 
0042     ret = register_netdevice(dev);
0043     if (ret < 0)
0044         return ret;
0045 
0046     lowpan_dev_debugfs_init(dev);
0047 
0048     return ret;
0049 }
0050 EXPORT_SYMBOL(lowpan_register_netdevice);
0051 
0052 int lowpan_register_netdev(struct net_device *dev,
0053                enum lowpan_lltypes lltype)
0054 {
0055     int ret;
0056 
0057     rtnl_lock();
0058     ret = lowpan_register_netdevice(dev, lltype);
0059     rtnl_unlock();
0060     return ret;
0061 }
0062 EXPORT_SYMBOL(lowpan_register_netdev);
0063 
0064 void lowpan_unregister_netdevice(struct net_device *dev)
0065 {
0066     unregister_netdevice(dev);
0067     lowpan_dev_debugfs_exit(dev);
0068 }
0069 EXPORT_SYMBOL(lowpan_unregister_netdevice);
0070 
0071 void lowpan_unregister_netdev(struct net_device *dev)
0072 {
0073     rtnl_lock();
0074     lowpan_unregister_netdevice(dev);
0075     rtnl_unlock();
0076 }
0077 EXPORT_SYMBOL(lowpan_unregister_netdev);
0078 
0079 int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev)
0080 {
0081     struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
0082 
0083     /* Set short_addr autoconfiguration if short_addr is present only */
0084     if (!lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr))
0085         return -1;
0086 
0087     /* For either address format, all zero addresses MUST NOT be used */
0088     if (wpan_dev->pan_id == cpu_to_le16(0x0000) &&
0089         wpan_dev->short_addr == cpu_to_le16(0x0000))
0090         return -1;
0091 
0092     /* Alternatively, if no PAN ID is known, 16 zero bits may be used */
0093     if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
0094         memset(eui, 0, 2);
0095     else
0096         ieee802154_le16_to_be16(eui, &wpan_dev->pan_id);
0097 
0098     /* The "Universal/Local" (U/L) bit shall be set to zero */
0099     eui[0] &= ~2;
0100     eui[2] = 0;
0101     eui[3] = 0xFF;
0102     eui[4] = 0xFE;
0103     eui[5] = 0;
0104     ieee802154_le16_to_be16(&eui[6], &wpan_dev->short_addr);
0105     return 0;
0106 }
0107 
0108 static int lowpan_event(struct notifier_block *unused,
0109             unsigned long event, void *ptr)
0110 {
0111     struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0112     struct inet6_dev *idev;
0113     struct in6_addr addr;
0114     int i;
0115 
0116     if (dev->type != ARPHRD_6LOWPAN)
0117         return NOTIFY_DONE;
0118 
0119     idev = __in6_dev_get(dev);
0120     if (!idev)
0121         return NOTIFY_DONE;
0122 
0123     switch (event) {
0124     case NETDEV_UP:
0125     case NETDEV_CHANGE:
0126         /* (802.15.4 6LoWPAN short address slaac handling */
0127         if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
0128             addrconf_ifid_802154_6lowpan(addr.s6_addr + 8, dev) == 0) {
0129             __ipv6_addr_set_half(&addr.s6_addr32[0],
0130                          htonl(0xFE800000), 0);
0131             addrconf_add_linklocal(idev, &addr, 0);
0132         }
0133         break;
0134     case NETDEV_DOWN:
0135         for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
0136             clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
0137                   &lowpan_dev(dev)->ctx.table[i].flags);
0138         break;
0139     default:
0140         return NOTIFY_DONE;
0141     }
0142 
0143     return NOTIFY_OK;
0144 }
0145 
0146 static struct notifier_block lowpan_notifier = {
0147     .notifier_call = lowpan_event,
0148 };
0149 
0150 static int __init lowpan_module_init(void)
0151 {
0152     int ret;
0153 
0154     lowpan_debugfs_init();
0155 
0156     ret = register_netdevice_notifier(&lowpan_notifier);
0157     if (ret < 0) {
0158         lowpan_debugfs_exit();
0159         return ret;
0160     }
0161 
0162     request_module_nowait("nhc_dest");
0163     request_module_nowait("nhc_fragment");
0164     request_module_nowait("nhc_hop");
0165     request_module_nowait("nhc_ipv6");
0166     request_module_nowait("nhc_mobility");
0167     request_module_nowait("nhc_routing");
0168     request_module_nowait("nhc_udp");
0169 
0170     return 0;
0171 }
0172 
0173 static void __exit lowpan_module_exit(void)
0174 {
0175     lowpan_debugfs_exit();
0176     unregister_netdevice_notifier(&lowpan_notifier);
0177 }
0178 
0179 module_init(lowpan_module_init);
0180 module_exit(lowpan_module_exit);
0181 
0182 MODULE_LICENSE("GPL");