iface.c 15.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright 2007-2012 Siemens AG
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Written by:
 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 * Sergey Lapin <slapin@ossfans.org>
 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 */

#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/if_arp.h>
23
#include <linux/ieee802154.h>
24

25
#include <net/nl802154.h>
26 27
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
28
#include <net/cfg802154.h>
29

30
#include "ieee802154_i.h"
31
#include "driver-ops.h"
32

33 34
static int mac802154_wpan_update_llsec(struct net_device *dev)
{
35
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
36
	struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
37
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
38 39 40 41 42 43
	int rc = 0;

	if (ops->llsec) {
		struct ieee802154_llsec_params params;
		int changed = 0;

44
		params.pan_id = wpan_dev->pan_id;
45 46
		changed |= IEEE802154_LLSEC_PARAM_PAN_ID;

47
		params.hwaddr = wpan_dev->extended_addr;
48 49 50 51 52 53 54 55
		changed |= IEEE802154_LLSEC_PARAM_HWADDR;

		rc = ops->llsec->set_params(dev, &params, changed);
	}

	return rc;
}

56 57 58
static int
mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
59
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
60
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
61 62 63 64
	struct sockaddr_ieee802154 *sa =
		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
	int err = -ENOIOCTLCMD;

65 66 67
	if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR)
		return err;

68
	rtnl_lock();
69 70 71

	switch (cmd) {
	case SIOCGIFADDR:
72 73 74
	{
		u16 pan_id, short_addr;

75 76
		pan_id = le16_to_cpu(wpan_dev->pan_id);
		short_addr = le16_to_cpu(wpan_dev->short_addr);
77 78
		if (pan_id == IEEE802154_PANID_BROADCAST ||
		    short_addr == IEEE802154_ADDR_BROADCAST) {
79 80 81 82 83 84
			err = -EADDRNOTAVAIL;
			break;
		}

		sa->family = AF_IEEE802154;
		sa->addr.addr_type = IEEE802154_ADDR_SHORT;
85 86
		sa->addr.pan_id = pan_id;
		sa->addr.short_addr = short_addr;
87 88 89

		err = 0;
		break;
90
	}
91
	case SIOCSIFADDR:
92
		if (netif_running(dev)) {
93
			rtnl_unlock();
94 95 96
			return -EBUSY;
		}

97
		dev_warn(&dev->dev,
M
Masanari Iida 已提交
98
			 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
99 100 101 102 103 104 105 106 107
		if (sa->family != AF_IEEE802154 ||
		    sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
		    sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
		    sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
		    sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
			err = -EINVAL;
			break;
		}

108 109
		wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
		wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
110

111
		err = mac802154_wpan_update_llsec(dev);
112 113 114
		break;
	}

115
	rtnl_unlock();
116 117 118 119 120
	return err;
}

static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
{
121
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
122
	struct sockaddr *addr = p;
123
	__le64 extended_addr;
124 125 126 127

	if (netif_running(dev))
		return -EBUSY;

128
	ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
129
	if (!ieee802154_is_valid_extended_unicast_addr(extended_addr))
130 131
		return -EINVAL;

132
	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
133
	sdata->wpan_dev.extended_addr = extended_addr;
134

135
	return mac802154_wpan_update_llsec(dev);
136 137
}

138 139 140 141 142 143 144 145
static int mac802154_slave_open(struct net_device *dev)
{
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	struct ieee802154_local *local = sdata->local;
	int res = 0;

	ASSERT_RTNL();

146
	set_bit(SDATA_STATE_RUNNING, &sdata->state);
147

148
	if (!local->open_count) {
149
		res = drv_start(local);
150 151 152 153
		if (res)
			goto err;
	}

154
	local->open_count++;
155 156 157
	netif_start_queue(dev);
	return 0;
err:
158 159
	/* might already be clear but that doesn't matter */
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
160 161 162 163

	return res;
}

164 165 166 167 168 169 170 171 172 173 174 175 176
static int
ieee802154_check_mac_settings(struct ieee802154_local *local,
			      struct wpan_dev *wpan_dev,
			      struct wpan_dev *nwpan_dev)
{
	ASSERT_RTNL();

	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
		if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_AFILT) {
177 178 179
		if (wpan_dev->pan_id != nwpan_dev->pan_id ||
		    wpan_dev->short_addr != nwpan_dev->short_addr ||
		    wpan_dev->extended_addr != nwpan_dev->extended_addr)
180 181 182 183
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
184 185 186
		if (wpan_dev->min_be != nwpan_dev->min_be ||
		    wpan_dev->max_be != nwpan_dev->max_be ||
		    wpan_dev->csma_retries != nwpan_dev->csma_retries)
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
		if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_LBT) {
		if (wpan_dev->lbt != nwpan_dev->lbt)
			return -EBUSY;
	}

	return 0;
}

