1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
55static int open_count;
56
57static const struct header_ops lowpan_header_ops = {
58 .create = lowpan_header_create,
59};
60
61static int lowpan_dev_init(struct net_device *ldev)
62{
63 netdev_lockdep_set_classes(ldev);
64
65 return 0;
66}
67
68static int lowpan_open(struct net_device *dev)
69{
70 if (!open_count)
71 lowpan_rx_init();
72 open_count++;
73 return 0;
74}
75
76static int lowpan_stop(struct net_device *dev)
77{
78 open_count--;
79 if (!open_count)
80 lowpan_rx_exit();
81 return 0;
82}
83
84static int lowpan_neigh_construct(struct net_device *dev, struct neighbour *n)
85{
86 struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n));
87
88
89 neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
90 return 0;
91}
92
93static int lowpan_get_iflink(const struct net_device *dev)
94{
95 return lowpan_802154_dev(dev)->wdev->ifindex;
96}
97
98static const struct net_device_ops lowpan_netdev_ops = {
99 .ndo_init = lowpan_dev_init,
100 .ndo_start_xmit = lowpan_xmit,
101 .ndo_open = lowpan_open,
102 .ndo_stop = lowpan_stop,
103 .ndo_neigh_construct = lowpan_neigh_construct,
104 .ndo_get_iflink = lowpan_get_iflink,
105};
106
107static void lowpan_setup(struct net_device *ldev)
108{
109 memset(ldev->broadcast, 0xff, IEEE802154_ADDR_LEN);
110
111 ldev->hard_header_len = sizeof(struct ipv6hdr);
112 ldev->flags = IFF_BROADCAST | IFF_MULTICAST;
113 ldev->priv_flags |= IFF_NO_QUEUE;
114
115 ldev->netdev_ops = &lowpan_netdev_ops;
116 ldev->header_ops = &lowpan_header_ops;
117 ldev->needs_free_netdev = true;
118 ldev->features |= NETIF_F_NETNS_LOCAL;
119}
120
121static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[],
122 struct netlink_ext_ack *extack)
123{
124 if (tb[IFLA_ADDRESS]) {
125 if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
126 return -EINVAL;
127 }
128 return 0;
129}
130
131static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
132 struct nlattr *tb[], struct nlattr *data[],
133 struct netlink_ext_ack *extack)
134{
135 struct net_device *wdev;
136 int ret;
137
138 ASSERT_RTNL();
139
140 pr_debug("adding new link\n");
141
142 if (!tb[IFLA_LINK])
143 return -EINVAL;
144
145 wdev = dev_get_by_index(dev_net(ldev), nla_get_u32(tb[IFLA_LINK]));
146 if (!wdev)
147 return -ENODEV;
148 if (wdev->type != ARPHRD_IEEE802154) {
149 dev_put(wdev);
150 return -EINVAL;
151 }
152
153 if (wdev->ieee802154_ptr->lowpan_dev) {
154 dev_put(wdev);
155 return -EBUSY;
156 }
157
158 lowpan_802154_dev(ldev)->wdev = wdev;
159
160 memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
161
162
163
164
165
166
167 ldev->needed_headroom = LOWPAN_IPHC_MAX_HEADER_LEN +
168 wdev->needed_headroom;
169 ldev->needed_tailroom = wdev->needed_tailroom;
170
171 ldev->neigh_priv_len = sizeof(struct lowpan_802154_neigh);
172
173 ret = lowpan_register_netdevice(ldev, LOWPAN_LLTYPE_IEEE802154);
174 if (ret < 0) {
175 dev_put(wdev);
176 return ret;
177 }
178
179 wdev->ieee802154_ptr->lowpan_dev = ldev;
180 return 0;
181}
182
183static void lowpan_dellink(struct net_device *ldev, struct list_head *head)
184{
185 struct net_device *wdev = lowpan_802154_dev(ldev)->wdev;
186
187 ASSERT_RTNL();
188
189 wdev->ieee802154_ptr->lowpan_dev = NULL;
190 lowpan_unregister_netdevice(ldev);
191 dev_put(wdev);
192}
193
194static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
195 .kind = "lowpan",
196 .priv_size = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_802154_dev)),
197 .setup = lowpan_setup,
198 .newlink = lowpan_newlink,
199 .dellink = lowpan_dellink,
200 .validate = lowpan_validate,
201};
202
203static inline int __init lowpan_netlink_init(void)
204{
205 return rtnl_link_register(&lowpan_link_ops);
206}
207
208static inline void lowpan_netlink_fini(void)
209{
210 rtnl_link_unregister(&lowpan_link_ops);
211}
212
213static int lowpan_device_event(struct notifier_block *unused,
214 unsigned long event, void *ptr)
215{
216 struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
217 struct wpan_dev *wpan_dev;
218
219 if (ndev->type != ARPHRD_IEEE802154)
220 return NOTIFY_DONE;
221 wpan_dev = ndev->ieee802154_ptr;
222 if (!wpan_dev)
223 return NOTIFY_DONE;
224
225 switch (event) {
226 case NETDEV_UNREGISTER:
227
228
229
230
231 if (wpan_dev->lowpan_dev)
232 lowpan_dellink(wpan_dev->lowpan_dev, NULL);
233 break;
234 default:
235 return NOTIFY_DONE;
236 }
237
238 return NOTIFY_OK;
239}
240
241static struct notifier_block lowpan_dev_notifier = {
242 .notifier_call = lowpan_device_event,
243};
244
245static int __init lowpan_init_module(void)
246{
247 int err = 0;
248
249 err = lowpan_net_frag_init();
250 if (err < 0)
251 goto out;
252
253 err = lowpan_netlink_init();
254 if (err < 0)
255 goto out_frag;
256
257 err = register_netdevice_notifier(&lowpan_dev_notifier);
258 if (err < 0)
259 goto out_pack;
260
261 return 0;
262
263out_pack:
264 lowpan_netlink_fini();
265out_frag:
266 lowpan_net_frag_exit();
267out:
268 return err;
269}
270
271static void __exit lowpan_cleanup_module(void)
272{
273 lowpan_netlink_fini();
274
275 lowpan_net_frag_exit();
276
277 unregister_netdevice_notifier(&lowpan_dev_notifier);
278}
279
280module_init(lowpan_init_module);
281module_exit(lowpan_cleanup_module);
282MODULE_LICENSE("GPL");
283MODULE_ALIAS_RTNL_LINK("lowpan");
284