cfg.c 24.3 KB
Newer Older
1
2
3
/*
 * mac80211 configuration hooks for cfg80211
 *
4
 * Copyright 2006, 2007	Johannes Berg <johannes@sipsolutions.net>
5
6
7
8
 *
 * This file is GPLv2 as found in COPYING.
 */

9
#include <linux/ieee80211.h>
10
11
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
12
#include <net/net_namespace.h>
13
#include <linux/rcupdate.h>
14
15
#include <net/cfg80211.h>
#include "ieee80211_i.h"
16
#include "cfg.h"
Johannes Berg's avatar
Johannes Berg committed
17
#include "rate.h"
18
19
#include "mesh.h"

20
21
22
23
24
25
26
struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy)
{
	struct ieee80211_local *local = wiphy_priv(wiphy);
	return &local->hw;
}
EXPORT_SYMBOL(wiphy_to_hw);

27
28
29
30
31
32
33
34
35
36
37
38
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
{
	switch (type) {
	case NL80211_IFTYPE_UNSPECIFIED:
		return IEEE80211_IF_TYPE_STA;
	case NL80211_IFTYPE_ADHOC:
		return IEEE80211_IF_TYPE_IBSS;
	case NL80211_IFTYPE_STATION:
		return IEEE80211_IF_TYPE_STA;
	case NL80211_IFTYPE_MONITOR:
		return IEEE80211_IF_TYPE_MNTR;
39
40
41
42
#ifdef CONFIG_MAC80211_MESH
	case NL80211_IFTYPE_MESH_POINT:
		return IEEE80211_IF_TYPE_MESH_POINT;
#endif
Johannes Berg's avatar
Johannes Berg committed
43
44
	case NL80211_IFTYPE_WDS:
		return IEEE80211_IF_TYPE_WDS;
45
46
47
48
49
	default:
		return IEEE80211_IF_TYPE_INVALID;
	}
}

50
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
51
52
			       enum nl80211_iftype type, u32 *flags,
			       struct vif_params *params)
53
54
{
	struct ieee80211_local *local = wiphy_priv(wiphy);
55
	enum ieee80211_if_types itype;
56
57
58
	struct net_device *dev;
	struct ieee80211_sub_if_data *sdata;
	int err;
59

60
61
	itype = nl80211_type_to_mac80211_type(type);
	if (itype == IEEE80211_IF_TYPE_INVALID)
62
63
		return -EINVAL;

64
	err = ieee80211_if_add(local, name, &dev, itype, params);
65
66
67
68
69
70
	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
		return err;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	sdata->u.mntr_flags = *flags;
	return 0;
71
72
73
74
75
}

static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
{
	struct net_device *dev;
76
	struct ieee80211_sub_if_data *sdata;
77

78
79
	/* we're under RTNL */
	dev = __dev_get_by_index(&init_net, ifindex);
80
	if (!dev)
81
		return -ENODEV;
82

83
84
85
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	ieee80211_if_remove(sdata);
86

87
	return 0;
88
89
}

90
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
91
92
				  enum nl80211_iftype type, u32 *flags,
				  struct vif_params *params)
93
{
94
	struct ieee80211_local *local = wiphy_priv(wiphy);
95
96
97
	struct net_device *dev;
	enum ieee80211_if_types itype;
	struct ieee80211_sub_if_data *sdata;
98
	int ret;
99
100
101
102
103
104
105
106
107
108

	/* we're under RTNL */
	dev = __dev_get_by_index(&init_net, ifindex);
	if (!dev)
		return -ENODEV;

	itype = nl80211_type_to_mac80211_type(type);
	if (itype == IEEE80211_IF_TYPE_INVALID)
		return -EINVAL;

109
110
111
	if (dev == local->mdev)
		return -EOPNOTSUPP;

112
113
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

114
115
116
	ret = ieee80211_if_change_type(sdata, itype);
	if (ret)
		return ret;
117

Johannes Berg's avatar
Johannes Berg committed
118
119
120
121
	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
					     params->mesh_id_len,
					     params->mesh_id);
122

123
124
125
126
	if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
		return 0;

	sdata->u.mntr_flags = *flags;
