]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - net/mac802154/iface.c
Bluetooth: mgmt: fix typos
[mirror_ubuntu-zesty-kernel.git] / net / mac802154 / iface.c
CommitLineData
32bad7e3 1/*
2 * Copyright 2007-2012 Siemens AG
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
32bad7e3 13 * Written by:
14 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
15 * Sergey Lapin <slapin@ossfans.org>
16 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
17 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
18 */
19
20#include <linux/netdevice.h>
21#include <linux/module.h>
22#include <linux/if_arp.h>
4ca24aca 23#include <linux/ieee802154.h>
32bad7e3 24
944742a3 25#include <net/nl802154.h>
32bad7e3 26#include <net/mac802154.h>
27#include <net/ieee802154_netdev.h>
5ad60d36 28#include <net/cfg802154.h>
32bad7e3 29
0f1556bc 30#include "ieee802154_i.h"
59cb300f 31#include "driver-ops.h"
32bad7e3 32
9b0bb4a8
PB
33static int mac802154_wpan_update_llsec(struct net_device *dev)
34{
59d19cd7 35 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
9b0bb4a8 36 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
863e88f2 37 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
9b0bb4a8
PB
38 int rc = 0;
39
40 if (ops->llsec) {
41 struct ieee802154_llsec_params params;
42 int changed = 0;
43
863e88f2 44 params.pan_id = wpan_dev->pan_id;
9b0bb4a8
PB
45 changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
46
863e88f2 47 params.hwaddr = wpan_dev->extended_addr;
9b0bb4a8
PB
48 changed |= IEEE802154_LLSEC_PARAM_HWADDR;
49
50 rc = ops->llsec->set_params(dev, &params, changed);
51 }
52
53 return rc;
54}
55
32bad7e3 56static int
57mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
58{
59d19cd7 59 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
863e88f2 60 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
32bad7e3 61 struct sockaddr_ieee802154 *sa =
62 (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
63 int err = -ENOIOCTLCMD;
64
4a669f7d 65 rtnl_lock();
32bad7e3 66
67 switch (cmd) {
68 case SIOCGIFADDR:
b70ab2e8
PB
69 {
70 u16 pan_id, short_addr;
71
863e88f2
AA
72 pan_id = le16_to_cpu(wpan_dev->pan_id);
73 short_addr = le16_to_cpu(wpan_dev->short_addr);
b70ab2e8
PB
74 if (pan_id == IEEE802154_PANID_BROADCAST ||
75 short_addr == IEEE802154_ADDR_BROADCAST) {
32bad7e3 76 err = -EADDRNOTAVAIL;
77 break;
78 }
79
80 sa->family = AF_IEEE802154;
81 sa->addr.addr_type = IEEE802154_ADDR_SHORT;
b70ab2e8
PB
82 sa->addr.pan_id = pan_id;
83 sa->addr.short_addr = short_addr;
32bad7e3 84
85 err = 0;
86 break;
b70ab2e8 87 }
32bad7e3 88 case SIOCSIFADDR:
f7cb96f1 89 if (netif_running(dev)) {
4a669f7d 90 rtnl_unlock();
f7cb96f1
AA
91 return -EBUSY;
92 }
93
32bad7e3 94 dev_warn(&dev->dev,
9b13494c 95 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
32bad7e3 96 if (sa->family != AF_IEEE802154 ||
97 sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
98 sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
99 sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
100 sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
101 err = -EINVAL;
102 break;
103 }
104
863e88f2
AA
105 wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
106 wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
32bad7e3 107
9b0bb4a8 108 err = mac802154_wpan_update_llsec(dev);
32bad7e3 109 break;
110 }
111
4a669f7d 112 rtnl_unlock();
32bad7e3 113 return err;
114}
115
116static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
117{
776e59de 118 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
32bad7e3 119 struct sockaddr *addr = p;
ea7053c1 120 __le64 extended_addr;
32bad7e3 121
122 if (netif_running(dev))
123 return -EBUSY;
124
705cbbbe 125 ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
ea7053c1
AA
126 if (!ieee802154_is_valid_extended_addr(extended_addr))
127 return -EINVAL;
128
32bad7e3 129 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
863e88f2 130 sdata->wpan_dev.extended_addr = extended_addr;
776e59de 131
9b0bb4a8 132 return mac802154_wpan_update_llsec(dev);
32bad7e3 133}
134
19ec690a
AA
135static int mac802154_slave_open(struct net_device *dev)
136{
137 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
19ec690a
AA
138 struct ieee802154_local *local = sdata->local;
139 int res = 0;
140
141 ASSERT_RTNL();
142
0ea3da64 143 set_bit(SDATA_STATE_RUNNING, &sdata->state);
19ec690a 144
74457641 145 if (!local->open_count) {
59cb300f 146 res = drv_start(local);
19ec690a
AA
147 WARN_ON(res);
148 if (res)
149 goto err;
150 }
151
74457641 152 local->open_count++;
19ec690a
AA
153 netif_start_queue(dev);
154 return 0;
155err:
0ea3da64
AA
156 /* might already be clear but that doesn't matter */
157 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
19ec690a
AA
158
159 return res;
160}
161
bd37a78d
AA
162static int
163ieee802154_check_mac_settings(struct ieee802154_local *local,
164 struct wpan_dev *wpan_dev,
165 struct wpan_dev *nwpan_dev)
166{
167 ASSERT_RTNL();
168
169 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
170 if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode)
171 return -EBUSY;
172 }
173
174 if (local->hw.flags & IEEE802154_HW_AFILT) {
8bf9538a
AA
175 if (wpan_dev->pan_id != nwpan_dev->pan_id ||
176 wpan_dev->short_addr != nwpan_dev->short_addr ||
177 wpan_dev->extended_addr != nwpan_dev->extended_addr)
bd37a78d
AA
178 return -EBUSY;
179 }
180
181 if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
8bf9538a
AA
182 if (wpan_dev->min_be != nwpan_dev->min_be ||
183 wpan_dev->max_be != nwpan_dev->max_be ||
184 wpan_dev->csma_retries != nwpan_dev->csma_retries)
bd37a78d
AA
185 return -EBUSY;
186 }
187
188 if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
189 if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
190 return -EBUSY;
191 }
192
193 if (local->hw.flags & IEEE802154_HW_LBT) {
194 if (wpan_dev->lbt != nwpan_dev->lbt)
195 return -EBUSY;
196 }
197
198 return 0;
199}
200
201static int
202ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
203 enum nl802154_iftype iftype)
204{
205 struct ieee802154_local *local = sdata->local;
206 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
207 struct ieee802154_sub_if_data *nsdata;
208
209 /* we hold the RTNL here so can safely walk the list */
210 list_for_each_entry(nsdata, &local->interfaces, list) {
211 if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
212 int ret;
213
cd1c5665
AA
214 /* TODO currently we don't support multiple node types
215 * we need to run skb_clone at rx path. Check if there
216 * exist really an use case if we need to support
217 * multiple node types at the same time.
218 */
219 if (sdata->vif.type == NL802154_IFTYPE_NODE &&
220 nsdata->vif.type == NL802154_IFTYPE_NODE)
221 return -EBUSY;
222
bd37a78d
AA
223 /* check all phy mac sublayer settings are the same.
224 * We have only one phy, different values makes trouble.
225 */
226 ret = ieee802154_check_mac_settings(local, wpan_dev,
227 &nsdata->wpan_dev);
228 if (ret < 0)
229 return ret;
230 }
231 }
232
233 return 0;
234}
235
6ef0023a 236static int mac802154_wpan_open(struct net_device *dev)
e462ded6
PB
237{
238 int rc;
59d19cd7 239 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
59cb300f 240 struct ieee802154_local *local = sdata->local;
863e88f2 241 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
e462ded6 242
bd37a78d
AA
243 rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type);
244 if (rc < 0)
245 return rc;
246
e462ded6
PB
247 rc = mac802154_slave_open(dev);
248 if (rc < 0)
249 return rc;
250
38130c31 251 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
863e88f2
AA
252 rc = drv_set_promiscuous_mode(local,
253 wpan_dev->promiscuous_mode);
38130c31
AA
254 if (rc < 0)
255 goto out;
256 }
257
776e59de 258 if (local->hw.flags & IEEE802154_HW_AFILT) {
863e88f2 259 rc = drv_set_pan_id(local, wpan_dev->pan_id);
50c79075
AA
260 if (rc < 0)
261 goto out;
262
863e88f2 263 rc = drv_set_extended_addr(local, wpan_dev->extended_addr);
776e59de
AA
264 if (rc < 0)
265 goto out;
78b4bad1 266
863e88f2 267 rc = drv_set_short_addr(local, wpan_dev->short_addr);
78b4bad1
AA
268 if (rc < 0)
269 goto out;
776e59de
AA
270 }
271
a543c598 272 if (local->hw.flags & IEEE802154_HW_LBT) {
5fb3f026 273 rc = drv_set_lbt_mode(local, wpan_dev->lbt);
e462ded6
PB
274 if (rc < 0)
275 goto out;
276 }
277
a543c598 278 if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
5fb3f026
AA
279 rc = drv_set_csma_params(local, wpan_dev->min_be,
280 wpan_dev->max_be,
281 wpan_dev->csma_retries);
e462ded6
PB
282 if (rc < 0)
283 goto out;
284 }
285
a543c598 286 if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
5fb3f026 287 rc = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
e462ded6
PB
288 if (rc < 0)
289 goto out;
290 }
291
e462ded6 292out:
e462ded6
PB
293 return rc;
294}
295
19ec690a
AA
296static int mac802154_slave_close(struct net_device *dev)
297{
298 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
299 struct ieee802154_local *local = sdata->local;
300
301 ASSERT_RTNL();
302
61f2dcba
AA
303 hrtimer_cancel(&local->ifs_timer);
304
19ec690a 305 netif_stop_queue(dev);
74457641 306 local->open_count--;
19ec690a 307
0ea3da64 308 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
19ec690a 309
74457641 310 if (!local->open_count)
59cb300f 311 drv_stop(local);
19ec690a
AA
312
313 return 0;
314}
315
036562f9 316static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
f30be4d5
PB
317 struct ieee802154_hdr *hdr,
318 const struct ieee802154_mac_cb *cb)
319{
320 struct ieee802154_llsec_params params;
321 u8 level;
322
036562f9 323 mac802154_llsec_get_params(&sdata->sec, &params);
f30be4d5
PB
324
325 if (!params.enabled && cb->secen_override && cb->secen)
326 return -EINVAL;
327 if (!params.enabled ||
328 (cb->secen_override && !cb->secen) ||
329 !params.out_level)
330 return 0;
331 if (cb->seclevel_override && !cb->seclevel)
332 return -EINVAL;
333
334 level = cb->seclevel_override ? cb->seclevel : params.out_level;
335
336 hdr->fc.security_enabled = 1;
337 hdr->sec.level = level;
338 hdr->sec.key_id_mode = params.out_key.mode;
339 if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
340 hdr->sec.short_src = params.out_key.short_source;
341 else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
342 hdr->sec.extended_src = params.out_key.extended_source;
343 hdr->sec.key_id = params.out_key.id;
344
345 return 0;
346}
347
32bad7e3 348static int mac802154_header_create(struct sk_buff *skb,
349 struct net_device *dev,
350 unsigned short type,
e6278d92
PB
351 const void *daddr,
352 const void *saddr,
32bad7e3 353 unsigned len)
354{
e6278d92 355 struct ieee802154_hdr hdr;
59d19cd7 356 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
863e88f2 357 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
32edc40a 358 struct ieee802154_mac_cb *cb = mac_cb(skb);
e6278d92 359 int hlen;
32bad7e3 360
361 if (!daddr)
362 return -EINVAL;
363
e6278d92 364 memset(&hdr.fc, 0, sizeof(hdr.fc));
32edc40a
PB
365 hdr.fc.type = cb->type;
366 hdr.fc.security_enabled = cb->secen;
367 hdr.fc.ack_request = cb->ackreq;
344f8c11 368 hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
32bad7e3 369
036562f9 370 if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
f30be4d5
PB
371 return -EINVAL;
372
32bad7e3 373 if (!saddr) {
863e88f2
AA
374 if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
375 wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
376 wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
e6278d92 377 hdr.source.mode = IEEE802154_ADDR_LONG;
863e88f2 378 hdr.source.extended_addr = wpan_dev->extended_addr;
32bad7e3 379 } else {
e6278d92 380 hdr.source.mode = IEEE802154_ADDR_SHORT;
863e88f2 381 hdr.source.short_addr = wpan_dev->short_addr;
32bad7e3 382 }
383
863e88f2 384 hdr.source.pan_id = wpan_dev->pan_id;
e6278d92
PB
385 } else {
386 hdr.source = *(const struct ieee802154_addr *)saddr;
32bad7e3 387 }
388
e6278d92 389 hdr.dest = *(const struct ieee802154_addr *)daddr;
32bad7e3 390
e6278d92
PB
391 hlen = ieee802154_hdr_push(skb, &hdr);
392 if (hlen < 0)
393 return -EINVAL;
32bad7e3 394
3e69162e 395 skb_reset_mac_header(skb);
e6278d92 396 skb->mac_len = hlen;
32bad7e3 397
8c84296f 398 if (len > ieee802154_max_payload(&hdr))
d1d7358e
PB
399 return -EMSGSIZE;
400
e6278d92 401 return hlen;
32bad7e3 402}
403
404static int
405mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
406{
e6278d92
PB
407 struct ieee802154_hdr hdr;
408 struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
32bad7e3 409
e6278d92
PB
410 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
411 pr_debug("malformed packet\n");
412 return 0;
32bad7e3 413 }
414
e6278d92
PB
415 *addr = hdr.source;
416 return sizeof(*addr);
32bad7e3 417}
418
32bad7e3 419static struct header_ops mac802154_header_ops = {
420 .create = mac802154_header_create,
421 .parse = mac802154_header_parse,
422};
423
424static const struct net_device_ops mac802154_wpan_ops = {
e462ded6 425 .ndo_open = mac802154_wpan_open,
32bad7e3 426 .ndo_stop = mac802154_slave_close,
e5e584fc 427 .ndo_start_xmit = ieee802154_subif_start_xmit,
32bad7e3 428 .ndo_do_ioctl = mac802154_wpan_ioctl,
429 .ndo_set_mac_address = mac802154_wpan_mac_addr,
430};
431
b9ff77e5 432static const struct net_device_ops mac802154_monitor_ops = {
38130c31 433 .ndo_open = mac802154_wpan_open,
b9ff77e5
AA
434 .ndo_stop = mac802154_slave_close,
435 .ndo_start_xmit = ieee802154_monitor_start_xmit,
436};
437
f30be4d5
PB
438static void mac802154_wpan_free(struct net_device *dev)
439{
59d19cd7 440 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
f30be4d5 441
036562f9 442 mac802154_llsec_destroy(&sdata->sec);
f30be4d5
PB
443
444 free_netdev(dev);
445}
446
d5ae67ba 447static void ieee802154_if_setup(struct net_device *dev)
32bad7e3 448{
e57a8946
AA
449 dev->addr_len = IEEE802154_EXTENDED_ADDR_LEN;
450 memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
32bad7e3 451
452 dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
f30be4d5 453 dev->needed_tailroom = 2 + 16; /* FCS + MIC */
32bad7e3 454 dev->mtu = IEEE802154_MTU;
e937f583 455 dev->tx_queue_len = 300;
32bad7e3 456 dev->flags = IFF_NOARP | IFF_BROADCAST;
d5ae67ba 457}
32bad7e3 458
d5ae67ba 459static int
944742a3
AA
460ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
461 enum nl802154_iftype type)
d5ae67ba 462{
863e88f2 463 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
344f8c11 464 u8 tmp;
863e88f2 465
d5ae67ba 466 /* set some type-dependent values */
7c118c1a 467 sdata->vif.type = type;
190ac1ca 468 sdata->wpan_dev.iftype = type;
32bad7e3 469
344f8c11
AA
470 get_random_bytes(&tmp, sizeof(tmp));
471 atomic_set(&wpan_dev->bsn, tmp);
472 get_random_bytes(&tmp, sizeof(tmp));
473 atomic_set(&wpan_dev->dsn, tmp);
32bad7e3 474
e462ded6 475 /* defaults per 802.15.4-2011 */
5fb3f026
AA
476 wpan_dev->min_be = 3;
477 wpan_dev->max_be = 5;
478 wpan_dev->csma_retries = 4;
036562f9 479 /* for compatibility, actual default is 3 */
5fb3f026 480 wpan_dev->frame_retries = -1;
e462ded6 481
863e88f2
AA
482 wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
483 wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
f30be4d5 484
d5ae67ba 485 switch (type) {
944742a3 486 case NL802154_IFTYPE_NODE:
b03c9ccc
AA
487 ieee802154_be64_to_le64(&wpan_dev->extended_addr,
488 sdata->dev->dev_addr);
489
d5ae67ba
AA
490 sdata->dev->header_ops = &mac802154_header_ops;
491 sdata->dev->destructor = mac802154_wpan_free;
492 sdata->dev->netdev_ops = &mac802154_wpan_ops;
493 sdata->dev->ml_priv = &mac802154_mlme_wpan;
863e88f2 494 wpan_dev->promiscuous_mode = false;
986a8abf 495
d5ae67ba 496 mutex_init(&sdata->sec_mtx);
986a8abf 497
d5ae67ba
AA
498 mac802154_llsec_init(&sdata->sec);
499 break;
944742a3 500 case NL802154_IFTYPE_MONITOR:
d5ae67ba
AA
501 sdata->dev->destructor = free_netdev;
502 sdata->dev->netdev_ops = &mac802154_monitor_ops;
863e88f2 503 wpan_dev->promiscuous_mode = true;
d5ae67ba
AA
504 break;
505 default:
506 BUG();
507 }
986a8abf
AA
508
509 return 0;
510}
511
512struct net_device *
513ieee802154_if_add(struct ieee802154_local *local, const char *name,
5b4a1039
VB
514 unsigned char name_assign_type, enum nl802154_iftype type,
515 __le64 extended_addr)
986a8abf 516{
d5ae67ba
AA
517 struct net_device *ndev = NULL;
518 struct ieee802154_sub_if_data *sdata = NULL;
519 int ret = -ENOMEM;
520
521 ASSERT_RTNL();
522
7c118c1a 523 ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
5b4a1039 524 name_assign_type, ieee802154_if_setup);
d5ae67ba
AA
525 if (!ndev)
526 return ERR_PTR(-ENOMEM);
527
528 ndev->needed_headroom = local->hw.extra_tx_headroom;
529
530 ret = dev_alloc_name(ndev, ndev->name);
531 if (ret < 0)
532 goto err;
986a8abf 533
0e57547e
AA
534 ieee802154_le64_to_be64(ndev->perm_addr,
535 &local->hw.phy->perm_extended_addr);
986a8abf 536 switch (type) {
944742a3 537 case NL802154_IFTYPE_NODE:
d5ae67ba 538 ndev->type = ARPHRD_IEEE802154;
0e57547e
AA
539 if (ieee802154_is_valid_extended_addr(extended_addr))
540 ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr);
541 else
542 memcpy(ndev->dev_addr, ndev->perm_addr,
543 IEEE802154_EXTENDED_ADDR_LEN);
986a8abf 544 break;
944742a3 545 case NL802154_IFTYPE_MONITOR:
d5ae67ba 546 ndev->type = ARPHRD_IEEE802154_MONITOR;
986a8abf 547 break;
d5ae67ba
AA
548 default:
549 ret = -EINVAL;
550 goto err;
986a8abf 551 }
d5ae67ba
AA
552
553 /* TODO check this */
554 SET_NETDEV_DEV(ndev, &local->phy->dev);
555 sdata = netdev_priv(ndev);
556 ndev->ieee802154_ptr = &sdata->wpan_dev;
557 memcpy(sdata->name, ndev->name, IFNAMSIZ);
558 sdata->dev = ndev;
559 sdata->wpan_dev.wpan_phy = local->hw.phy;
560 sdata->local = local;
561
562 /* setup type-dependent data */
563 ret = ieee802154_setup_sdata(sdata, type);
564 if (ret)
986a8abf
AA
565 goto err;
566
473f3766
VB
567 ret = register_netdevice(ndev);
568 if (ret < 0)
569 goto err;
d5ae67ba
AA
570
571 mutex_lock(&local->iflist_mtx);
572 list_add_tail_rcu(&sdata->list, &local->interfaces);
573 mutex_unlock(&local->iflist_mtx);
986a8abf 574
d5ae67ba 575 return ndev;
986a8abf 576
986a8abf 577err:
d5ae67ba
AA
578 free_netdev(ndev);
579 return ERR_PTR(ret);
986a8abf
AA
580}
581
b210b187
AA
582void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
583{
584 ASSERT_RTNL();
585
586 mutex_lock(&sdata->local->iflist_mtx);
587 list_del_rcu(&sdata->list);
588 mutex_unlock(&sdata->local->iflist_mtx);
589
590 synchronize_rcu();
591 unregister_netdevice(sdata->dev);
592}
592dfbfc
AA
593
594void ieee802154_remove_interfaces(struct ieee802154_local *local)
595{
d14e1c71 596 struct ieee802154_sub_if_data *sdata, *tmp;
592dfbfc 597
2789e629 598 mutex_lock(&local->iflist_mtx);
d14e1c71 599 list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
592dfbfc 600 list_del(&sdata->list);
592dfbfc
AA
601
602 unregister_netdevice(sdata->dev);
603 }
2789e629 604 mutex_unlock(&local->iflist_mtx);
592dfbfc 605}
be4fd8e5
AA
606
607static int netdev_notify(struct notifier_block *nb,
608 unsigned long state, void *ptr)
609{
610 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
611 struct ieee802154_sub_if_data *sdata;
612
613 if (state != NETDEV_CHANGENAME)
614 return NOTIFY_DONE;
615
616 if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
617 return NOTIFY_DONE;
618
619 if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
620 return NOTIFY_DONE;
621
622 sdata = IEEE802154_DEV_TO_SUB_IF(dev);
623 memcpy(sdata->name, dev->name, IFNAMSIZ);
624
625 return NOTIFY_OK;
626}
627
628static struct notifier_block mac802154_netdev_notifier = {
629 .notifier_call = netdev_notify,
630};
631
632int ieee802154_iface_init(void)
633{
634 return register_netdevice_notifier(&mac802154_netdev_notifier);
635}
636
637void ieee802154_iface_exit(void)
638{
639 unregister_netdevice_notifier(&mac802154_netdev_notifier);
640}