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