127
128
129
	return 0;
}

130
131
132
133
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr,
			     struct key_params *params)
{
134
	struct ieee80211_local *local = wiphy_priv(wiphy);
135
136
137
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta = NULL;
	enum ieee80211_key_alg alg;
138
	struct ieee80211_key *key;
139
	int err;
140

141
142
143
	if (dev == local->mdev)
		return -EOPNOTSUPP;

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	switch (params->cipher) {
	case WLAN_CIPHER_SUITE_WEP40:
	case WLAN_CIPHER_SUITE_WEP104:
		alg = ALG_WEP;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		alg = ALG_TKIP;
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		alg = ALG_CCMP;
		break;
	default:
		return -EINVAL;
	}

161
162
163
164
	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
	if (!key)
		return -ENOMEM;

165
166
	rcu_read_lock();

167
168
	if (mac_addr) {
		sta = sta_info_get(sdata->local, mac_addr);
169
170
		if (!sta) {
			ieee80211_key_free(key);
171
172
			err = -ENOENT;
			goto out_unlock;
173
		}
174
175
	}

176
177
	ieee80211_key_link(key, sdata, sta);

178
179
180
181
182
	err = 0;
 out_unlock:
	rcu_read_unlock();

	return err;
183
184
185
186
187
}

static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr)
{
188
	struct ieee80211_local *local = wiphy_priv(wiphy);
189
190
191
192
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta;
	int ret;

193
194
195
	if (dev == local->mdev)
		return -EOPNOTSUPP;

196
197
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

198
199
	rcu_read_lock();

200
	if (mac_addr) {
201
202
		ret = -ENOENT;

203
204
		sta = sta_info_get(sdata->local, mac_addr);
		if (!sta)
205
			goto out_unlock;
206

207
		if (sta->key) {
208
			ieee80211_key_free(sta->key);
209
			WARN_ON(sta->key);
210
211
			ret = 0;
		}
212

213
		goto out_unlock;
214
215
	}

216
217
218
219
	if (!sdata->keys[key_idx]) {
		ret = -ENOENT;
		goto out_unlock;
	}
220

221
	ieee80211_key_free(sdata->keys[key_idx]);
222
	WARN_ON(sdata->keys[key_idx]);
223

224
225
226
227
228
	ret = 0;
 out_unlock:
	rcu_read_unlock();

	return ret;
229
230
}

231
232
233
234
235
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr, void *cookie,
			     void (*callback)(void *cookie,
					      struct key_params *params))
{
236
237
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
238
239
240
241
242
243
244
245
	struct sta_info *sta = NULL;
	u8 seq[6] = {0};
	struct key_params params;
	struct ieee80211_key *key;
	u32 iv32;
	u16 iv16;
	int err = -ENOENT;

246
247
248
249
250
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

251
252
	rcu_read_lock();

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
	if (mac_addr) {
		sta = sta_info_get(sdata->local, mac_addr);
		if (!sta)
			goto out;

		key = sta->key;
	} else
		key = sdata->keys[key_idx];

	if (!key)
		goto out;

	memset(&params, 0, sizeof(params));

	switch (key->conf.alg) {
	case ALG_TKIP:
		params.cipher = WLAN_CIPHER_SUITE_TKIP;

271
272
		iv32 = key->u.tkip.tx.iv32;
		iv16 = key->u.tkip.tx.iv16;
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
		    sdata->local->ops->get_tkip_seq)
			sdata->local->ops->get_tkip_seq(
				local_to_hw(sdata->local),
				key->conf.hw_key_idx,
				&iv32, &iv16);

