iface.c 14.3 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
	ASSERT_RTNL();

67
	spin_lock_bh(&sdata->mib_lock);
68 69 70

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

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

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

		err = 0;
		break;
89
	}
90
	case SIOCSIFADDR:
91 92 93 94 95
		if (netif_running(dev)) {
			spin_unlock_bh(&sdata->mib_lock);
			return -EBUSY;
		}

96
		dev_warn(&dev->dev,
M
Masanari Iida 已提交
97
			 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
98 99 100 101 102 103 104 105 106
		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;
		}

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

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

114
	spin_unlock_bh(&sdata->mib_lock);
115 116 117 118 119
	return err;
}

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

	if (netif_running(dev))
		return -EBUSY;

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

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

134
	return mac802154_wpan_update_llsec(dev);
135 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_sub_if_data *subif;
	struct ieee802154_local *local = sdata->local;
	int res = 0;

	ASSERT_RTNL();

146
	if (sdata->vif.type == NL802154_IFTYPE_NODE) {
147 148
		mutex_lock(&sdata->local->iflist_mtx);
		list_for_each_entry(subif, &sdata->local->interfaces, list) {
149 150
			if (subif != sdata &&
			    subif->vif.type == sdata->vif.type &&
151
			    ieee802154_sdata_running(subif)) {
152 153 154 155 156 157 158
				mutex_unlock(&sdata->local->iflist_mtx);
				return -EBUSY;
			}
		}
		mutex_unlock(&sdata->local->iflist_mtx);
	}

159
	set_bit(SDATA_STATE_RUNNING, &sdata->state);
160

161
	if (!local->open_count) {
162
		res = drv_start(local);
163 164 165 166 167
		WARN_ON(res);
		if (res)
			goto err;
	}

168
	local->open_count++;
169 170 171
	netif_start_queue(dev);
	return 0;
err:
172 173
	/* might already be clear but that doesn't matter */
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
174 175 176 177

	return res;
}

178
static int mac802154_wpan_open(struct net_device *dev)
179 180
{
	int rc;
181
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
182
	struct ieee802154_local *local = sdata->local;
183
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
184
	struct wpan_phy *phy = sdata->local->phy;
185 186 187 188 189 190 191

	rc = mac802154_slave_open(dev);
	if (rc < 0)
		return rc;

	mutex_lock(&phy->pib_lock);

192
	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
193 194
		rc = drv_set_promiscuous_mode(local,
					      wpan_dev->promiscuous_mode);
195 196 197 198
		if (rc < 0)
			goto out;
	}

199
	if (local->hw.flags & IEEE802154_HW_AFILT) {
200
		rc = drv_set_pan_id(local, wpan_dev->pan_id);
201 202 203
		if (rc < 0)
			goto out;

204
		rc = drv_set_extended_addr(local, wpan_dev->extended_addr);
205 206
		if (rc < 0)
			goto out;
207

208
		rc = drv_set_short_addr(local, wpan_dev->short_addr);
209 210
		if (rc < 0)
			goto out;
211 212
	}

213
	if (local->hw.flags & IEEE802154_HW_LBT) {
214
		rc = drv_set_lbt_mode(local, wpan_dev->lbt);
215 216 217 218
		if (rc < 0)
			goto out;
	}

219
	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
220 221 222
		rc = drv_set_csma_params(local, wpan_dev->min_be,
					 wpan_dev->max_be,
					 wpan_dev->csma_retries);
223 224 225 226
		if (rc < 0)
			goto out;
	}

227
	if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
228
		rc = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
229 230 231 232 233 234 235 236 237 238 239 240
		if (rc < 0)
			goto out;
	}

	mutex_unlock(&phy->pib_lock);
	return 0;

out:
	mutex_unlock(&phy->pib_lock);
	return rc;
}

241 242 243 244 245 246 247
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();

248 249
	hrtimer_cancel(&local->ifs_timer);

250
	netif_stop_queue(dev);
