blob: 6b183a3526b0ae2f4f0b0c703d1686a2d2bc5222 [file] [log] [blame]
Jiri Bencf0706e82007-05-05 11:45:53 -07001/*
2 * mac80211 configuration hooks for cfg80211
3 *
Johannes Berg62da92f2007-12-19 02:03:31 +01004 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
Jiri Bencf0706e82007-05-05 11:45:53 -07005 *
6 * This file is GPLv2 as found in COPYING.
7 */
8
Johannes Berge8cbb4c2007-12-19 02:03:30 +01009#include <linux/ieee80211.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070010#include <linux/nl80211.h>
11#include <linux/rtnetlink.h>
Eric W. Biederman881d9662007-09-17 11:56:21 -070012#include <net/net_namespace.h>
Johannes Berg5dfdaf52007-12-19 02:03:33 +010013#include <linux/rcupdate.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070014#include <net/cfg80211.h>
15#include "ieee80211_i.h"
Michael Wue0eb6852007-09-18 17:29:21 -040016#include "cfg.h"
Johannes Berg4fd69312007-12-19 02:03:35 +010017#include "ieee80211_rate.h"
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +010018#include "mesh.h"
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +010019
Johannes Berg42613db2007-09-28 21:52:27 +020020static enum ieee80211_if_types
21nl80211_type_to_mac80211_type(enum nl80211_iftype type)
22{
23 switch (type) {
24 case NL80211_IFTYPE_UNSPECIFIED:
25 return IEEE80211_IF_TYPE_STA;
26 case NL80211_IFTYPE_ADHOC:
27 return IEEE80211_IF_TYPE_IBSS;
28 case NL80211_IFTYPE_STATION:
29 return IEEE80211_IF_TYPE_STA;
30 case NL80211_IFTYPE_MONITOR:
31 return IEEE80211_IF_TYPE_MNTR;
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +010032#ifdef CONFIG_MAC80211_MESH
33 case NL80211_IFTYPE_MESH_POINT:
34 return IEEE80211_IF_TYPE_MESH_POINT;
35#endif
Johannes Berg42613db2007-09-28 21:52:27 +020036 default:
37 return IEEE80211_IF_TYPE_INVALID;
38 }
39}
40
Jiri Bencf0706e82007-05-05 11:45:53 -070041static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010042 enum nl80211_iftype type, u32 *flags,
43 struct vif_params *params)
Jiri Bencf0706e82007-05-05 11:45:53 -070044{
45 struct ieee80211_local *local = wiphy_priv(wiphy);
Johannes Berg42613db2007-09-28 21:52:27 +020046 enum ieee80211_if_types itype;
Michael Wu8cc9a732008-01-31 19:48:23 +010047 struct net_device *dev;
48 struct ieee80211_sub_if_data *sdata;
49 int err;
Jiri Bencf0706e82007-05-05 11:45:53 -070050
51 if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
52 return -ENODEV;
53
Johannes Berg42613db2007-09-28 21:52:27 +020054 itype = nl80211_type_to_mac80211_type(type);
55 if (itype == IEEE80211_IF_TYPE_INVALID)
Jiri Bencf0706e82007-05-05 11:45:53 -070056 return -EINVAL;
Jiri Bencf0706e82007-05-05 11:45:53 -070057
Luis Carlos Coboee385852008-02-23 15:17:11 +010058 err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
Michael Wu8cc9a732008-01-31 19:48:23 +010059 if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
60 return err;
61
62 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
63 sdata->u.mntr_flags = *flags;
64 return 0;
Jiri Bencf0706e82007-05-05 11:45:53 -070065}
66
67static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
68{
69 struct ieee80211_local *local = wiphy_priv(wiphy);
70 struct net_device *dev;
71 char *name;
72
73 if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
74 return -ENODEV;
75
Johannes Berg42613db2007-09-28 21:52:27 +020076 /* we're under RTNL */
77 dev = __dev_get_by_index(&init_net, ifindex);
Jiri Bencf0706e82007-05-05 11:45:53 -070078 if (!dev)
79 return 0;
80
81 name = dev->name;
Jiri Bencf0706e82007-05-05 11:45:53 -070082
83 return ieee80211_if_remove(local->mdev, name, -1);
84}
85
Johannes Berg42613db2007-09-28 21:52:27 +020086static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +010087 enum nl80211_iftype type, u32 *flags,
88 struct vif_params *params)
Johannes Berg42613db2007-09-28 21:52:27 +020089{
90 struct ieee80211_local *local = wiphy_priv(wiphy);
91 struct net_device *dev;
92 enum ieee80211_if_types itype;
93 struct ieee80211_sub_if_data *sdata;
94
95 if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
96 return -ENODEV;
97
98 /* we're under RTNL */
99 dev = __dev_get_by_index(&init_net, ifindex);
100 if (!dev)
101 return -ENODEV;
102
103 if (netif_running(dev))
104 return -EBUSY;
105
106 itype = nl80211_type_to_mac80211_type(type);
107 if (itype == IEEE80211_IF_TYPE_INVALID)
108 return -EINVAL;
109
110 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
111
Johannes Berg51fb61e2007-12-19 01:31:27 +0100112 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
Johannes Berg42613db2007-09-28 21:52:27 +0200113 return -EOPNOTSUPP;
114
115 ieee80211_if_reinit(dev);
116 ieee80211_if_set_type(dev, itype);
117
Johannes Berg902acc72008-02-23 15:17:19 +0100118 if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
119 ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
120 params->mesh_id_len,
121 params->mesh_id);
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100122
Michael Wu8cc9a732008-01-31 19:48:23 +0100123 if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
124 return 0;
125
126 sdata->u.mntr_flags = *flags;
Johannes Berg42613db2007-09-28 21:52:27 +0200127 return 0;
128}
129
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100130static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
131 u8 key_idx, u8 *mac_addr,
132 struct key_params *params)
133{
134 struct ieee80211_sub_if_data *sdata;
135 struct sta_info *sta = NULL;
136 enum ieee80211_key_alg alg;
Johannes Bergdb4d1162008-02-25 16:27:45 +0100137 struct ieee80211_key *key;
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100138
139 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
140
141 switch (params->cipher) {
142 case WLAN_CIPHER_SUITE_WEP40:
143 case WLAN_CIPHER_SUITE_WEP104:
144 alg = ALG_WEP;
145 break;
146 case WLAN_CIPHER_SUITE_TKIP:
147 alg = ALG_TKIP;
148 break;
149 case WLAN_CIPHER_SUITE_CCMP:
150 alg = ALG_CCMP;
151 break;
152 default:
153 return -EINVAL;
154 }
155
Johannes Bergdb4d1162008-02-25 16:27:45 +0100156 key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
157 if (!key)
158 return -ENOMEM;
159
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100160 if (mac_addr) {
161 sta = sta_info_get(sdata->local, mac_addr);
Johannes Bergdb4d1162008-02-25 16:27:45 +0100162 if (!sta) {
163 ieee80211_key_free(key);
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100164 return -ENOENT;
Johannes Bergdb4d1162008-02-25 16:27:45 +0100165 }
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100166 }
167
Johannes Bergdb4d1162008-02-25 16:27:45 +0100168 ieee80211_key_link(key, sdata, sta);
169
Johannes Bergd0709a62008-02-25 16:27:46 +0100170 return 0;
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100171}
172
173static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
174 u8 key_idx, u8 *mac_addr)
175{
176 struct ieee80211_sub_if_data *sdata;
177 struct sta_info *sta;
178 int ret;
179
180 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
181
182 if (mac_addr) {
183 sta = sta_info_get(sdata->local, mac_addr);
184 if (!sta)
185 return -ENOENT;
186
187 ret = 0;
Johannes Bergdb4d1162008-02-25 16:27:45 +0100188 if (sta->key) {
Johannes Bergd0709a62008-02-25 16:27:46 +0100189 ieee80211_key_free(sta->key);
Johannes Bergdb4d1162008-02-25 16:27:45 +0100190 WARN_ON(sta->key);
191 } else
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100192 ret = -ENOENT;
193
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100194 return ret;
195 }
196
197 if (!sdata->keys[key_idx])
198 return -ENOENT;
199
Johannes Bergd0709a62008-02-25 16:27:46 +0100200 ieee80211_key_free(sdata->keys[key_idx]);
Johannes Bergdb4d1162008-02-25 16:27:45 +0100201 WARN_ON(sdata->keys[key_idx]);
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100202
203 return 0;
204}
205
Johannes Berg62da92f2007-12-19 02:03:31 +0100206static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
207 u8 key_idx, u8 *mac_addr, void *cookie,
208 void (*callback)(void *cookie,
209 struct key_params *params))
210{
211 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
212 struct sta_info *sta = NULL;
213 u8 seq[6] = {0};
214 struct key_params params;
215 struct ieee80211_key *key;
216 u32 iv32;
217 u16 iv16;
218 int err = -ENOENT;
219
220 if (mac_addr) {
221 sta = sta_info_get(sdata->local, mac_addr);
222 if (!sta)
223 goto out;
224
225 key = sta->key;
226 } else
227 key = sdata->keys[key_idx];
228
229 if (!key)
230 goto out;
231
232 memset(&params, 0, sizeof(params));
233
234 switch (key->conf.alg) {
235 case ALG_TKIP:
236 params.cipher = WLAN_CIPHER_SUITE_TKIP;
237
238 iv32 = key->u.tkip.iv32;
239 iv16 = key->u.tkip.iv16;
240
241 if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
242 sdata->local->ops->get_tkip_seq)
243 sdata->local->ops->get_tkip_seq(
244 local_to_hw(sdata->local),
245 key->conf.hw_key_idx,
246 &iv32, &iv16);
247
248 seq[0] = iv16 & 0xff;
249 seq[1] = (iv16 >> 8) & 0xff;
250 seq[2] = iv32 & 0xff;
251 seq[3] = (iv32 >> 8) & 0xff;
252 seq[4] = (iv32 >> 16) & 0xff;
253 seq[5] = (iv32 >> 24) & 0xff;
254 params.seq = seq;
255 params.seq_len = 6;
256 break;
257 case ALG_CCMP:
258 params.cipher = WLAN_CIPHER_SUITE_CCMP;
259 seq[0] = key->u.ccmp.tx_pn[5];
260 seq[1] = key->u.ccmp.tx_pn[4];
261 seq[2] = key->u.ccmp.tx_pn[3];
262 seq[3] = key->u.ccmp.tx_pn[2];
263 seq[4] = key->u.ccmp.tx_pn[1];
264 seq[5] = key->u.ccmp.tx_pn[0];
265 params.seq = seq;
266 params.seq_len = 6;
267 break;
268 case ALG_WEP:
269 if (key->conf.keylen == 5)
270 params.cipher = WLAN_CIPHER_SUITE_WEP40;
271 else
272 params.cipher = WLAN_CIPHER_SUITE_WEP104;
273 break;
274 }
275
276 params.key = key->conf.key;
277 params.key_len = key->conf.keylen;
278
279 callback(cookie, &params);
280 err = 0;
281
282 out:
Johannes Berg62da92f2007-12-19 02:03:31 +0100283 return err;
284}
285
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100286static int ieee80211_config_default_key(struct wiphy *wiphy,
287 struct net_device *dev,
288 u8 key_idx)
289{
290 struct ieee80211_sub_if_data *sdata;
291
292 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
293 ieee80211_set_default_key(sdata, key_idx);
294
295 return 0;
296}
297
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100298static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
299{
Johannes Bergd0709a62008-02-25 16:27:46 +0100300 struct ieee80211_sub_if_data *sdata = sta->sdata;
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100301
302 sinfo->filled = STATION_INFO_INACTIVE_TIME |
303 STATION_INFO_RX_BYTES |
304 STATION_INFO_TX_BYTES;
305
306 sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
307 sinfo->rx_bytes = sta->rx_bytes;
308 sinfo->tx_bytes = sta->tx_bytes;
309
Johannes Berg902acc72008-02-23 15:17:19 +0100310 if (ieee80211_vif_is_mesh(&sdata->vif)) {
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100311#ifdef CONFIG_MAC80211_MESH
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100312 sinfo->filled |= STATION_INFO_LLID |
313 STATION_INFO_PLID |
314 STATION_INFO_PLINK_STATE;
315
316 sinfo->llid = le16_to_cpu(sta->llid);
317 sinfo->plid = le16_to_cpu(sta->plid);
318 sinfo->plink_state = sta->plink_state;
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100319#endif
Johannes Berg902acc72008-02-23 15:17:19 +0100320 }
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100321}
322
323
324static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
325 int idx, u8 *mac, struct station_info *sinfo)
326{
327 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
328 struct sta_info *sta;
Johannes Bergd0709a62008-02-25 16:27:46 +0100329 int ret = -ENOENT;
330
331 rcu_read_lock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100332
333 sta = sta_info_get_by_idx(local, idx, dev);
Johannes Bergd0709a62008-02-25 16:27:46 +0100334 if (sta) {
335 ret = 0;
336 memcpy(mac, sta->addr, ETH_ALEN);
337 sta_set_sinfo(sta, sinfo);
338 }
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100339
Johannes Bergd0709a62008-02-25 16:27:46 +0100340 rcu_read_unlock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100341
Johannes Bergd0709a62008-02-25 16:27:46 +0100342 return ret;
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100343}
344
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100345static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
Luis Carlos Cobo2ec600d2008-02-23 15:17:06 +0100346 u8 *mac, struct station_info *sinfo)
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100347{
348 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
349 struct sta_info *sta;
Johannes Bergd0709a62008-02-25 16:27:46 +0100350 int ret = -ENOENT;
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100351
Johannes Bergd0709a62008-02-25 16:27:46 +0100352 rcu_read_lock();
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100353
354 /* XXX: verify sta->dev == dev */
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100355
Johannes Bergd0709a62008-02-25 16:27:46 +0100356 sta = sta_info_get(local, mac);
357 if (sta) {
358 ret = 0;
359 sta_set_sinfo(sta, sinfo);
360 }
361
362 rcu_read_unlock();
363
364 return ret;
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100365}
366
Johannes Berg5dfdaf52007-12-19 02:03:33 +0100367/*
368 * This handles both adding a beacon and setting new beacon info
369 */
370static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
371 struct beacon_parameters *params)
372{
373 struct beacon_data *new, *old;
374 int new_head_len, new_tail_len;
375 int size;
376 int err = -EINVAL;
377
378 old = sdata->u.ap.beacon;
379
380 /* head must not be zero-length */
381 if (params->head && !params->head_len)
382 return -EINVAL;
383
384 /*
385 * This is a kludge. beacon interval should really be part
386 * of the beacon information.
387 */
388 if (params->interval) {
389 sdata->local->hw.conf.beacon_int = params->interval;
390 if (ieee80211_hw_config(sdata->local))
391 return -EINVAL;
392 /*
393 * We updated some parameter so if below bails out
394 * it's not an error.
395 */
396 err = 0;
397 }
398
399 /* Need to have a beacon head if we don't have one yet */
400 if (!params->head && !old)
401 return err;
402
403 /* sorry, no way to start beaconing without dtim period */
404 if (!params->dtim_period && !old)
405 return err;
406
407 /* new or old head? */
408 if (params->head)
409 new_head_len = params->head_len;
410 else
411 new_head_len = old->head_len;
412
413 /* new or old tail? */
414 if (params->tail || !old)
415 /* params->tail_len will be zero for !params->tail */
416 new_tail_len = params->tail_len;
417 else
418 new_tail_len = old->tail_len;
419
420 size = sizeof(*new) + new_head_len + new_tail_len;
421
422 new = kzalloc(size, GFP_KERNEL);
423 if (!new)
424 return -ENOMEM;
425
426 /* start filling the new info now */
427
428 /* new or old dtim period? */
429 if (params->dtim_period)
430 new->dtim_period = params->dtim_period;
431 else
432 new->dtim_period = old->dtim_period;
433
434 /*
435 * pointers go into the block we allocated,
436 * memory is | beacon_data | head | tail |
437 */
438 new->head = ((u8 *) new) + sizeof(*new);
439 new->tail = new->head + new_head_len;
440 new->head_len = new_head_len;
441 new->tail_len = new_tail_len;
442
443 /* copy in head */
444 if (params->head)
445 memcpy(new->head, params->head, new_head_len);
446 else
447 memcpy(new->head, old->head, new_head_len);
448
449 /* copy in optional tail */
450 if (params->tail)
451 memcpy(new->tail, params->tail, new_tail_len);
452 else
453 if (old)
454 memcpy(new->tail, old->tail, new_tail_len);
455
456 rcu_assign_pointer(sdata->u.ap.beacon, new);
457
458 synchronize_rcu();
459
460 kfree(old);
461
462 return ieee80211_if_config_beacon(sdata->dev);
463}
464
465static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
466 struct beacon_parameters *params)
467{
468 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
469 struct beacon_data *old;
470
471 if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
472 return -EINVAL;
473
474 old = sdata->u.ap.beacon;
475
476 if (old)
477 return -EALREADY;
478
479 return ieee80211_config_beacon(sdata, params);
480}
481
482static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
483 struct beacon_parameters *params)
484{
485 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
486 struct beacon_data *old;
487
488 if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
489 return -EINVAL;
490
491 old = sdata->u.ap.beacon;
492
493 if (!old)
494 return -ENOENT;
495
496 return ieee80211_config_beacon(sdata, params);
497}
498
499static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
500{
501 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
502 struct beacon_data *old;
503
504 if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
505 return -EINVAL;
506
507 old = sdata->u.ap.beacon;
508
509 if (!old)
510 return -ENOENT;
511
512 rcu_assign_pointer(sdata->u.ap.beacon, NULL);
513 synchronize_rcu();
514 kfree(old);
515
516 return ieee80211_if_config_beacon(dev);
517}
518
Johannes Berg4fd69312007-12-19 02:03:35 +0100519/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
520struct iapp_layer2_update {
521 u8 da[ETH_ALEN]; /* broadcast */
522 u8 sa[ETH_ALEN]; /* STA addr */
523 __be16 len; /* 6 */
524 u8 dsap; /* 0 */
525 u8 ssap; /* 0 */
526 u8 control;
527 u8 xid_info[3];
528} __attribute__ ((packed));
529
530static void ieee80211_send_layer2_update(struct sta_info *sta)
531{
532 struct iapp_layer2_update *msg;
533 struct sk_buff *skb;
534
535 /* Send Level 2 Update Frame to update forwarding tables in layer 2
536 * bridge devices */
537
538 skb = dev_alloc_skb(sizeof(*msg));
539 if (!skb)
540 return;
541 msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg));
542
543 /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
544 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
545
546 memset(msg->da, 0xff, ETH_ALEN);
547 memcpy(msg->sa, sta->addr, ETH_ALEN);
548 msg->len = htons(6);
549 msg->dsap = 0;
550 msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
551 msg->control = 0xaf; /* XID response lsb.1111F101.
552 * F=0 (no poll command; unsolicited frame) */
553 msg->xid_info[0] = 0x81; /* XID format identifier */
554 msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
555 msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
556
Johannes Bergd0709a62008-02-25 16:27:46 +0100557 skb->dev = sta->sdata->dev;
558 skb->protocol = eth_type_trans(skb, sta->sdata->dev);
Johannes Berg4fd69312007-12-19 02:03:35 +0100559 memset(skb->cb, 0, sizeof(skb->cb));
560 netif_rx(skb);
561}
562
563static void sta_apply_parameters(struct ieee80211_local *local,
564 struct sta_info *sta,
565 struct station_parameters *params)
566{
567 u32 rates;
568 int i, j;
Johannes Berg8318d782008-01-24 19:38:38 +0100569 struct ieee80211_supported_band *sband;
Johannes Bergd0709a62008-02-25 16:27:46 +0100570 struct ieee80211_sub_if_data *sdata = sta->sdata;
Johannes Berg4fd69312007-12-19 02:03:35 +0100571
Johannes Berg73651ee2008-02-25 16:27:47 +0100572 /*
573 * FIXME: updating the flags is racy when this function is
574 * called from ieee80211_change_station(), this will
575 * be resolved in a future patch.
576 */
577
Johannes Berg4fd69312007-12-19 02:03:35 +0100578 if (params->station_flags & STATION_FLAG_CHANGED) {
579 sta->flags &= ~WLAN_STA_AUTHORIZED;
580 if (params->station_flags & STATION_FLAG_AUTHORIZED)
581 sta->flags |= WLAN_STA_AUTHORIZED;
582
583 sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
584 if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
585 sta->flags |= WLAN_STA_SHORT_PREAMBLE;
586
587 sta->flags &= ~WLAN_STA_WME;
588 if (params->station_flags & STATION_FLAG_WME)
589 sta->flags |= WLAN_STA_WME;
590 }
591
Johannes Berg73651ee2008-02-25 16:27:47 +0100592 /*
593 * FIXME: updating the following information is racy when this
594 * function is called from ieee80211_change_station().
595 * However, all this information should be static so
596 * maybe we should just reject attemps to change it.
597 */
598
Johannes Berg4fd69312007-12-19 02:03:35 +0100599 if (params->aid) {
600 sta->aid = params->aid;
601 if (sta->aid > IEEE80211_MAX_AID)
602 sta->aid = 0; /* XXX: should this be an error? */
603 }
604
605 if (params->listen_interval >= 0)
606 sta->listen_interval = params->listen_interval;
607
608 if (params->supported_rates) {
609 rates = 0;
Johannes Berg8318d782008-01-24 19:38:38 +0100610 sband = local->hw.wiphy->bands[local->oper_channel->band];
611
Johannes Berg4fd69312007-12-19 02:03:35 +0100612 for (i = 0; i < params->supported_rates_len; i++) {
613 int rate = (params->supported_rates[i] & 0x7f) * 5;
Johannes Berg8318d782008-01-24 19:38:38 +0100614 for (j = 0; j < sband->n_bitrates; j++) {
615 if (sband->bitrates[j].bitrate == rate)
Johannes Berg4fd69312007-12-19 02:03:35 +0100616 rates |= BIT(j);
617 }
618 }
Johannes Berg8318d782008-01-24 19:38:38 +0100619 sta->supp_rates[local->oper_channel->band] = rates;
Johannes Berg4fd69312007-12-19 02:03:35 +0100620 }
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100621
Johannes Berg902acc72008-02-23 15:17:19 +0100622 if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100623 switch (params->plink_action) {
624 case PLINK_ACTION_OPEN:
625 mesh_plink_open(sta);
626 break;
627 case PLINK_ACTION_BLOCK:
628 mesh_plink_block(sta);
629 break;
630 }
Johannes Berg902acc72008-02-23 15:17:19 +0100631 }
Johannes Berg4fd69312007-12-19 02:03:35 +0100632}
633
634static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
635 u8 *mac, struct station_parameters *params)
636{
637 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
638 struct sta_info *sta;
639 struct ieee80211_sub_if_data *sdata;
Johannes Berg73651ee2008-02-25 16:27:47 +0100640 int err;
Johannes Berg4fd69312007-12-19 02:03:35 +0100641
642 /* Prevent a race with changing the rate control algorithm */
643 if (!netif_running(dev))
644 return -ENETDOWN;
645
Johannes Berg4fd69312007-12-19 02:03:35 +0100646 if (params->vlan) {
647 sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
648
649 if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
650 sdata->vif.type != IEEE80211_IF_TYPE_AP)
651 return -EINVAL;
652 } else
653 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
654
Johannes Berg03e44972008-02-27 09:56:40 +0100655 if (compare_ether_addr(mac, dev->dev_addr) == 0)
656 return -EINVAL;
657
658 if (is_multicast_ether_addr(mac))
659 return -EINVAL;
660
661 sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
Johannes Berg73651ee2008-02-25 16:27:47 +0100662 if (!sta)
663 return -ENOMEM;
Johannes Berg4fd69312007-12-19 02:03:35 +0100664
665 sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
666
667 sta_apply_parameters(local, sta, params);
668
669 rate_control_rate_init(sta, local);
670
Johannes Berg73651ee2008-02-25 16:27:47 +0100671 rcu_read_lock();
672
673 err = sta_info_insert(sta);
674 if (err) {
675 sta_info_destroy(sta);
676 rcu_read_unlock();
677 return err;
678 }
679
680 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
681 sdata->vif.type == IEEE80211_IF_TYPE_AP)
682 ieee80211_send_layer2_update(sta);
683
684 rcu_read_unlock();
685
Johannes Berg4fd69312007-12-19 02:03:35 +0100686 return 0;
687}
688
689static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
690 u8 *mac)
691{
Johannes Bergd0709a62008-02-25 16:27:46 +0100692 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
693 struct ieee80211_local *local = sdata->local;
Johannes Berg4fd69312007-12-19 02:03:35 +0100694 struct sta_info *sta;
695
696 if (mac) {
697 /* XXX: get sta belonging to dev */
698 sta = sta_info_get(local, mac);
699 if (!sta)
700 return -ENOENT;
701
Johannes Bergd0709a62008-02-25 16:27:46 +0100702 sta_info_unlink(&sta);
703
704 if (sta) {
705 synchronize_rcu();
706 sta_info_destroy(sta);
707 }
Johannes Berg4fd69312007-12-19 02:03:35 +0100708 } else
Johannes Bergd0709a62008-02-25 16:27:46 +0100709 sta_info_flush(local, sdata);
Johannes Berg4fd69312007-12-19 02:03:35 +0100710
711 return 0;
712}
713
714static int ieee80211_change_station(struct wiphy *wiphy,
715 struct net_device *dev,
716 u8 *mac,
717 struct station_parameters *params)
718{
719 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
720 struct sta_info *sta;
721 struct ieee80211_sub_if_data *vlansdata;
722
723 /* XXX: get sta belonging to dev */
724 sta = sta_info_get(local, mac);
725 if (!sta)
726 return -ENOENT;
727
Johannes Bergd0709a62008-02-25 16:27:46 +0100728 if (params->vlan && params->vlan != sta->sdata->dev) {
Johannes Berg4fd69312007-12-19 02:03:35 +0100729 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
730
731 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
732 vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
733 return -EINVAL;
734
Johannes Bergd0709a62008-02-25 16:27:46 +0100735 sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
Johannes Berg4fd69312007-12-19 02:03:35 +0100736 ieee80211_send_layer2_update(sta);
737 }
738
739 sta_apply_parameters(local, sta, params);
740
Johannes Berg4fd69312007-12-19 02:03:35 +0100741 return 0;
742}
743
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100744#ifdef CONFIG_MAC80211_MESH
745static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
746 u8 *dst, u8 *next_hop)
747{
748 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
749 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
750 struct mesh_path *mpath;
751 struct sta_info *sta;
752 int err;
753
754 if (!netif_running(dev))
755 return -ENETDOWN;
756
757 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
758 return -ENOTSUPP;
759
Johannes Bergd0709a62008-02-25 16:27:46 +0100760 rcu_read_lock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100761 sta = sta_info_get(local, next_hop);
Johannes Bergd0709a62008-02-25 16:27:46 +0100762 if (!sta) {
763 rcu_read_unlock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100764 return -ENOENT;
Johannes Bergd0709a62008-02-25 16:27:46 +0100765 }
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100766
767 err = mesh_path_add(dst, dev);
Johannes Bergd0709a62008-02-25 16:27:46 +0100768 if (err) {
769 rcu_read_unlock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100770 return err;
Johannes Bergd0709a62008-02-25 16:27:46 +0100771 }
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100772
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100773 mpath = mesh_path_lookup(dst, dev);
774 if (!mpath) {
775 rcu_read_unlock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100776 return -ENXIO;
777 }
778 mesh_path_fix_nexthop(mpath, sta);
Johannes Bergd0709a62008-02-25 16:27:46 +0100779
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100780 rcu_read_unlock();
781 return 0;
782}
783
784static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
785 u8 *dst)
786{
787 if (dst)
Luis Carlos Cobocfa22c72008-02-29 15:04:13 -0800788 return mesh_path_del(dst, dev);
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100789
790 mesh_path_flush(dev);
791 return 0;
792}
793
794static int ieee80211_change_mpath(struct wiphy *wiphy,
795 struct net_device *dev,
796 u8 *dst, u8 *next_hop)
797{
798 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
799 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
800 struct mesh_path *mpath;
801 struct sta_info *sta;
802
803 if (!netif_running(dev))
804 return -ENETDOWN;
805
806 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
807 return -ENOTSUPP;
808
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100809 rcu_read_lock();
Johannes Bergd0709a62008-02-25 16:27:46 +0100810
811 sta = sta_info_get(local, next_hop);
812 if (!sta) {
813 rcu_read_unlock();
814 return -ENOENT;
815 }
816
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100817 mpath = mesh_path_lookup(dst, dev);
818 if (!mpath) {
819 rcu_read_unlock();
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100820 return -ENOENT;
821 }
822
823 mesh_path_fix_nexthop(mpath, sta);
Johannes Bergd0709a62008-02-25 16:27:46 +0100824
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100825 rcu_read_unlock();
826 return 0;
827}
828
829static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
830 struct mpath_info *pinfo)
831{
832 if (mpath->next_hop)
833 memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
834 else
835 memset(next_hop, 0, ETH_ALEN);
836
837 pinfo->filled = MPATH_INFO_FRAME_QLEN |
838 MPATH_INFO_DSN |
839 MPATH_INFO_METRIC |
840 MPATH_INFO_EXPTIME |
841 MPATH_INFO_DISCOVERY_TIMEOUT |
842 MPATH_INFO_DISCOVERY_RETRIES |
843 MPATH_INFO_FLAGS;
844
845 pinfo->frame_qlen = mpath->frame_queue.qlen;
846 pinfo->dsn = mpath->dsn;
847 pinfo->metric = mpath->metric;
848 if (time_before(jiffies, mpath->exp_time))
849 pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
850 pinfo->discovery_timeout =
851 jiffies_to_msecs(mpath->discovery_timeout);
852 pinfo->discovery_retries = mpath->discovery_retries;
853 pinfo->flags = 0;
854 if (mpath->flags & MESH_PATH_ACTIVE)
855 pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
856 if (mpath->flags & MESH_PATH_RESOLVING)
857 pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
858 if (mpath->flags & MESH_PATH_DSN_VALID)
859 pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID;
860 if (mpath->flags & MESH_PATH_FIXED)
861 pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
862 if (mpath->flags & MESH_PATH_RESOLVING)
863 pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
864
865 pinfo->flags = mpath->flags;
866}
867
868static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
869 u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
870
871{
872 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
873 struct mesh_path *mpath;
874
875 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
876 return -ENOTSUPP;
877
878 rcu_read_lock();
879 mpath = mesh_path_lookup(dst, dev);
880 if (!mpath) {
881 rcu_read_unlock();
882 return -ENOENT;
883 }
884 memcpy(dst, mpath->dst, ETH_ALEN);
885 mpath_set_pinfo(mpath, next_hop, pinfo);
886 rcu_read_unlock();
887 return 0;
888}
889
890static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
891 int idx, u8 *dst, u8 *next_hop,
892 struct mpath_info *pinfo)
893{
894 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
895 struct mesh_path *mpath;
896
897 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
898 return -ENOTSUPP;
899
900 rcu_read_lock();
901 mpath = mesh_path_lookup_by_idx(idx, dev);
902 if (!mpath) {
903 rcu_read_unlock();
904 return -ENOENT;
905 }
906 memcpy(dst, mpath->dst, ETH_ALEN);
907 mpath_set_pinfo(mpath, next_hop, pinfo);
908 rcu_read_unlock();
909 return 0;
910}
911#endif
912
Jiri Bencf0706e82007-05-05 11:45:53 -0700913struct cfg80211_ops mac80211_config_ops = {
914 .add_virtual_intf = ieee80211_add_iface,
915 .del_virtual_intf = ieee80211_del_iface,
Johannes Berg42613db2007-09-28 21:52:27 +0200916 .change_virtual_intf = ieee80211_change_iface,
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100917 .add_key = ieee80211_add_key,
918 .del_key = ieee80211_del_key,
Johannes Berg62da92f2007-12-19 02:03:31 +0100919 .get_key = ieee80211_get_key,
Johannes Berge8cbb4c2007-12-19 02:03:30 +0100920 .set_default_key = ieee80211_config_default_key,
Johannes Berg5dfdaf52007-12-19 02:03:33 +0100921 .add_beacon = ieee80211_add_beacon,
922 .set_beacon = ieee80211_set_beacon,
923 .del_beacon = ieee80211_del_beacon,
Johannes Berg4fd69312007-12-19 02:03:35 +0100924 .add_station = ieee80211_add_station,
925 .del_station = ieee80211_del_station,
926 .change_station = ieee80211_change_station,
Johannes Berg7bbdd2d2007-12-19 02:03:37 +0100927 .get_station = ieee80211_get_station,
Luis Carlos Coboc5dd9c22008-02-23 15:17:17 +0100928 .dump_station = ieee80211_dump_station,
929#ifdef CONFIG_MAC80211_MESH
930 .add_mpath = ieee80211_add_mpath,
931 .del_mpath = ieee80211_del_mpath,
932 .change_mpath = ieee80211_change_mpath,
933 .get_mpath = ieee80211_get_mpath,
934 .dump_mpath = ieee80211_dump_mpath,
935#endif
Jiri Bencf0706e82007-05-05 11:45:53 -0700936};