		seq[0] = iv16 & 0xff;
		seq[1] = (iv16 >> 8) & 0xff;
		seq[2] = iv32 & 0xff;
		seq[3] = (iv32 >> 8) & 0xff;
		seq[4] = (iv32 >> 16) & 0xff;
		seq[5] = (iv32 >> 24) & 0xff;
		params.seq = seq;
		params.seq_len = 6;
		break;
	case ALG_CCMP:
		params.cipher = WLAN_CIPHER_SUITE_CCMP;
		seq[0] = key->u.ccmp.tx_pn[5];
		seq[1] = key->u.ccmp.tx_pn[4];
		seq[2] = key->u.ccmp.tx_pn[3];
		seq[3] = key->u.ccmp.tx_pn[2];
		seq[4] = key->u.ccmp.tx_pn[1];
		seq[5] = key->u.ccmp.tx_pn[0];
		params.seq = seq;
		params.seq_len = 6;
		break;
	case ALG_WEP:
		if (key->conf.keylen == 5)
			params.cipher = WLAN_CIPHER_SUITE_WEP40;
		else
			params.cipher = WLAN_CIPHER_SUITE_WEP104;
		break;
	}

	params.key = key->conf.key;
	params.key_len = key->conf.keylen;

	callback(cookie, &params);
	err = 0;

 out:
316
	rcu_read_unlock();
317
318
319
	return err;
}

320
321
322
323
static int ieee80211_config_default_key(struct wiphy *wiphy,
					struct net_device *dev,
					u8 key_idx)
{
324
	struct ieee80211_local *local = wiphy_priv(wiphy);
325
326
	struct ieee80211_sub_if_data *sdata;

327
328
329
	if (dev == local->mdev)
		return -EOPNOTSUPP;

330
331
	rcu_read_lock();

332
333
334
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	ieee80211_set_default_key(sdata, key_idx);

335
336
	rcu_read_unlock();

337
338
339
	return 0;
}

340
341
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
342
	struct ieee80211_sub_if_data *sdata = sta->sdata;
343
344
345
346
347
348
349
350
351

	sinfo->filled = STATION_INFO_INACTIVE_TIME |
			STATION_INFO_RX_BYTES |
			STATION_INFO_TX_BYTES;

	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
	sinfo->rx_bytes = sta->rx_bytes;
	sinfo->tx_bytes = sta->tx_bytes;

Johannes Berg's avatar
Johannes Berg committed
352
	if (ieee80211_vif_is_mesh(&sdata->vif)) {
353
354
355
356
357
358
359
360
361
#ifdef CONFIG_MAC80211_MESH
		sinfo->filled |= STATION_INFO_LLID |
				 STATION_INFO_PLID |
				 STATION_INFO_PLINK_STATE;

		sinfo->llid = le16_to_cpu(sta->llid);
		sinfo->plid = le16_to_cpu(sta->plid);
		sinfo->plink_state = sta->plink_state;
#endif
Johannes Berg's avatar
Johannes Berg committed
362
	}
363
364
365
366
367
368
369
370
}


static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
				 int idx, u8 *mac, struct station_info *sinfo)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct sta_info *sta;
371
372
373
	int ret = -ENOENT;

	rcu_read_lock();
374
375

	sta = sta_info_get_by_idx(local, idx, dev);
376
377
378
379
380
	if (sta) {
		ret = 0;
		memcpy(mac, sta->addr, ETH_ALEN);
		sta_set_sinfo(sta, sinfo);
	}
381

382
	rcu_read_unlock();
383

384
	return ret;
385
386
}

387
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
388
				 u8 *mac, struct station_info *sinfo)
389
390
391
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct sta_info *sta;
392
	int ret = -ENOENT;
393

394
	rcu_read_lock();
395
396
397

	/* XXX: verify sta->dev == dev */

398
399
400
401
402
403
404
405
406
	sta = sta_info_get(local, mac);
	if (sta) {
		ret = 0;
		sta_set_sinfo(sta, sinfo);
	}

	rcu_read_unlock();

	return ret;
407
408
}

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/*
 * This handles both adding a beacon and setting new beacon info
 */
static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
				   struct beacon_parameters *params)
{
	struct beacon_data *new, *old;
	int new_head_len, new_tail_len;
	int size;
	int err = -EINVAL;

	old = sdata->u.ap.beacon;

	/* head must not be zero-length */
	if (params->head && !params->head_len)
		return -EINVAL;