251
	local->open_count--;
252

253
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
254

255
	if (!local->open_count)
256
		drv_stop(local);
257 258 259 260

	return 0;
}

261
static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
262 263 264 265 266 267
					 struct ieee802154_hdr *hdr,
					 const struct ieee802154_mac_cb *cb)
{
	struct ieee802154_llsec_params params;
	u8 level;

268
	mac802154_llsec_get_params(&sdata->sec, &params);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

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

293 294 295
static int mac802154_header_create(struct sk_buff *skb,
				   struct net_device *dev,
				   unsigned short type,
296 297
				   const void *daddr,
				   const void *saddr,
298 299
				   unsigned len)
{
300
	struct ieee802154_hdr hdr;
301
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
302
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
303
	struct ieee802154_mac_cb *cb = mac_cb(skb);
304
	int hlen;
305 306 307 308

	if (!daddr)
		return -EINVAL;

309
	memset(&hdr.fc, 0, sizeof(hdr.fc));
310 311 312 313
	hdr.fc.type = cb->type;
	hdr.fc.security_enabled = cb->secen;
	hdr.fc.ack_request = cb->ackreq;
	hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
314

315
	if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
316 317
		return -EINVAL;

318
	if (!saddr) {
319
		spin_lock_bh(&sdata->mib_lock);
320

321 322 323
		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)) {
324
			hdr.source.mode = IEEE802154_ADDR_LONG;
325
			hdr.source.extended_addr = wpan_dev->extended_addr;
326
		} else {
327
			hdr.source.mode = IEEE802154_ADDR_SHORT;
328
			hdr.source.short_addr = wpan_dev->short_addr;
329 330
		}

331
		hdr.source.pan_id = wpan_dev->pan_id;
332

333
		spin_unlock_bh(&sdata->mib_lock);
334 335
	} else {
		hdr.source = *(const struct ieee802154_addr *)saddr;
336 337
	}

338
	hdr.dest = *(const struct ieee802154_addr *)daddr;
339

340 341 342
	hlen = ieee802154_hdr_push(skb, &hdr);
	if (hlen < 0)
		return -EINVAL;
343

344
	skb_reset_mac_header(skb);
345
	skb->mac_len = hlen;
346

347
	if (len > ieee802154_max_payload(&hdr))
348 349
		return -EMSGSIZE;

350
	return hlen;
351 352 353 354 355
}

static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
356 357
	struct ieee802154_hdr hdr;
	struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
358

359 360 361
	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
		pr_debug("malformed packet\n");
		return 0;
362 363
	}

364 365
	*addr = hdr.source;
	return sizeof(*addr);
366 367 368 369 370 371 372 373
}

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

static const struct net_device_ops mac802154_wpan_ops = {
374
	.ndo_open		= mac802154_wpan_open,
375
	.ndo_stop		= mac802154_slave_close,
376
	.ndo_start_xmit		= ieee802154_subif_start_xmit,
377 378 379 380
	.ndo_do_ioctl		= mac802154_wpan_ioctl,
	.ndo_set_mac_address	= mac802154_wpan_mac_addr,
};

381
static const struct net_device_ops mac802154_monitor_ops = {
382
	.ndo_open		= mac802154_wpan_open,
383 384 385 386
	.ndo_stop		= mac802154_slave_close,
	.ndo_start_xmit		= ieee802154_monitor_start_xmit,
};

387 388
static void mac802154_wpan_free(struct net_device *dev)
{
389
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
390

391
	mac802154_llsec_destroy(&sdata->sec);
392 393 394 395

	free_netdev(dev);
}

396
static void ieee802154_if_setup(struct net_device *dev)
397
{
398 399
	dev->addr_len		= IEEE802154_EXTENDED_ADDR_LEN;
	memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
400 401

	dev->hard_header_len	= MAC802154_FRAME_HARD_HEADER_LEN;
402
	dev->needed_tailroom	= 2 + 16; /* FCS + MIC */
403
	dev->mtu		= IEEE802154_MTU;
A
Alan Ott 已提交
404
	dev->tx_queue_len	= 300;
405
	dev->flags		= IFF_NOARP | IFF_BROADCAST;
406
}
407

