cfg.c 22.4 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
static bool nl80211_type_check(enum nl80211_iftype type)
21
22
23
24
25
{
	switch (type) {
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_MONITOR:
26
27
28
#ifdef CONFIG_MAC80211_MESH
	case NL80211_IFTYPE_MESH_POINT:
#endif
Johannes Berg's avatar
Johannes Berg committed
29
	case NL80211_IFTYPE_WDS:
30
		return true;
31
	default:
32
		return false;
33
34
35
	}
}

36
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
37
38
			       enum nl80211_iftype type, u32 *flags,
			       struct vif_params *params)
39
40
{
	struct ieee80211_local *local = wiphy_priv(wiphy);
41
42
43
	struct net_device *dev;
	struct ieee80211_sub_if_data *sdata;
	int err;
44

45
	if (!nl80211_type_check(type))
46
47
		return -EINVAL;

48
49
	err = ieee80211_if_add(local, name, &dev, type, params);
	if (err || type != NL80211_IFTYPE_MONITOR || !flags)
50
51
52
53
54
		return err;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	sdata->u.mntr_flags = *flags;
	return 0;
55
56
57
58
59
}

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

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

67
68
69
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	ieee80211_if_remove(sdata);
70

71
	return 0;
72
73
}

74
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
75
76
				  enum nl80211_iftype type, u32 *flags,
				  struct vif_params *params)
77
78
79
{
	struct net_device *dev;
	struct ieee80211_sub_if_data *sdata;
80
	int ret;
81
82
83
84
85
86

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

87
	if (!nl80211_type_check(type))
88
89
90
91
		return -EINVAL;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

92
	ret = ieee80211_if_change_type(sdata, type);
93
94
	if (ret)
		return ret;
95

96
97
98
	if (netif_running(sdata->dev))
		return -EBUSY;

Johannes Berg's avatar
Johannes Berg committed
99
	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
100
101
102
		ieee80211_sdata_set_mesh_id(sdata,
					    params->mesh_id_len,
					    params->mesh_id);
103

104
	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
105
106
107
		return 0;

	sdata->u.mntr_flags = *flags;
108
109
110
	return 0;
}

111
112
113
114
115
116
117
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr,
			     struct key_params *params)
{
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta = NULL;
	enum ieee80211_key_alg alg;
118
	struct ieee80211_key *key;
119
	int err;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

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

138
139
140
141
	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
	if (!key)
		return -ENOMEM;

142
143
	rcu_read_lock();

144
145
	if (mac_addr) {
		sta = sta_info_get(sdata->local, mac_addr);
146
147
		if (!sta) {
			ieee80211_key_free(key);
148
149
			err = -ENOENT;
			goto out_unlock;
150
		}
151
152
	}

153
154
	ieee80211_key_link(key, sdata, sta);

155
156
157
158
159
	err = 0;
 out_unlock:
	rcu_read_unlock();

	return err;
160
161
162
163
164
165
166
167
168
169
170
}

static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr)
{
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta;
	int ret;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

171
172
	rcu_read_lock();

173
	if (mac_addr) {
174
175
		ret = -ENOENT;

176
177
		sta = sta_info_get(sdata->local, mac_addr);
		if (!sta)
178
			goto out_unlock;
179

180
		if (sta->key) {
181
			ieee80211_key_free(sta->key);
182
			WARN_ON(sta->key);
183
184
			ret = 0;
		}
185

186
		goto out_unlock;
187
188
	}

189
190
191
192
	if (!sdata->keys[key_idx]) {
		ret = -ENOENT;
		goto out_unlock;
	}
193

194
	ieee80211_key_free(sdata->keys[key_idx]);
195
	WARN_ON(sdata->keys[key_idx]);
196

197
198
199
200
201
	ret = 0;
 out_unlock:
	rcu_read_unlock();

	return ret;
202
203
}

204
205
206
207
208
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))
{
209
	struct ieee80211_sub_if_data *sdata;
210
211
212
213
214
215
216
217
	struct sta_info *sta = NULL;
	u8 seq[6] = {0};
	struct key_params params;
	struct ieee80211_key *key;
	u32 iv32;
	u16 iv16;
	int err = -ENOENT;

218
219
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

220
221
	rcu_read_lock();

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	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;

240
241
		iv32 = key->u.tkip.tx.iv32;
		iv16 = key->u.tkip.tx.iv16;
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

		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:
285
	rcu_read_unlock();
286
287
288
	return err;
}