	/*
	 * This is a kludge. beacon interval should really be part
	 * of the beacon information.
	 */
	if (params->interval) {
		sdata->local->hw.conf.beacon_int = params->interval;
		if (ieee80211_hw_config(sdata->local))
			return -EINVAL;
		/*
		 * We updated some parameter so if below bails out
		 * it's not an error.
		 */
		err = 0;
	}

	/* Need to have a beacon head if we don't have one yet */
	if (!params->head && !old)
		return err;

	/* sorry, no way to start beaconing without dtim period */
	if (!params->dtim_period && !old)
		return err;

	/* new or old head? */
	if (params->head)
		new_head_len = params->head_len;
	else
		new_head_len = old->head_len;

	/* new or old tail? */
	if (params->tail || !old)
		/* params->tail_len will be zero for !params->tail */
		new_tail_len = params->tail_len;
	else
		new_tail_len = old->tail_len;

	size = sizeof(*new) + new_head_len + new_tail_len;

	new = kzalloc(size, GFP_KERNEL);
	if (!new)
		return -ENOMEM;

	/* start filling the new info now */

	/* new or old dtim period? */
	if (params->dtim_period)
		new->dtim_period = params->dtim_period;
	else
		new->dtim_period = old->dtim_period;

	/*
	 * pointers go into the block we allocated,
	 * memory is | beacon_data | head | tail |
	 */
	new->head = ((u8 *) new) + sizeof(*new);
	new->tail = new->head + new_head_len;
	new->head_len = new_head_len;
	new->tail_len = new_tail_len;

	/* copy in head */
	if (params->head)
		memcpy(new->head, params->head, new_head_len);
	else
		memcpy(new->head, old->head, new_head_len);

	/* copy in optional tail */
	if (params->tail)
		memcpy(new->tail, params->tail, new_tail_len);
	else
		if (old)
			memcpy(new->tail, old->tail, new_tail_len);

	rcu_assign_pointer(sdata->u.ap.beacon, new);

	synchronize_rcu();

	kfree(old);

504
	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
505
506
507
508
509
}

static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
				struct beacon_parameters *params)
{
510
511
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
512
513
	struct beacon_data *old;

514
515
516
517
518
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

519
520
521
522
523
524
525
526
527
528
529
530
531
532
	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
		return -EINVAL;

	old = sdata->u.ap.beacon;

	if (old)
		return -EALREADY;

	return ieee80211_config_beacon(sdata, params);
}

static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
				struct beacon_parameters *params)
{
533
534
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
535
536
	struct beacon_data *old;

537
538
539
540
541
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

542
543
544
545
546
547
548
549
550
551
552
553
554
	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
		return -EINVAL;

	old = sdata->u.ap.beacon;

	if (!old)
		return -ENOENT;

	return ieee80211_config_beacon(sdata, params);
}

static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
{
555
556
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
557
558
	struct beacon_data *old;

559
560
561
562
563
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

564
565
566
567
568
569
570
571
572
573
574
575
	if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
		return -EINVAL;

	old = sdata->u.ap.beacon;

	if (!old)
		return -ENOENT;

	rcu_assign_pointer(sdata->u.ap.beacon, NULL);
	synchronize_rcu();
	kfree(old);

576
	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
577
578
}

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
	u8 da[ETH_ALEN];	/* broadcast */
	u8 sa[ETH_ALEN];	/* STA addr */
	__be16 len;		/* 6 */
	u8 dsap;		/* 0 */
	u8 ssap;		/* 0 */
	u8 control;
	u8 xid_info[3];
} __attribute__ ((packed));

static void ieee80211_send_layer2_update(struct sta_info *sta)
{
	struct iapp_layer2_update *msg;
	struct sk_buff *skb;

	/* Send Level 2 Update Frame to update forwarding tables in layer 2
	 * bridge devices */

	skb = dev_alloc_skb(sizeof(*msg));
	if (!skb)
		return;
	msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));

	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */

	memset(msg->da, 0xff, ETH_ALEN);
	memcpy(msg->sa, sta->addr, ETH_ALEN);
	msg->len = htons(6);
	msg->dsap = 0;
	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
	msg->control = 0xaf;	/* XID response lsb.1111F101.
				 * F=0 (no poll command; unsolicited frame) */
	msg->xid_info[0] = 0x81;	/* XID format identifier */
	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */

