linux/net/6lowpan/core.c
<<
>>
Prefs
   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#include <net/addrconf.h>
  18
  19#include "6lowpan_i.h"
  20
  21int lowpan_register_netdevice(struct net_device *dev,
  22                              enum lowpan_lltypes lltype)
  23{
  24        int i, ret;
  25
  26        switch (lltype) {
  27        case LOWPAN_LLTYPE_IEEE802154:
  28                dev->addr_len = EUI64_ADDR_LEN;
  29                break;
  30
  31        case LOWPAN_LLTYPE_BTLE:
  32                dev->addr_len = ETH_ALEN;
  33                break;
  34        }
  35
  36        dev->type = ARPHRD_6LOWPAN;
  37        dev->mtu = IPV6_MIN_MTU;
  38
  39        lowpan_dev(dev)->lltype = lltype;
  40
  41        spin_lock_init(&lowpan_dev(dev)->ctx.lock);
  42        for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
  43                lowpan_dev(dev)->ctx.table[i].id = i;
  44
  45        dev->ndisc_ops = &lowpan_ndisc_ops;
  46
  47        ret = register_netdevice(dev);
  48        if (ret < 0)
  49                return ret;
  50
  51        ret = lowpan_dev_debugfs_init(dev);
  52        if (ret < 0)
  53                unregister_netdevice(dev);
  54
  55        return ret;
  56}
  57EXPORT_SYMBOL(lowpan_register_netdevice);
  58
  59int lowpan_register_netdev(struct net_device *dev,
  60                           enum lowpan_lltypes lltype)
  61{
  62        int ret;
  63
  64        rtnl_lock();
  65        ret = lowpan_register_netdevice(dev, lltype);
  66        rtnl_unlock();
  67        return ret;
  68}
  69EXPORT_SYMBOL(lowpan_register_netdev);
  70
  71void lowpan_unregister_netdevice(struct net_device *dev)
  72{
  73        unregister_netdevice(dev);
  74        lowpan_dev_debugfs_exit(dev);
  75}
  76EXPORT_SYMBOL(lowpan_unregister_netdevice);
  77
  78void lowpan_unregister_netdev(struct net_device *dev)
  79{
  80        rtnl_lock();
  81        lowpan_unregister_netdevice(dev);
  82        rtnl_unlock();
  83}
  84EXPORT_SYMBOL(lowpan_unregister_netdev);
  85
  86int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev)
  87{
  88        struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
  89
  90        /* Set short_addr autoconfiguration if short_addr is present only */
  91        if (!lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr))
  92                return -1;
  93
  94        /* For either address format, all zero addresses MUST NOT be used */
  95        if (wpan_dev->pan_id == cpu_to_le16(0x0000) &&
  96            wpan_dev->short_addr == cpu_to_le16(0x0000))
  97                return -1;
  98
  99        /* Alternatively, if no PAN ID is known, 16 zero bits may be used */
 100        if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
 101                memset(eui, 0, 2);
 102        else
 103                ieee802154_le16_to_be16(eui, &wpan_dev->pan_id);
 104
 105        /* The "Universal/Local" (U/L) bit shall be set to zero */
 106        eui[0] &= ~2;
 107        eui[2] = 0;
 108        eui[3] = 0xFF;
 109        eui[4] = 0xFE;
 110        eui[5] = 0;
 111        ieee802154_le16_to_be16(&eui[6], &wpan_dev->short_addr);
 112        return 0;
 113}
 114
 115static int lowpan_event(struct notifier_block *unused,
 116                        unsigned long event, void *ptr)
 117{
 118        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 119        struct inet6_dev *idev;
 120        struct in6_addr addr;
 121        int i;
 122
 123        if (dev->type != ARPHRD_6LOWPAN)
 124                return NOTIFY_DONE;
 125
 126        idev = __in6_dev_get(dev);
 127        if (!idev)
 128                return NOTIFY_DONE;
 129
 130        switch (event) {
 131        case NETDEV_UP:
 132        case NETDEV_CHANGE:
 133                /* (802.15.4 6LoWPAN short address slaac handling */
 134                if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
 135                    addrconf_ifid_802154_6lowpan(addr.s6_addr + 8, dev) == 0) {
 136                        __ipv6_addr_set_half(&addr.s6_addr32[0],
 137                                             htonl(0xFE800000), 0);
 138                        addrconf_add_linklocal(idev, &addr, 0);
 139                }
 140                break;
 141        case NETDEV_DOWN:
 142                for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
 143                        clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
 144                                  &lowpan_dev(dev)->ctx.table[i].flags);
 145                break;
 146        default:
 147                return NOTIFY_DONE;
 148        }
 149
 150        return NOTIFY_OK;
 151}
 152
 153static struct notifier_block lowpan_notifier = {
 154        .notifier_call = lowpan_event,
 155};
 156
 157static int __init lowpan_module_init(void)
 158{
 159        int ret;
 160
 161        ret = lowpan_debugfs_init();
 162        if (ret < 0)
 163                return ret;
 164
 165        ret = register_netdevice_notifier(&lowpan_notifier);
 166        if (ret < 0) {
 167                lowpan_debugfs_exit();
 168                return ret;
 169        }
 170
 171        request_module_nowait("nhc_dest");
 172        request_module_nowait("nhc_fragment");
 173        request_module_nowait("nhc_hop");
 174        request_module_nowait("nhc_ipv6");
 175        request_module_nowait("nhc_mobility");
 176        request_module_nowait("nhc_routing");
 177        request_module_nowait("nhc_udp");
 178
 179        return 0;
 180}
 181
 182static void __exit lowpan_module_exit(void)
 183{
 184        lowpan_debugfs_exit();
 185        unregister_netdevice_notifier(&lowpan_notifier);
 186}
 187
 188module_init(lowpan_module_init);
 189module_exit(lowpan_module_exit);
 190
 191MODULE_LICENSE("GPL");
 192