289
290
291
292
293
294
static int ieee80211_config_default_key(struct wiphy *wiphy,
					struct net_device *dev,
					u8 key_idx)
{
	struct ieee80211_sub_if_data *sdata;

295
296
	rcu_read_lock();

297
298
299
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	ieee80211_set_default_key(sdata, key_idx);

300
301
	rcu_read_unlock();

302
303
304
	return 0;
}

305
306
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
307
	struct ieee80211_sub_if_data *sdata = sta->sdata;
308
309
310
311
312
313
314
315
316

	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
317
	if (ieee80211_vif_is_mesh(&sdata->vif)) {
318
319
320
321
322
323
324
325
326
#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
327
	}
328
329
330
331
332
333
334
335
}


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;
336
337
338
	int ret = -ENOENT;

	rcu_read_lock();
339
340

	sta = sta_info_get_by_idx(local, idx, dev);
341
342
	if (sta) {
		ret = 0;
343
		memcpy(mac, sta->sta.addr, ETH_ALEN);
344
345
		sta_set_sinfo(sta, sinfo);
	}
346

347
	rcu_read_unlock();
348

349
	return ret;
350
351
}

352
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
353
				 u8 *mac, struct station_info *sinfo)
354
355
356
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct sta_info *sta;
357
	int ret = -ENOENT;
358

359
	rcu_read_lock();
360
361
362

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

363
364
365
366
367
368
369
370
371
	sta = sta_info_get(local, mac);
	if (sta) {
		ret = 0;
		sta_set_sinfo(sta, sinfo);
	}

	rcu_read_unlock();

	return ret;
372
373
}

374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/*
 * 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;
397
398
		ieee80211_hw_config(sdata->local,
				    IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
399
400
401
402
403
404
405
406
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
		/*
		 * 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);

469
	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
470
471
472
473
474
}

static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
				struct beacon_parameters *params)
{
475
	struct ieee80211_sub_if_data *sdata;
476
477
	struct beacon_data *old;

478
479
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

480
	if (sdata->vif.type != NL80211_IFTYPE_AP)
481
482
483
484
485
486
487
488
489
490
491
492
493
		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)
{
494
	struct ieee80211_sub_if_data *sdata;
495
496
	struct beacon_data *old;

497
498
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

499
	if (sdata->vif.type != NL80211_IFTYPE_AP)
500
501
502
503
504
505
506
507
508
509
510
511
		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)
{
512
	struct ieee80211_sub_if_data *sdata;
513
514
	struct beacon_data *old;

515
516
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

517
	if (sdata->vif.type != NL80211_IFTYPE_AP)
518
519
520
521
522
523
524
525
526
527
528
		return -EINVAL;

	old = sdata->u.ap.beacon;

	if (!old)
		return -ENOENT;

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

529
	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
530
531
}

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
/* 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);
560
	memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
561
562
563
564
565
566
567
568
569
	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) */

570
571
	skb->dev = sta->sdata->dev;
	skb->protocol = eth_type_trans(skb, sta->sdata->dev);
572
573
574
575
576
577
578
579
580
581
	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;
582
	struct ieee80211_supported_band *sband;
583
	struct ieee80211_sub_if_data *sdata = sta->sdata;
584

Johannes Berg's avatar
Johannes Berg committed
585
586
587
588
589
590
	/*
	 * FIXME: updating the flags is racy when this function is
	 *	  called from ieee80211_change_station(), this will
	 *	  be resolved in a future patch.
	 */

591
	if (params->station_flags & STATION_FLAG_CHANGED) {
592
		spin_lock_bh(&sta->lock);
593
594
595
596
597
598
599
600
601
602
603
		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;
604
		spin_unlock_bh(&sta->lock);
605
606
	}

Johannes Berg's avatar
Johannes Berg committed
607
608
609
610
611
612
613
	/*
	 * 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.
	 */

614
	if (params->aid) {
615
616
617
		sta->sta.aid = params->aid;
		if (sta->sta.aid > IEEE80211_MAX_AID)
			sta->sta.aid = 0; /* XXX: should this be an error? */
618
619
620
621
622
623
624
	}

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

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

627
628
		for (i = 0; i < params->supported_rates_len; i++) {
			int rate = (params->supported_rates[i] & 0x7f) * 5;
629
630
			for (j = 0; j < sband->n_bitrates; j++) {
				if (sband->bitrates[j].bitrate == rate)
631
632
633
					rates |= BIT(j);
			}
		}