617
618
	skb->dev = sta->sdata->dev;
	skb->protocol = eth_type_trans(skb, sta->sdata->dev);
619
620
621
622
623
624
625
626
627
628
	memset(skb->cb, 0, sizeof(skb->cb));
	netif_rx(skb);
}

static void sta_apply_parameters(struct ieee80211_local *local,
				 struct sta_info *sta,
				 struct station_parameters *params)
{
	u32 rates;
	int i, j;
629
	struct ieee80211_supported_band *sband;
630
	struct ieee80211_sub_if_data *sdata = sta->sdata;
631

Johannes Berg's avatar
Johannes Berg committed
632
633
634
635
636
637
	/*
	 * FIXME: updating the flags is racy when this function is
	 *	  called from ieee80211_change_station(), this will
	 *	  be resolved in a future patch.
	 */

638
	if (params->station_flags & STATION_FLAG_CHANGED) {
639
		spin_lock_bh(&sta->lock);
640
641
642
643
644
645
646
647
648
649
650
		sta->flags &= ~WLAN_STA_AUTHORIZED;
		if (params->station_flags & STATION_FLAG_AUTHORIZED)
			sta->flags |= WLAN_STA_AUTHORIZED;

		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
		if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
			sta->flags |= WLAN_STA_SHORT_PREAMBLE;

		sta->flags &= ~WLAN_STA_WME;
		if (params->station_flags & STATION_FLAG_WME)
			sta->flags |= WLAN_STA_WME;
651
		spin_unlock_bh(&sta->lock);
652
653
	}

Johannes Berg's avatar
Johannes Berg committed
654
655
656
657
658
659
660
	/*
	 * FIXME: updating the following information is racy when this
	 *	  function is called from ieee80211_change_station().
	 *	  However, all this information should be static so
	 *	  maybe we should just reject attemps to change it.
	 */

661
662
663
664
665
666
667
668
669
670
671
	if (params->aid) {
		sta->aid = params->aid;
		if (sta->aid > IEEE80211_MAX_AID)
			sta->aid = 0; /* XXX: should this be an error? */
	}

	if (params->listen_interval >= 0)
		sta->listen_interval = params->listen_interval;

	if (params->supported_rates) {
		rates = 0;
672
673
		sband = local->hw.wiphy->bands[local->oper_channel->band];

674
675
		for (i = 0; i < params->supported_rates_len; i++) {
			int rate = (params->supported_rates[i] & 0x7f) * 5;
676
677
			for (j = 0; j < sband->n_bitrates; j++) {
				if (sband->bitrates[j].bitrate == rate)
678
679
680
					rates |= BIT(j);
			}
		}
681
		sta->supp_rates[local->oper_channel->band] = rates;
682
	}
683

684
685
686
687
688
	if (params->ht_capa) {
		ieee80211_ht_cap_ie_to_ht_info(params->ht_capa,
					       &sta->ht_info);
	}

Johannes Berg's avatar
Johannes Berg committed
689
	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
690
691
692
693
694
695
696
697
		switch (params->plink_action) {
		case PLINK_ACTION_OPEN:
			mesh_plink_open(sta);
			break;
		case PLINK_ACTION_BLOCK:
			mesh_plink_block(sta);
			break;
		}
Johannes Berg's avatar
Johannes Berg committed
698
	}
699
700
701
702
703
}

static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
				 u8 *mac, struct station_parameters *params)
{
704
	struct ieee80211_local *local = wiphy_priv(wiphy);
705
706
	struct sta_info *sta;
	struct ieee80211_sub_if_data *sdata;
Johannes Berg's avatar
Johannes Berg committed
707
	int err;
708

709
710
711
	if (dev == local->mdev || params->vlan == local->mdev)
		return -EOPNOTSUPP;

712
713
714
715
716
717
718
	/* Prevent a race with changing the rate control algorithm */
	if (!netif_running(dev))
		return -ENETDOWN;

	if (params->vlan) {
		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);

719
		if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
720
721
722
723
724
		    sdata->vif.type != IEEE80211_IF_TYPE_AP)
			return -EINVAL;
	} else
		sdata = IEEE80211_DEV_TO_SUB_IF(dev);

