root/net/ieee802154/6lowpan/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lowpan_open
  2. lowpan_stop
  3. lowpan_neigh_construct
  4. lowpan_get_iflink
  5. lowpan_setup
  6. lowpan_validate
  7. lowpan_newlink
  8. lowpan_dellink
  9. lowpan_netlink_init
  10. lowpan_netlink_fini
  11. lowpan_device_event
  12. lowpan_init_module
  13. lowpan_cleanup_module

   1 /* Copyright 2011, Siemens AG
   2  * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
   3  */
   4 
   5 /* Based on patches from Jon Smirl <jonsmirl@gmail.com>
   6  * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License version 2
  10  * as published by the Free Software Foundation.
  11  *
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  */
  17 
  18 /* Jon's code is based on 6lowpan implementation for Contiki which is:
  19  * Copyright (c) 2008, Swedish Institute of Computer Science.
  20  * All rights reserved.
  21  *
  22  * Redistribution and use in source and binary forms, with or without
  23  * modification, are permitted provided that the following conditions
  24  * are met:
  25  * 1. Redistributions of source code must retain the above copyright
  26  *    notice, this list of conditions and the following disclaimer.
  27  * 2. Redistributions in binary form must reproduce the above copyright
  28  *    notice, this list of conditions and the following disclaimer in the
  29  *    documentation and/or other materials provided with the distribution.
  30  * 3. Neither the name of the Institute nor the names of its contributors
  31  *    may be used to endorse or promote products derived from this software
  32  *    without specific prior written permission.
  33  *
  34  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  38  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  44  * SUCH DAMAGE.
  45  */
  46 
  47 #include <linux/module.h>
  48 #include <linux/netdevice.h>
  49 #include <linux/ieee802154.h>
  50 
  51 #include <net/ipv6.h>
  52 
  53 #include "6lowpan_i.h"
  54 
  55 static int open_count;
  56 
  57 static const struct header_ops lowpan_header_ops = {
  58         .create = lowpan_header_create,
  59 };
  60 
  61 static int lowpan_open(struct net_device *dev)
  62 {
  63         if (!open_count)
  64                 lowpan_rx_init();
  65         open_count++;
  66         return 0;
  67 }
  68 
  69 static int lowpan_stop(struct net_device *dev)
  70 {
  71         open_count--;
  72         if (!open_count)
  73                 lowpan_rx_exit();
  74         return 0;
  75 }
  76 
  77 static int lowpan_neigh_construct(struct net_device *dev, struct neighbour *n)
  78 {
  79         struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n));
  80 
  81         /* default no short_addr is available for a neighbour */
  82         neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
  83         return 0;
  84 }
  85 
  86 static int lowpan_get_iflink(const struct net_device *dev)
  87 {
  88         return lowpan_802154_dev(dev)->wdev->ifindex;
  89 }
  90 
  91 static const struct net_device_ops lowpan_netdev_ops = {
  92         .ndo_start_xmit         = lowpan_xmit,
  93         .ndo_open               = lowpan_open,
  94         .ndo_stop               = lowpan_stop,
  95         .ndo_neigh_construct    = lowpan_neigh_construct,
  96         .ndo_get_iflink         = lowpan_get_iflink,
  97 };
  98 
  99 static void lowpan_setup(struct net_device *ldev)
 100 {
 101         memset(ldev->broadcast, 0xff, IEEE802154_ADDR_LEN);
 102         /* We need an ipv6hdr as minimum len when calling xmit */
 103         ldev->hard_header_len   = sizeof(struct ipv6hdr);
 104         ldev->flags             = IFF_BROADCAST | IFF_MULTICAST;
 105         ldev->priv_flags        |= IFF_NO_QUEUE;
 106 
 107         ldev->netdev_ops        = &lowpan_netdev_ops;
 108         ldev->header_ops        = &lowpan_header_ops;
 109         ldev->needs_free_netdev = true;
 110         ldev->features          |= NETIF_F_NETNS_LOCAL;
 111 }
 112 
 113 static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[],
 114                            struct netlink_ext_ack *extack)
 115 {
 116         if (tb[IFLA_ADDRESS]) {
 117                 if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
 118                         return -EINVAL;
 119         }
 120         return 0;
 121 }
 122 
 123 static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
 124                           struct nlattr *tb[], struct nlattr *data[],
 125                           struct netlink_ext_ack *extack)
 126 {
 127         struct net_device *wdev;
 128         int ret;
 129 
 130         ASSERT_RTNL();
 131 
 132         pr_debug("adding new link\n");
 133 
 134         if (!tb[IFLA_LINK])
 135                 return -EINVAL;
 136         /* find and hold wpan device */
 137         wdev = dev_get_by_index(dev_net(ldev), nla_get_u32(tb[IFLA_LINK]));
 138         if (!wdev)
 139                 return -ENODEV;
 140         if (wdev->type != ARPHRD_IEEE802154) {
 141                 dev_put(wdev);
 142                 return -EINVAL;
 143         }
 144 
 145         if (wdev->ieee802154_ptr->lowpan_dev) {
 146                 dev_put(wdev);
 147                 return -EBUSY;
 148         }
 149 
 150         lowpan_802154_dev(ldev)->wdev = wdev;
 151         /* Set the lowpan hardware address to the wpan hardware address. */
 152         memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
 153         /* We need headroom for possible wpan_dev_hard_header call and tailroom
 154          * for encryption/fcs handling. The lowpan interface will replace
 155          * the IPv6 header with 6LoWPAN header. At worst case the 6LoWPAN
 156          * header has LOWPAN_IPHC_MAX_HEADER_LEN more bytes than the IPv6
 157          * header.
 158          */
 159         ldev->needed_headroom = LOWPAN_IPHC_MAX_HEADER_LEN +
 160                                 wdev->needed_headroom;
 161         ldev->needed_tailroom = wdev->needed_tailroom;
 162 
 163         ldev->neigh_priv_len = sizeof(struct lowpan_802154_neigh);
 164 
 165         ret = lowpan_register_netdevice(ldev, LOWPAN_LLTYPE_IEEE802154);
 166         if (ret < 0) {
 167                 dev_put(wdev);
 168                 return ret;
 169         }
 170 
 171         wdev->ieee802154_ptr->lowpan_dev = ldev;
 172         return 0;
 173 }
 174 
 175 static void lowpan_dellink(struct net_device *ldev, struct list_head *head)
 176 {
 177         struct net_device *wdev = lowpan_802154_dev(ldev)->wdev;
 178 
 179         ASSERT_RTNL();
 180 
 181         wdev->ieee802154_ptr->lowpan_dev = NULL;
 182         lowpan_unregister_netdevice(ldev);
 183         dev_put(wdev);
 184 }
 185 
 186 static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
 187         .kind           = "lowpan",
 188         .priv_size      = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_802154_dev)),
 189         .setup          = lowpan_setup,
 190         .newlink        = lowpan_newlink,
 191         .dellink        = lowpan_dellink,
 192         .validate       = lowpan_validate,
 193 };
 194 
 195 static inline int __init lowpan_netlink_init(void)
 196 {
 197         return rtnl_link_register(&lowpan_link_ops);
 198 }
 199 
 200 static inline void lowpan_netlink_fini(void)
 201 {
 202         rtnl_link_unregister(&lowpan_link_ops);
 203 }
 204 
 205 static int lowpan_device_event(struct notifier_block *unused,
 206                                unsigned long event, void *ptr)
 207 {
 208         struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
 209         struct wpan_dev *wpan_dev;
 210 
 211         if (ndev->type != ARPHRD_IEEE802154)
 212                 return NOTIFY_DONE;
 213         wpan_dev = ndev->ieee802154_ptr;
 214         if (!wpan_dev)
 215                 return NOTIFY_DONE;
 216 
 217         switch (event) {
 218         case NETDEV_UNREGISTER:
 219                 /* Check if wpan interface is unregistered that we
 220                  * also delete possible lowpan interfaces which belongs
 221                  * to the wpan interface.
 222                  */
 223                 if (wpan_dev->lowpan_dev)
 224                         lowpan_dellink(wpan_dev->lowpan_dev, NULL);
 225                 break;
 226         default:
 227                 return NOTIFY_DONE;
 228         }
 229 
 230         return NOTIFY_OK;
 231 }
 232 
 233 static struct notifier_block lowpan_dev_notifier = {
 234         .notifier_call = lowpan_device_event,
 235 };
 236 
 237 static int __init lowpan_init_module(void)
 238 {
 239         int err = 0;
 240 
 241         err = lowpan_net_frag_init();
 242         if (err < 0)
 243                 goto out;
 244 
 245         err = lowpan_netlink_init();
 246         if (err < 0)
 247                 goto out_frag;
 248 
 249         err = register_netdevice_notifier(&lowpan_dev_notifier);
 250         if (err < 0)
 251                 goto out_pack;
 252 
 253         return 0;
 254 
 255 out_pack:
 256         lowpan_netlink_fini();
 257 out_frag:
 258         lowpan_net_frag_exit();
 259 out:
 260         return err;
 261 }
 262 
 263 static void __exit lowpan_cleanup_module(void)
 264 {
 265         lowpan_netlink_fini();
 266 
 267         lowpan_net_frag_exit();
 268 
 269         unregister_netdevice_notifier(&lowpan_dev_notifier);
 270 }
 271 
 272 module_init(lowpan_init_module);
 273 module_exit(lowpan_cleanup_module);
 274 MODULE_LICENSE("GPL");
 275 MODULE_ALIAS_RTNL_LINK("lowpan");

/* [<][>][^][v][top][bottom][index][help] */