634
		sta->sta.supp_rates[local->oper_channel->band] = rates;
635
	}
636

637
638
639
	if (params->ht_capa)
		ieee80211_ht_cap_ie_to_sta_ht_cap(params->ht_capa,
						  &sta->sta.ht_cap);
640

Johannes Berg's avatar
Johannes Berg committed
641
	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
642
643
644
645
646
647
648
649
		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
650
	}
651
652
653
654
655
}

static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
				 u8 *mac, struct station_parameters *params)
{
656
	struct ieee80211_local *local = wiphy_priv(wiphy);
657
658
	struct sta_info *sta;
	struct ieee80211_sub_if_data *sdata;
Johannes Berg's avatar
Johannes Berg committed
659
	int err;
660
661
662
663
664
665
666
667

	/* 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);

668
669
		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
		    sdata->vif.type != NL80211_IFTYPE_AP)
670
671
672
673
			return -EINVAL;
	} else
		sdata = IEEE80211_DEV_TO_SUB_IF(dev);

674
675
676
677
678
679
680
	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
681
682
	if (!sta)
		return -ENOMEM;
683
684
685
686
687

	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;

	sta_apply_parameters(local, sta, params);

688
	rate_control_rate_init(sta);
689

Johannes Berg's avatar
Johannes Berg committed
690
691
692
693
	rcu_read_lock();

	err = sta_info_insert(sta);
	if (err) {
694
		/* STA has been freed */
Johannes Berg's avatar
Johannes Berg committed
695
696
697
698
		rcu_read_unlock();
		return err;
	}

699
700
	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
	    sdata->vif.type == NL80211_IFTYPE_AP)
Johannes Berg's avatar
Johannes Berg committed
701
702
703
704
		ieee80211_send_layer2_update(sta);

	rcu_read_unlock();

705
706
707
708
709
710
	return 0;
}

static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
				 u8 *mac)
{
711
712
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
713
714
	struct sta_info *sta;

715
716
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

717
	if (mac) {
Johannes Berg's avatar
Johannes Berg committed
718
719
		rcu_read_lock();

720
721
		/* XXX: get sta belonging to dev */
		sta = sta_info_get(local, mac);
Johannes Berg's avatar
Johannes Berg committed
722
723
		if (!sta) {
			rcu_read_unlock();
724
			return -ENOENT;
Johannes Berg's avatar
Johannes Berg committed
725
		}
726

727
		sta_info_unlink(&sta);
Johannes Berg's avatar
Johannes Berg committed
728
729
		rcu_read_unlock();

730
		sta_info_destroy(sta);
731
	} else
732
		sta_info_flush(local, sdata);
733
734
735
736
737
738
739
740
741

	return 0;
}

static int ieee80211_change_station(struct wiphy *wiphy,
				    struct net_device *dev,
				    u8 *mac,
				    struct station_parameters *params)
{
742
	struct ieee80211_local *local = wiphy_priv(wiphy);
743
744
745
	struct sta_info *sta;
	struct ieee80211_sub_if_data *vlansdata;

Johannes Berg's avatar
Johannes Berg committed
746
747
	rcu_read_lock();

748
749
	/* XXX: get sta belonging to dev */
	sta = sta_info_get(local, mac);
Johannes Berg's avatar
Johannes Berg committed
750
751
	if (!sta) {
		rcu_read_unlock();
752
		return -ENOENT;
Johannes Berg's avatar
Johannes Berg committed
753
	}
754

755
	if (params->vlan && params->vlan != sta->sdata->dev) {
756
757
		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);

758
759
		if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
		    vlansdata->vif.type != NL80211_IFTYPE_AP) {
Johannes Berg's avatar
Johannes Berg committed
760
			rcu_read_unlock();
761
			return -EINVAL;
Johannes Berg's avatar
Johannes Berg committed
762
		}
763

764
		sta->sdata = vlansdata;
765
766
767
768
769
		ieee80211_send_layer2_update(sta);
	}

	sta_apply_parameters(local, sta, params);

Johannes Berg's avatar
Johannes Berg committed
770
771
	rcu_read_unlock();

772
773
774
	return 0;
}