725
726
727
728
729
730
731
	if (compare_ether_addr(mac, dev->dev_addr) == 0)
		return -EINVAL;

	if (is_multicast_ether_addr(mac))
		return -EINVAL;

	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
Johannes Berg's avatar
Johannes Berg committed
732
733
	if (!sta)
		return -ENOMEM;
734
735
736
737
738
739
740

	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;

	sta_apply_parameters(local, sta, params);

	rate_control_rate_init(sta, local);

Johannes Berg's avatar
Johannes Berg committed
741
742
743
744
	rcu_read_lock();

	err = sta_info_insert(sta);
	if (err) {
745
		/* STA has been freed */
Johannes Berg's avatar
Johannes Berg committed
746
747
748
749
750
751
752
753
754
755
		rcu_read_unlock();
		return err;
	}

	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
	    sdata->vif.type == IEEE80211_IF_TYPE_AP)
		ieee80211_send_layer2_update(sta);

	rcu_read_unlock();

756
757
758
759
760
761
	return 0;
}

static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
				 u8 *mac)
{
762
763
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
764
765
	struct sta_info *sta;

766
767
768
769
770
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

771
	if (mac) {
Johannes Berg's avatar
Johannes Berg committed
772
773
		rcu_read_lock();

774
775
		/* XXX: get sta belonging to dev */
		sta = sta_info_get(local, mac);
Johannes Berg's avatar
Johannes Berg committed
776
777
		if (!sta) {
			rcu_read_unlock();
778
			return -ENOENT;
Johannes Berg's avatar
Johannes Berg committed
779
		}
780

781
		sta_info_unlink(&sta);
Johannes Berg's avatar
Johannes Berg committed
782
783
		rcu_read_unlock();

784
		sta_info_destroy(sta);
785
	} else
786
		sta_info_flush(local, sdata);
787
788
789
790
791
792
793
794
795

	return 0;
}

static int ieee80211_change_station(struct wiphy *wiphy,
				    struct net_device *dev,
				    u8 *mac,
				    struct station_parameters *params)
{
796
	struct ieee80211_local *local = wiphy_priv(wiphy);
797
798
799
	struct sta_info *sta;
	struct ieee80211_sub_if_data *vlansdata;

800
801
802
	if (dev == local->mdev || params->vlan == local->mdev)
		return -EOPNOTSUPP;

Johannes Berg's avatar
Johannes Berg committed
803
804
	rcu_read_lock();

805
806
	/* XXX: get sta belonging to dev */
	sta = sta_info_get(local, mac);
Johannes Berg's avatar
Johannes Berg committed
807
808
	if (!sta) {
		rcu_read_unlock();
809
		return -ENOENT;
Johannes Berg's avatar
Johannes Berg committed
810
	}
811

812
	if (params->vlan && params->vlan != sta->sdata->dev) {
813
814
		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);

815
		if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
Johannes Berg's avatar
Johannes Berg committed
816
817
		    vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
			rcu_read_unlock();
818
			return -EINVAL;
Johannes Berg's avatar
Johannes Berg committed
819
		}
820

821
		sta->sdata = vlansdata;
822
823
824
825
826
		ieee80211_send_layer2_update(sta);
	}

	sta_apply_parameters(local, sta, params);

Johannes Berg's avatar
Johannes Berg committed
827
828
	rcu_read_unlock();

829
830
831
	return 0;
}