static int
ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
				  enum nl802154_iftype iftype)
{
	struct ieee802154_local *local = sdata->local;
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
	struct ieee802154_sub_if_data *nsdata;

	/* we hold the RTNL here so can safely walk the list */
	list_for_each_entry(nsdata, &local->interfaces, list) {
		if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
			int ret;

216 217 218 219 220
			/* TODO currently we don't support multiple node types
			 * we need to run skb_clone at rx path. Check if there
			 * exist really an use case if we need to support
			 * multiple node types at the same time.
			 */
221 222
			if (wpan_dev->iftype == NL802154_IFTYPE_NODE &&
			    nsdata->wpan_dev.iftype == NL802154_IFTYPE_NODE)
223 224
				return -EBUSY;

225 226 227 228 229 230 231 232 233 234 235 236 237
			/* check all phy mac sublayer settings are the same.
			 * We have only one phy, different values makes trouble.
			 */
			ret = ieee802154_check_mac_settings(local, wpan_dev,
							    &nsdata->wpan_dev);
			if (ret < 0)
				return ret;
		}
	}

	return 0;
}

238
static int mac802154_wpan_open(struct net_device *dev)
239 240
{
	int rc;
241
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
242
	struct ieee802154_local *local = sdata->local;
243
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
244

245
	rc = ieee802154_check_concurrent_iface(sdata, wpan_dev->iftype);
246 247 248
	if (rc < 0)
		return rc;

249 250 251 252
	rc = mac802154_slave_open(dev);
	if (rc < 0)
		return rc;

253
	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
254 255
		rc = drv_set_promiscuous_mode(local,
					      wpan_dev->promiscuous_mode);
256 257 258 259
		if (rc < 0)
			goto out;
	}

260
	if (local->hw.flags & IEEE802154_HW_AFILT) {
261
		rc = drv_set_pan_id(local, wpan_dev->pan_id);
262 263 264
		if (rc < 0)
			goto out;

265
		rc = drv_set_extended_addr(local, wpan_dev->extended_addr);
266 267
		if (rc < 0)
			goto out;
268

269
		rc = drv_set_short_addr(local, wpan_dev->short_addr);
270 271
		if (rc < 0)
			goto out;
272 273
	}

274
	if (local->hw.flags & IEEE802154_HW_LBT) {
275
		rc = drv_set_lbt_mode(local, wpan_dev->lbt);
276 277 278 279
		if (rc < 0)
			goto out;
	}

280
	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
281 282 283
		rc = drv_set_csma_params(local, wpan_dev->min_be,
					 wpan_dev->max_be,
					 wpan_dev->csma_retries);
284 285 286 287
		if (rc < 0)
			goto out;
	}

288
	if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
289
		rc = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
290 291 292 293 294 295 296 297
		if (rc < 0)
			goto out;
	}

out:
	return rc;
}

298 299 300 301 302 303 304
static int mac802154_slave_close(struct net_device *dev)
{
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	struct ieee802154_local *local = sdata->local;

	ASSERT_RTNL();

305 306
	hrtimer_cancel(&local->ifs_timer);

307
	netif_stop_queue(dev);
308
	local->open_count--;
309

310
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
311

312
	if (!local->open_count)
313
		drv_stop(local);
314 315 316 317

	return 0;
}

318
static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
319 320 321 322 323 324
					 struct ieee802154_hdr *hdr,
					 const struct ieee802154_mac_cb *cb)
{
	struct ieee802154_llsec_params params;
	u8 level;

325
	mac802154_llsec_get_params(&sdata->sec, &params);
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

	if (!params.enabled && cb->secen_override && cb->secen)
		return -EINVAL;
	if (!params.enabled ||
	    (cb->secen_override && !cb->secen) ||
	    !params.out_level)
		return 0;
	if (cb->seclevel_override && !cb->seclevel)
		return -EINVAL;

	level = cb->seclevel_override ? cb->seclevel : params.out_level;

	hdr->fc.security_enabled = 1;
	hdr->sec.level = level;
	hdr->sec.key_id_mode = params.out_key.mode;
	if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
		hdr->sec.short_src = params.out_key.short_source;
	else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
		hdr->sec.extended_src = params.out_key.extended_source;
	hdr->sec.key_id = params.out_key.id;

	return 0;
}