775
776
777
778
#ifdef CONFIG_MAC80211_MESH
static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
				 u8 *dst, u8 *next_hop)
{
779
780
	struct ieee80211_local *local = wiphy_priv(wiphy);
	struct ieee80211_sub_if_data *sdata;
781
782
783
784
785
786
787
	struct mesh_path *mpath;
	struct sta_info *sta;
	int err;

	if (!netif_running(dev))
		return -ENETDOWN;

788
789
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

790
	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
791
792
		return -ENOTSUPP;

793
	rcu_read_lock();
794
	sta = sta_info_get(local, next_hop);
795
796
	if (!sta) {
		rcu_read_unlock();
797
		return -ENOENT;
798
	}
799

800
	err = mesh_path_add(dst, sdata);
801
802
	if (err) {
		rcu_read_unlock();
803
		return err;
804
	}
805

806
	mpath = mesh_path_lookup(dst, sdata);
807
808
809
810
811
	if (!mpath) {
		rcu_read_unlock();
		return -ENXIO;
	}
	mesh_path_fix_nexthop(mpath, sta);
812

813
814
815
816
817
818
819
	rcu_read_unlock();
	return 0;
}

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

822
	if (dst)
823
		return mesh_path_del(dst, sdata);
824

825
	mesh_path_flush(sdata);
826
827
828
829
830
831
832
	return 0;
}

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

	if (!netif_running(dev))
		return -ENETDOWN;

841
842
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

843
	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
844
845
		return -ENOTSUPP;

846
847
	rcu_read_lock();

848
	sta = sta_info_get(local, next_hop);
849
850
	if (!sta) {
		rcu_read_unlock();
851
		return -ENOENT;
852
	}
853

854
	mpath = mesh_path_lookup(dst, sdata);
855
856
857
858
859
860
	if (!mpath) {
		rcu_read_unlock();
		return -ENOENT;
	}

	mesh_path_fix_nexthop(mpath, sta);
861

862
863
864
865
866
867
868
869
	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)
870
		memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
	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)

{
909
	struct ieee80211_sub_if_data *sdata;
910
911
	struct mesh_path *mpath;

912
913
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

914
	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
915
916
917
		return -ENOTSUPP;

	rcu_read_lock();
918
	mpath = mesh_path_lookup(dst, sdata);
919
920
921
922
923
924
925
926
927
928
929
930
931
932
	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)
{
933
	struct ieee80211_sub_if_data *sdata;
934
935
	struct mesh_path *mpath;

936
937
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

938
	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
939
940
941
		return -ENOTSUPP;

	rcu_read_lock();
942
	mpath = mesh_path_lookup_by_idx(idx, sdata);
943
944
945
946
947
948
949
950
951
952
953
	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;
}
#endif

954
955
956
957
958
959
960
961
962
static int ieee80211_change_bss(struct wiphy *wiphy,
				struct net_device *dev,
				struct bss_parameters *params)
{
	struct ieee80211_sub_if_data *sdata;
	u32 changed = 0;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

963
	if (sdata->vif.type != NL80211_IFTYPE_AP)
964
965
966
		return -EINVAL;

	if (params->use_cts_prot >= 0) {
967
		sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
968
969
970
		changed |= BSS_CHANGED_ERP_CTS_PROT;
	}
	if (params->use_short_preamble >= 0) {
971
		sdata->vif.bss_conf.use_short_preamble =
972
973
974
975
			params->use_short_preamble;
		changed |= BSS_CHANGED_ERP_PREAMBLE;
	}
	if (params->use_short_slot_time >= 0) {
976
		sdata->vif.bss_conf.use_short_slot =
977
978
979
980
981
982
983
984
985
			params->use_short_slot_time;
		changed |= BSS_CHANGED_ERP_SLOT;
	}

	ieee80211_bss_info_change_notify(sdata, changed);

	return 0;
}

986
987
988
struct cfg80211_ops mac80211_config_ops = {
	.add_virtual_intf = ieee80211_add_iface,
	.del_virtual_intf = ieee80211_del_iface,
989
	.change_virtual_intf = ieee80211_change_iface,
990
991
	.add_key = ieee80211_add_key,
	.del_key = ieee80211_del_key,
992
	.get_key = ieee80211_get_key,
993
	.set_default_key = ieee80211_config_default_key,
994
995
996
	.add_beacon = ieee80211_add_beacon,
	.set_beacon = ieee80211_set_beacon,
	.del_beacon = ieee80211_del_beacon,
997
998
999
	.add_station = ieee80211_add_station,
	.del_station = ieee80211_del_station,
	.change_station = ieee80211_change_station,
1000
	.get_station = ieee80211_get_station,
For faster browsing, not all history is shown. View entire blame