832
833
834
835
#ifdef CONFIG_MAC80211_MESH
static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
				 u8 *dst, u8 *next_hop)
{
836
837
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
838
839
840
841
	struct mesh_path *mpath;
	struct sta_info *sta;
	int err;

842
843
844
	if (dev == local->mdev)
		return -EOPNOTSUPP;

845
846
847
	if (!netif_running(dev))
		return -ENETDOWN;

848
849
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

850
851
852
	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
		return -ENOTSUPP;

853
	rcu_read_lock();
854
	sta = sta_info_get(local, next_hop);
855
856
	if (!sta) {
		rcu_read_unlock();
857
		return -ENOENT;
858
	}
859

860
	err = mesh_path_add(dst, sdata);
861
862
	if (err) {
		rcu_read_unlock();
863
		return err;
864
	}
865

866
	mpath = mesh_path_lookup(dst, sdata);
867
868
869
870
871
	if (!mpath) {
		rcu_read_unlock();
		return -ENXIO;
	}
	mesh_path_fix_nexthop(mpath, sta);
872

873
874
875
876
877
878
879
	rcu_read_unlock();
	return 0;
}

static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
				 u8 *dst)
{
880
881
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

882
	if (dst)
883
		return mesh_path_del(dst, sdata);
884

885
	mesh_path_flush(sdata);
886
887
888
889
890
891
892
	return 0;
}

static int ieee80211_change_mpath(struct wiphy *wiphy,
				    struct net_device *dev,
				    u8 *dst, u8 *next_hop)
{
893
894
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
895
896
897
	struct mesh_path *mpath;
	struct sta_info *sta;

898
899
900
	if (dev == local->mdev)
		return -EOPNOTSUPP;

901
902
903
	if (!netif_running(dev))
		return -ENETDOWN;

904
905
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

906
907
908
	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
		return -ENOTSUPP;

909
910
	rcu_read_lock();

911
	sta = sta_info_get(local, next_hop);
912
913
	if (!sta) {
		rcu_read_unlock();
914
		return -ENOENT;
915
	}
916

917
	mpath = mesh_path_lookup(dst, sdata);
918
919
920
921
922
923
	if (!mpath) {
		rcu_read_unlock();
		return -ENOENT;
	}

	mesh_path_fix_nexthop(mpath, sta);
924

925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
	rcu_read_unlock();
	return 0;
}

static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
			    struct mpath_info *pinfo)
{
	if (mpath->next_hop)
		memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
	else
		memset(next_hop, 0, ETH_ALEN);

	pinfo->filled = MPATH_INFO_FRAME_QLEN |
			MPATH_INFO_DSN |
			MPATH_INFO_METRIC |
			MPATH_INFO_EXPTIME |
			MPATH_INFO_DISCOVERY_TIMEOUT |
			MPATH_INFO_DISCOVERY_RETRIES |
			MPATH_INFO_FLAGS;

	pinfo->frame_qlen = mpath->frame_queue.qlen;
	pinfo->dsn = mpath->dsn;
	pinfo->metric = mpath->metric;
	if (time_before(jiffies, mpath->exp_time))
		pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
	pinfo->discovery_timeout =
			jiffies_to_msecs(mpath->discovery_timeout);
	pinfo->discovery_retries = mpath->discovery_retries;
	pinfo->flags = 0;
	if (mpath->flags & MESH_PATH_ACTIVE)
		pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
	if (mpath->flags & MESH_PATH_RESOLVING)
		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
	if (mpath->flags & MESH_PATH_DSN_VALID)
		pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID;
	if (mpath->flags & MESH_PATH_FIXED)
		pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
	if (mpath->flags & MESH_PATH_RESOLVING)
		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;

	pinfo->flags = mpath->flags;
}

static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo)

{
972
973
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
974
975
	struct mesh_path *mpath;

976
977
978
979
980
	if (dev == local->mdev)
		return -EOPNOTSUPP;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

981
982
983
984
	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
		return -ENOTSUPP;

	rcu_read_lock();
985
	mpath = mesh_path_lookup(dst, sdata);
986
987
988
989
990
991
992
993
994
995
996
997
998
999
	if (!mpath) {
		rcu_read_unlock();
		return -ENOENT;
	}
	memcpy(dst, mpath->dst, ETH_ALEN);
	mpath_set_pinfo(mpath, next_hop, pinfo);
	rcu_read_unlock();
	return 0;
}

static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
				 int idx, u8 *dst, u8 *next_hop,
				 struct mpath_info *pinfo)
{
1000
	struct ieee80211_local *local = wiphy_priv(wiphy);
For faster browsing, not all history is shown. View entire blame