350 351 352
static int mac802154_header_create(struct sk_buff *skb,
				   struct net_device *dev,
				   unsigned short type,
353 354
				   const void *daddr,
				   const void *saddr,
355 356
				   unsigned len)
{
357
	struct ieee802154_hdr hdr;
358
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
359
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
360
	struct ieee802154_mac_cb *cb = mac_cb(skb);
361
	int hlen;
362 363 364 365

	if (!daddr)
		return -EINVAL;

366
	memset(&hdr.fc, 0, sizeof(hdr.fc));
367 368 369
	hdr.fc.type = cb->type;
	hdr.fc.security_enabled = cb->secen;
	hdr.fc.ack_request = cb->ackreq;
370
	hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
371

372
	if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
373 374
		return -EINVAL;

375
	if (!saddr) {
376 377 378
		if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
		    wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
		    wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
379
			hdr.source.mode = IEEE802154_ADDR_LONG;
380
			hdr.source.extended_addr = wpan_dev->extended_addr;
381
		} else {
382
			hdr.source.mode = IEEE802154_ADDR_SHORT;
383
			hdr.source.short_addr = wpan_dev->short_addr;
384 385
		}

386
		hdr.source.pan_id = wpan_dev->pan_id;
387 388
	} else {
		hdr.source = *(const struct ieee802154_addr *)saddr;
389 390
	}

391
	hdr.dest = *(const struct ieee802154_addr *)daddr;
392

393 394 395
	hlen = ieee802154_hdr_push(skb, &hdr);
	if (hlen < 0)
		return -EINVAL;
396

397
	skb_reset_mac_header(skb);
398
	skb->mac_len = hlen;
399

400
	if (len > ieee802154_max_payload(&hdr))
401 402
		return -EMSGSIZE;

403
	return hlen;
404 405 406 407 408
}

static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
409 410
	struct ieee802154_hdr hdr;
	struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
411

412 413 414
	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
		pr_debug("malformed packet\n");
		return 0;
415 416
	}

417 418
	*addr = hdr.source;
	return sizeof(*addr);
419 420 421 422 423 424 425 426
}

static struct header_ops mac802154_header_ops = {
	.create		= mac802154_header_create,
	.parse		= mac802154_header_parse,
};

static const struct net_device_ops mac802154_wpan_ops = {
427
	.ndo_open		= mac802154_wpan_open,
428
	.ndo_stop		= mac802154_slave_close,
429
	.ndo_start_xmit		= ieee802154_subif_start_xmit,
430 431 432 433
	.ndo_do_ioctl		= mac802154_wpan_ioctl,
	.ndo_set_mac_address	= mac802154_wpan_mac_addr,
};

434
static const struct net_device_ops mac802154_monitor_ops = {
435
	.ndo_open		= mac802154_wpan_open,
436 437 438 439
	.ndo_stop		= mac802154_slave_close,
	.ndo_start_xmit		= ieee802154_monitor_start_xmit,
};

440 441
static void mac802154_wpan_free(struct net_device *dev)
{
442
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
443

444
	mac802154_llsec_destroy(&sdata->sec);
445 446 447 448

	free_netdev(dev);
}

449
static void ieee802154_if_setup(struct net_device *dev)
450
{
451 452
	dev->addr_len		= IEEE802154_EXTENDED_ADDR_LEN;
	memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
453 454

	dev->hard_header_len	= MAC802154_FRAME_HARD_HEADER_LEN;
455
	dev->needed_tailroom	= 2 + 16; /* FCS + MIC */
456
	dev->mtu		= IEEE802154_MTU;
A
Alan Ott 已提交
457
	dev->tx_queue_len	= 300;
458
	dev->flags		= IFF_NOARP | IFF_BROADCAST;
459
}
460

461
static int
462 463
ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
		       enum nl802154_iftype type)
464
{
465
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
466
	u8 tmp;
467

468
	/* set some type-dependent values */
469
	sdata->wpan_dev.iftype = type;
470

471 472 473 474
	get_random_bytes(&tmp, sizeof(tmp));
	atomic_set(&wpan_dev->bsn, tmp);
	get_random_bytes(&tmp, sizeof(tmp));
	atomic_set(&wpan_dev->dsn, tmp);
475

476
	/* defaults per 802.15.4-2011 */
477 478 479
	wpan_dev->min_be = 3;
	wpan_dev->max_be = 5;
	wpan_dev->csma_retries = 4;
480
	/* for compatibility, actual default is 3 */
481
	wpan_dev->frame_retries = -1;
482

483 484
	wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
	wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
485

486
	switch (type) {
487
	case NL802154_IFTYPE_NODE:
488 489 490
		ieee802154_be64_to_le64(&wpan_dev->extended_addr,
					sdata->dev->dev_addr);

491 492 493 494
		sdata->dev->header_ops = &mac802154_header_ops;
		sdata->dev->destructor = mac802154_wpan_free;
		sdata->dev->netdev_ops = &mac802154_wpan_ops;
		sdata->dev->ml_priv = &mac802154_mlme_wpan;
495
		wpan_dev->promiscuous_mode = false;
496

497
		mutex_init(&sdata->sec_mtx);
498

499 500
		mac802154_llsec_init(&sdata->sec);
		break;
501
	case NL802154_IFTYPE_MONITOR:
502 503
		sdata->dev->destructor = free_netdev;
		sdata->dev->netdev_ops = &mac802154_monitor_ops;
504
		wpan_dev->promiscuous_mode = true;
505 506 507 508
		break;
	default:
		BUG();
	}
509 510 511 512 513 514

	return 0;
}

