iface.c 15.9 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 154
		WARN_ON(res);
		if (res)
			goto err;
	}

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

	return res;
}

165 166 167 168 169 170 171 172 173 174 175 176 177
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) {
178 179 180
		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)
181 182 183 184
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
185 186 187
		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)
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 216
			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;

217 218 219 220 221 222 223 224 225
			/* 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.
			 */
			if (sdata->vif.type == NL802154_IFTYPE_NODE &&
			    nsdata->vif.type == NL802154_IFTYPE_NODE)
				return -EBUSY;

226 227 228 229 230 231 232 233 234 235 236 237 238
			/* 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;
}

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

246 247 248 249
	rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type);
	if (rc < 0)
		return rc;

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

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

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

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

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

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

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

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

out:
	return rc;
}

299 300 301 302 303 304 305
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();

306 307
	hrtimer_cancel(&local->ifs_timer);

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

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

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

	return 0;
}

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

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

	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;
}

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

	if (!daddr)
		return -EINVAL;

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

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

376
	if (!saddr) {
377 378 379
		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)) {
380
			hdr.source.mode = IEEE802154_ADDR_LONG;
381
			hdr.source.extended_addr = wpan_dev->extended_addr;
382
		} else {
383
			hdr.source.mode = IEEE802154_ADDR_SHORT;
384
			hdr.source.short_addr = wpan_dev->short_addr;
385 386
		}

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

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

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

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

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

404
	return hlen;
405 406 407 408 409
}

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

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

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

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

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

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

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

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

	free_netdev(dev);
}

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

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

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

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

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

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

485 486
	wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
	wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
487

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

493 494 495 496
		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;
497
		wpan_dev->promiscuous_mode = false;
498

499
		mutex_init(&sdata->sec_mtx);
500

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

	return 0;
}

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

	ASSERT_RTNL();

526
	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
527
			    name_assign_type, ieee802154_if_setup);
528 529 530 531 532 533 534 535
	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;
536

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

	/* 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)
568 569
		goto err;

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

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

578
	return ndev;
579 580

err:
581 582
	free_netdev(ndev);
	return ERR_PTR(ret);
583 584
}

585 586 587 588 589 590 591 592 593 594 595
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);
}
596 597 598

void ieee802154_remove_interfaces(struct ieee802154_local *local)
{
599
	struct ieee802154_sub_if_data *sdata, *tmp;
600

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

		unregister_netdevice(sdata->dev);
	}
607
	mutex_unlock(&local->iflist_mtx);
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 642 643

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);
}