408
static int
409 410
ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
		       enum nl802154_iftype type)
411
{
412 413
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;

414
	/* set some type-dependent values */
415
	sdata->vif.type = type;
416
	sdata->wpan_dev.iftype = type;
417

418 419
	get_random_bytes(&wpan_dev->bsn, 1);
	get_random_bytes(&wpan_dev->dsn, 1);
420

421
	/* defaults per 802.15.4-2011 */
422 423 424
	wpan_dev->min_be = 3;
	wpan_dev->max_be = 5;
	wpan_dev->csma_retries = 4;
425
	/* for compatibility, actual default is 3 */
426
	wpan_dev->frame_retries = -1;
427

428 429
	wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
	wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
430

431
	switch (type) {
432
	case NL802154_IFTYPE_NODE:
433 434 435
		ieee802154_be64_to_le64(&wpan_dev->extended_addr,
					sdata->dev->dev_addr);

436 437 438 439
		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;
440
		wpan_dev->promiscuous_mode = false;
441

442 443
		spin_lock_init(&sdata->mib_lock);
		mutex_init(&sdata->sec_mtx);
444

445 446
		mac802154_llsec_init(&sdata->sec);
		break;
447
	case NL802154_IFTYPE_MONITOR:
448 449
		sdata->dev->destructor = free_netdev;
		sdata->dev->netdev_ops = &mac802154_monitor_ops;
450
		wpan_dev->promiscuous_mode = true;
451 452 453 454
		break;
	default:
		BUG();
	}
455 456 457 458 459 460

	return 0;
}

struct net_device *
ieee802154_if_add(struct ieee802154_local *local, const char *name,
461
		  enum nl802154_iftype type, __le64 extended_addr)
462
{
463 464 465 466 467 468
	struct net_device *ndev = NULL;
	struct ieee802154_sub_if_data *sdata = NULL;
	int ret = -ENOMEM;

	ASSERT_RTNL();

469 470
	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
			    NET_NAME_UNKNOWN, ieee802154_if_setup);
471 472 473 474 475 476 477 478
	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;
479

480 481
	ieee802154_le64_to_be64(ndev->perm_addr,
				&local->hw.phy->perm_extended_addr);
482
	switch (type) {
483
	case NL802154_IFTYPE_NODE:
484
		ndev->type = ARPHRD_IEEE802154;
485 486 487 488 489
		if (ieee802154_is_valid_extended_addr(extended_addr))
			ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr);
		else
			memcpy(ndev->dev_addr, ndev->perm_addr,
			       IEEE802154_EXTENDED_ADDR_LEN);
490
		break;
491
	case NL802154_IFTYPE_MONITOR:
492
		ndev->type = ARPHRD_IEEE802154_MONITOR;
493
		break;
494 495 496
	default:
		ret = -EINVAL;
		goto err;
497
	}
498 499 500 501 502 503 504 505 506 507 508 509 510

	/* 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)
511 512
		goto err;

513 514 515
	ret = register_netdevice(ndev);
	if (ret < 0)
		goto err;
516 517 518 519

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

521
	return ndev;
522 523

err:
524 525
	free_netdev(ndev);
	return ERR_PTR(ret);
526 527
}

528 529 530 531 532 533 534 535 536 537 538
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);
}
539 540 541

void ieee802154_remove_interfaces(struct ieee802154_local *local)
{
542
	struct ieee802154_sub_if_data *sdata, *tmp;
543

544
	mutex_lock(&local->iflist_mtx);
545
	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
546 547 548 549
		list_del(&sdata->list);

		unregister_netdevice(sdata->dev);
	}
550
	mutex_unlock(&local->iflist_mtx);
551
}
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586

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