struct net_device *
ieee802154_if_add(struct ieee802154_local *local, const char *name,
515 516
		  unsigned char name_assign_type, enum nl802154_iftype type,
		  __le64 extended_addr)
517
{
518 519 520 521 522 523
	struct net_device *ndev = NULL;
	struct ieee802154_sub_if_data *sdata = NULL;
	int ret = -ENOMEM;

	ASSERT_RTNL();

524
	ndev = alloc_netdev(sizeof(*sdata), name,
525
			    name_assign_type, ieee802154_if_setup);
526 527 528 529 530 531 532 533
	if (!ndev)
		return ERR_PTR(-ENOMEM);

	ndev->needed_headroom = local->hw.extra_tx_headroom;

	ret = dev_alloc_name(ndev, ndev->name);
	if (ret < 0)
		goto err;
534

535 536
	ieee802154_le64_to_be64(ndev->perm_addr,
				&local->hw.phy->perm_extended_addr);
537
	switch (type) {
538
	case NL802154_IFTYPE_NODE:
539
		ndev->type = ARPHRD_IEEE802154;
540
		if (ieee802154_is_valid_extended_unicast_addr(extended_addr))
541 542 543 544
			ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr);
		else
			memcpy(ndev->dev_addr, ndev->perm_addr,
			       IEEE802154_EXTENDED_ADDR_LEN);
545
		break;
546
	case NL802154_IFTYPE_MONITOR:
547
		ndev->type = ARPHRD_IEEE802154_MONITOR;
548
		break;
549 550 551
	default:
		ret = -EINVAL;
		goto err;
552
	}
553 554 555 556 557 558 559 560 561 562 563 564 565

	/* TODO check this */
	SET_NETDEV_DEV(ndev, &local->phy->dev);
	sdata = netdev_priv(ndev);
	ndev->ieee802154_ptr = &sdata->wpan_dev;
	memcpy(sdata->name, ndev->name, IFNAMSIZ);
	sdata->dev = ndev;
	sdata->wpan_dev.wpan_phy = local->hw.phy;
	sdata->local = local;

	/* setup type-dependent data */
	ret = ieee802154_setup_sdata(sdata, type);
	if (ret)
566 567
		goto err;

568 569 570
	ret = register_netdevice(ndev);
	if (ret < 0)
		goto err;
571 572 573 574

	mutex_lock(&local->iflist_mtx);
	list_add_tail_rcu(&sdata->list, &local->interfaces);
	mutex_unlock(&local->iflist_mtx);
575

576
	return ndev;
577 578

err:
579 580
	free_netdev(ndev);
	return ERR_PTR(ret);
581 582
}

583 584 585 586 587 588 589 590 591 592 593
void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
{
	ASSERT_RTNL();

	mutex_lock(&sdata->local->iflist_mtx);
	list_del_rcu(&sdata->list);
	mutex_unlock(&sdata->local->iflist_mtx);

	synchronize_rcu();
	unregister_netdevice(sdata->dev);
}
594 595 596

void ieee802154_remove_interfaces(struct ieee802154_local *local)
{
597
	struct ieee802154_sub_if_data *sdata, *tmp;
598

599
	mutex_lock(&local->iflist_mtx);
600
	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
601 602 603 604
		list_del(&sdata->list);

		unregister_netdevice(sdata->dev);
	}
605
	mutex_unlock(&local->iflist_mtx);
606
}
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

static int netdev_notify(struct notifier_block *nb,
			 unsigned long state, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct ieee802154_sub_if_data *sdata;

	if (state != NETDEV_CHANGENAME)
		return NOTIFY_DONE;

	if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
		return NOTIFY_DONE;

	if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
		return NOTIFY_DONE;

	sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	memcpy(sdata->name, dev->name, IFNAMSIZ);

	return NOTIFY_OK;
}

static struct notifier_block mac802154_netdev_notifier = {
	.notifier_call = netdev_notify,
};

int ieee802154_iface_init(void)
{
	return register_netdevice_notifier(&mac802154_netdev_notifier);
}

void ieee802154_iface_exit(void)
{
	unregister_netdevice_notifier(&mac802154_netdev_notifier);
}