core.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* Copyright 2011, Siemens AG
  2. * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  3. */
  4. /* Based on patches from Jon Smirl <jonsmirl@gmail.com>
  5. * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. /* Jon's code is based on 6lowpan implementation for Contiki which is:
  17. * Copyright (c) 2008, Swedish Institute of Computer Science.
  18. * All rights reserved.
  19. *
  20. * Redistribution and use in source and binary forms, with or without
  21. * modification, are permitted provided that the following conditions
  22. * are met:
  23. * 1. Redistributions of source code must retain the above copyright
  24. * notice, this list of conditions and the following disclaimer.
  25. * 2. Redistributions in binary form must reproduce the above copyright
  26. * notice, this list of conditions and the following disclaimer in the
  27. * documentation and/or other materials provided with the distribution.
  28. * 3. Neither the name of the Institute nor the names of its contributors
  29. * may be used to endorse or promote products derived from this software
  30. * without specific prior written permission.
  31. *
  32. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  33. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  34. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  36. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  40. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  41. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  42. * SUCH DAMAGE.
  43. */
  44. #include <linux/module.h>
  45. #include <linux/netdevice.h>
  46. #include <linux/ieee802154.h>
  47. #include <net/ipv6.h>
  48. #include "6lowpan_i.h"
  49. static int open_count;
  50. static struct header_ops lowpan_header_ops = {
  51. .create = lowpan_header_create,
  52. };
  53. static struct lock_class_key lowpan_tx_busylock;
  54. static struct lock_class_key lowpan_netdev_xmit_lock_key;
  55. static void lowpan_set_lockdep_class_one(struct net_device *dev,
  56. struct netdev_queue *txq,
  57. void *_unused)
  58. {
  59. lockdep_set_class(&txq->_xmit_lock,
  60. &lowpan_netdev_xmit_lock_key);
  61. }
  62. static int lowpan_dev_init(struct net_device *dev)
  63. {
  64. netdev_for_each_tx_queue(dev, lowpan_set_lockdep_class_one, NULL);
  65. dev->qdisc_tx_busylock = &lowpan_tx_busylock;
  66. return 0;
  67. }
  68. static const struct net_device_ops lowpan_netdev_ops = {
  69. .ndo_init = lowpan_dev_init,
  70. .ndo_start_xmit = lowpan_xmit,
  71. };
  72. static void lowpan_setup(struct net_device *dev)
  73. {
  74. dev->addr_len = IEEE802154_ADDR_LEN;
  75. memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
  76. dev->type = ARPHRD_6LOWPAN;
  77. /* Frame Control + Sequence Number + Address fields + Security Header */
  78. dev->hard_header_len = 2 + 1 + 20 + 14;
  79. dev->needed_tailroom = 2; /* FCS */
  80. dev->mtu = IPV6_MIN_MTU;
  81. dev->priv_flags |= IFF_NO_QUEUE;
  82. dev->flags = IFF_BROADCAST | IFF_MULTICAST;
  83. dev->watchdog_timeo = 0;
  84. dev->netdev_ops = &lowpan_netdev_ops;
  85. dev->header_ops = &lowpan_header_ops;
  86. dev->destructor = free_netdev;
  87. dev->features |= NETIF_F_NETNS_LOCAL;
  88. }
  89. static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
  90. {
  91. if (tb[IFLA_ADDRESS]) {
  92. if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
  93. return -EINVAL;
  94. }
  95. return 0;
  96. }
  97. static int lowpan_newlink(struct net *src_net, struct net_device *dev,
  98. struct nlattr *tb[], struct nlattr *data[])
  99. {
  100. struct net_device *real_dev;
  101. int ret;
  102. ASSERT_RTNL();
  103. pr_debug("adding new link\n");
  104. if (!tb[IFLA_LINK] ||
  105. !net_eq(dev_net(dev), &init_net))
  106. return -EINVAL;
  107. /* find and hold real wpan device */
  108. real_dev = dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK]));
  109. if (!real_dev)
  110. return -ENODEV;
  111. if (real_dev->type != ARPHRD_IEEE802154) {
  112. dev_put(real_dev);
  113. return -EINVAL;
  114. }
  115. if (real_dev->ieee802154_ptr->lowpan_dev) {
  116. dev_put(real_dev);
  117. return -EBUSY;
  118. }
  119. lowpan_dev_info(dev)->real_dev = real_dev;
  120. /* Set the lowpan hardware address to the wpan hardware address. */
  121. memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
  122. lowpan_netdev_setup(dev, LOWPAN_LLTYPE_IEEE802154);
  123. ret = register_netdevice(dev);
  124. if (ret < 0) {
  125. dev_put(real_dev);
  126. return ret;
  127. }
  128. real_dev->ieee802154_ptr->lowpan_dev = dev;
  129. if (!open_count)
  130. lowpan_rx_init();
  131. open_count++;
  132. return 0;
  133. }
  134. static void lowpan_dellink(struct net_device *dev, struct list_head *head)
  135. {
  136. struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
  137. struct net_device *real_dev = lowpan_dev->real_dev;
  138. ASSERT_RTNL();
  139. open_count--;
  140. if (!open_count)
  141. lowpan_rx_exit();
  142. real_dev->ieee802154_ptr->lowpan_dev = NULL;
  143. unregister_netdevice(dev);
  144. dev_put(real_dev);
  145. }
  146. static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
  147. .kind = "lowpan",
  148. .priv_size = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_dev_info)),
  149. .setup = lowpan_setup,
  150. .newlink = lowpan_newlink,
  151. .dellink = lowpan_dellink,
  152. .validate = lowpan_validate,
  153. };
  154. static inline int __init lowpan_netlink_init(void)
  155. {
  156. return rtnl_link_register(&lowpan_link_ops);
  157. }
  158. static inline void lowpan_netlink_fini(void)
  159. {
  160. rtnl_link_unregister(&lowpan_link_ops);
  161. }
  162. static int lowpan_device_event(struct notifier_block *unused,
  163. unsigned long event, void *ptr)
  164. {
  165. struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  166. if (dev->type != ARPHRD_IEEE802154)
  167. goto out;
  168. switch (event) {
  169. case NETDEV_UNREGISTER:
  170. /* Check if wpan interface is unregistered that we
  171. * also delete possible lowpan interfaces which belongs
  172. * to the wpan interface.
  173. */
  174. if (dev->ieee802154_ptr && dev->ieee802154_ptr->lowpan_dev)
  175. lowpan_dellink(dev->ieee802154_ptr->lowpan_dev, NULL);
  176. break;
  177. default:
  178. break;
  179. }
  180. out:
  181. return NOTIFY_DONE;
  182. }
  183. static struct notifier_block lowpan_dev_notifier = {
  184. .notifier_call = lowpan_device_event,
  185. };
  186. static int __init lowpan_init_module(void)
  187. {
  188. int err = 0;
  189. err = lowpan_net_frag_init();
  190. if (err < 0)
  191. goto out;
  192. err = lowpan_netlink_init();
  193. if (err < 0)
  194. goto out_frag;
  195. err = register_netdevice_notifier(&lowpan_dev_notifier);
  196. if (err < 0)
  197. goto out_pack;
  198. return 0;
  199. out_pack:
  200. lowpan_netlink_fini();
  201. out_frag:
  202. lowpan_net_frag_exit();
  203. out:
  204. return err;
  205. }
  206. static void __exit lowpan_cleanup_module(void)
  207. {
  208. lowpan_netlink_fini();
  209. lowpan_net_frag_exit();
  210. unregister_netdevice_notifier(&lowpan_dev_notifier);
  211. }
  212. module_init(lowpan_init_module);
  213. module_exit(lowpan_cleanup_module);
  214. MODULE_LICENSE("GPL");
  215. MODULE_ALIAS_RTNL_LINK("lowpan");