diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 436 |
1 files changed, 369 insertions, 67 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 22c9619ba776..8af576c1d2f1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -14,7 +14,8 @@ | |||
14 | #include <net/cfg80211.h> | 14 | #include <net/cfg80211.h> |
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "cfg.h" | 16 | #include "cfg.h" |
17 | #include "ieee80211_rate.h" | 17 | #include "rate.h" |
18 | #include "mesh.h" | ||
18 | 19 | ||
19 | static enum ieee80211_if_types | 20 | static enum ieee80211_if_types |
20 | nl80211_type_to_mac80211_type(enum nl80211_iftype type) | 21 | nl80211_type_to_mac80211_type(enum nl80211_iftype type) |
@@ -28,16 +29,24 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) | |||
28 | return IEEE80211_IF_TYPE_STA; | 29 | return IEEE80211_IF_TYPE_STA; |
29 | case NL80211_IFTYPE_MONITOR: | 30 | case NL80211_IFTYPE_MONITOR: |
30 | return IEEE80211_IF_TYPE_MNTR; | 31 | return IEEE80211_IF_TYPE_MNTR; |
32 | #ifdef CONFIG_MAC80211_MESH | ||
33 | case NL80211_IFTYPE_MESH_POINT: | ||
34 | return IEEE80211_IF_TYPE_MESH_POINT; | ||
35 | #endif | ||
31 | default: | 36 | default: |
32 | return IEEE80211_IF_TYPE_INVALID; | 37 | return IEEE80211_IF_TYPE_INVALID; |
33 | } | 38 | } |
34 | } | 39 | } |
35 | 40 | ||
36 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 41 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
37 | enum nl80211_iftype type) | 42 | enum nl80211_iftype type, u32 *flags, |
43 | struct vif_params *params) | ||
38 | { | 44 | { |
39 | struct ieee80211_local *local = wiphy_priv(wiphy); | 45 | struct ieee80211_local *local = wiphy_priv(wiphy); |
40 | enum ieee80211_if_types itype; | 46 | enum ieee80211_if_types itype; |
47 | struct net_device *dev; | ||
48 | struct ieee80211_sub_if_data *sdata; | ||
49 | int err; | ||
41 | 50 | ||
42 | if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) | 51 | if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) |
43 | return -ENODEV; | 52 | return -ENODEV; |
@@ -46,7 +55,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
46 | if (itype == IEEE80211_IF_TYPE_INVALID) | 55 | if (itype == IEEE80211_IF_TYPE_INVALID) |
47 | return -EINVAL; | 56 | return -EINVAL; |
48 | 57 | ||
49 | return ieee80211_if_add(local->mdev, name, NULL, itype); | 58 | err = ieee80211_if_add(local->mdev, name, &dev, itype, params); |
59 | 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; | ||
50 | } | 65 | } |
51 | 66 | ||
52 | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | 67 | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) |
@@ -69,7 +84,8 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | |||
69 | } | 84 | } |
70 | 85 | ||
71 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 86 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, |
72 | enum nl80211_iftype type) | 87 | enum nl80211_iftype type, u32 *flags, |
88 | struct vif_params *params) | ||
73 | { | 89 | { |
74 | struct ieee80211_local *local = wiphy_priv(wiphy); | 90 | struct ieee80211_local *local = wiphy_priv(wiphy); |
75 | struct net_device *dev; | 91 | struct net_device *dev; |
@@ -99,6 +115,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | |||
99 | ieee80211_if_reinit(dev); | 115 | ieee80211_if_reinit(dev); |
100 | ieee80211_if_set_type(dev, itype); | 116 | ieee80211_if_set_type(dev, itype); |
101 | 117 | ||
118 | 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); | ||
122 | |||
123 | if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) | ||
124 | return 0; | ||
125 | |||
126 | sdata->u.mntr_flags = *flags; | ||
102 | return 0; | 127 | return 0; |
103 | } | 128 | } |
104 | 129 | ||
@@ -109,7 +134,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
109 | struct ieee80211_sub_if_data *sdata; | 134 | struct ieee80211_sub_if_data *sdata; |
110 | struct sta_info *sta = NULL; | 135 | struct sta_info *sta = NULL; |
111 | enum ieee80211_key_alg alg; | 136 | enum ieee80211_key_alg alg; |
112 | int ret; | 137 | struct ieee80211_key *key; |
138 | int err; | ||
113 | 139 | ||
114 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 140 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
115 | 141 | ||
@@ -128,21 +154,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
128 | return -EINVAL; | 154 | return -EINVAL; |
129 | } | 155 | } |
130 | 156 | ||
157 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | ||
158 | if (!key) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | rcu_read_lock(); | ||
162 | |||
131 | if (mac_addr) { | 163 | if (mac_addr) { |
132 | sta = sta_info_get(sdata->local, mac_addr); | 164 | sta = sta_info_get(sdata->local, mac_addr); |
133 | if (!sta) | 165 | if (!sta) { |
134 | return -ENOENT; | 166 | ieee80211_key_free(key); |
167 | err = -ENOENT; | ||
168 | goto out_unlock; | ||
169 | } | ||
135 | } | 170 | } |
136 | 171 | ||
137 | ret = 0; | 172 | ieee80211_key_link(key, sdata, sta); |
138 | if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, | ||
139 | params->key_len, params->key)) | ||
140 | ret = -ENOMEM; | ||
141 | 173 | ||
142 | if (sta) | 174 | err = 0; |
143 | sta_info_put(sta); | 175 | out_unlock: |
176 | rcu_read_unlock(); | ||
144 | 177 | ||
145 | return ret; | 178 | return err; |
146 | } | 179 | } |
147 | 180 | ||
148 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 181 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -154,27 +187,37 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
154 | 187 | ||
155 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 188 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
156 | 189 | ||
190 | rcu_read_lock(); | ||
191 | |||
157 | if (mac_addr) { | 192 | if (mac_addr) { |
193 | ret = -ENOENT; | ||
194 | |||
158 | sta = sta_info_get(sdata->local, mac_addr); | 195 | sta = sta_info_get(sdata->local, mac_addr); |
159 | if (!sta) | 196 | if (!sta) |
160 | return -ENOENT; | 197 | goto out_unlock; |
161 | 198 | ||
162 | ret = 0; | 199 | if (sta->key) { |
163 | if (sta->key) | ||
164 | ieee80211_key_free(sta->key); | 200 | ieee80211_key_free(sta->key); |
165 | else | 201 | WARN_ON(sta->key); |
166 | ret = -ENOENT; | 202 | ret = 0; |
203 | } | ||
167 | 204 | ||
168 | sta_info_put(sta); | 205 | goto out_unlock; |
169 | return ret; | ||
170 | } | 206 | } |
171 | 207 | ||
172 | if (!sdata->keys[key_idx]) | 208 | if (!sdata->keys[key_idx]) { |
173 | return -ENOENT; | 209 | ret = -ENOENT; |
210 | goto out_unlock; | ||
211 | } | ||
174 | 212 | ||
175 | ieee80211_key_free(sdata->keys[key_idx]); | 213 | ieee80211_key_free(sdata->keys[key_idx]); |
214 | WARN_ON(sdata->keys[key_idx]); | ||
176 | 215 | ||
177 | return 0; | 216 | ret = 0; |
217 | out_unlock: | ||
218 | rcu_read_unlock(); | ||
219 | |||
220 | return ret; | ||
178 | } | 221 | } |
179 | 222 | ||
180 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 223 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -191,6 +234,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
191 | u16 iv16; | 234 | u16 iv16; |
192 | int err = -ENOENT; | 235 | int err = -ENOENT; |
193 | 236 | ||
237 | rcu_read_lock(); | ||
238 | |||
194 | if (mac_addr) { | 239 | if (mac_addr) { |
195 | sta = sta_info_get(sdata->local, mac_addr); | 240 | sta = sta_info_get(sdata->local, mac_addr); |
196 | if (!sta) | 241 | if (!sta) |
@@ -254,8 +299,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
254 | err = 0; | 299 | err = 0; |
255 | 300 | ||
256 | out: | 301 | out: |
257 | if (sta) | 302 | rcu_read_unlock(); |
258 | sta_info_put(sta); | ||
259 | return err; | 303 | return err; |
260 | } | 304 | } |
261 | 305 | ||
@@ -265,35 +309,83 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
265 | { | 309 | { |
266 | struct ieee80211_sub_if_data *sdata; | 310 | struct ieee80211_sub_if_data *sdata; |
267 | 311 | ||
312 | rcu_read_lock(); | ||
313 | |||
268 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 314 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
269 | ieee80211_set_default_key(sdata, key_idx); | 315 | ieee80211_set_default_key(sdata, key_idx); |
270 | 316 | ||
317 | rcu_read_unlock(); | ||
318 | |||
271 | return 0; | 319 | return 0; |
272 | } | 320 | } |
273 | 321 | ||
322 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
323 | { | ||
324 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
325 | |||
326 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
327 | STATION_INFO_RX_BYTES | | ||
328 | STATION_INFO_TX_BYTES; | ||
329 | |||
330 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
331 | sinfo->rx_bytes = sta->rx_bytes; | ||
332 | sinfo->tx_bytes = sta->tx_bytes; | ||
333 | |||
334 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
335 | #ifdef CONFIG_MAC80211_MESH | ||
336 | sinfo->filled |= STATION_INFO_LLID | | ||
337 | STATION_INFO_PLID | | ||
338 | STATION_INFO_PLINK_STATE; | ||
339 | |||
340 | sinfo->llid = le16_to_cpu(sta->llid); | ||
341 | sinfo->plid = le16_to_cpu(sta->plid); | ||
342 | sinfo->plink_state = sta->plink_state; | ||
343 | #endif | ||
344 | } | ||
345 | } | ||
346 | |||
347 | |||
348 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | ||
349 | int idx, u8 *mac, struct station_info *sinfo) | ||
350 | { | ||
351 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
352 | struct sta_info *sta; | ||
353 | int ret = -ENOENT; | ||
354 | |||
355 | rcu_read_lock(); | ||
356 | |||
357 | sta = sta_info_get_by_idx(local, idx, dev); | ||
358 | if (sta) { | ||
359 | ret = 0; | ||
360 | memcpy(mac, sta->addr, ETH_ALEN); | ||
361 | sta_set_sinfo(sta, sinfo); | ||
362 | } | ||
363 | |||
364 | rcu_read_unlock(); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
274 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 369 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
275 | u8 *mac, struct station_stats *stats) | 370 | u8 *mac, struct station_info *sinfo) |
276 | { | 371 | { |
277 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 372 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
278 | struct sta_info *sta; | 373 | struct sta_info *sta; |
374 | int ret = -ENOENT; | ||
279 | 375 | ||
280 | sta = sta_info_get(local, mac); | 376 | rcu_read_lock(); |
281 | if (!sta) | ||
282 | return -ENOENT; | ||
283 | 377 | ||
284 | /* XXX: verify sta->dev == dev */ | 378 | /* XXX: verify sta->dev == dev */ |
285 | 379 | ||
286 | stats->filled = STATION_STAT_INACTIVE_TIME | | 380 | sta = sta_info_get(local, mac); |
287 | STATION_STAT_RX_BYTES | | 381 | if (sta) { |
288 | STATION_STAT_TX_BYTES; | 382 | ret = 0; |
289 | 383 | sta_set_sinfo(sta, sinfo); | |
290 | stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 384 | } |
291 | stats->rx_bytes = sta->rx_bytes; | ||
292 | stats->tx_bytes = sta->tx_bytes; | ||
293 | 385 | ||
294 | sta_info_put(sta); | 386 | rcu_read_unlock(); |
295 | 387 | ||
296 | return 0; | 388 | return ret; |
297 | } | 389 | } |
298 | 390 | ||
299 | /* | 391 | /* |
@@ -486,8 +578,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
486 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ | 578 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ |
487 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ | 579 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ |
488 | 580 | ||
489 | skb->dev = sta->dev; | 581 | skb->dev = sta->sdata->dev; |
490 | skb->protocol = eth_type_trans(skb, sta->dev); | 582 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
491 | memset(skb->cb, 0, sizeof(skb->cb)); | 583 | memset(skb->cb, 0, sizeof(skb->cb)); |
492 | netif_rx(skb); | 584 | netif_rx(skb); |
493 | } | 585 | } |
@@ -498,7 +590,14 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
498 | { | 590 | { |
499 | u32 rates; | 591 | u32 rates; |
500 | int i, j; | 592 | int i, j; |
501 | struct ieee80211_hw_mode *mode; | 593 | struct ieee80211_supported_band *sband; |
594 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
595 | |||
596 | /* | ||
597 | * FIXME: updating the flags is racy when this function is | ||
598 | * called from ieee80211_change_station(), this will | ||
599 | * be resolved in a future patch. | ||
600 | */ | ||
502 | 601 | ||
503 | if (params->station_flags & STATION_FLAG_CHANGED) { | 602 | if (params->station_flags & STATION_FLAG_CHANGED) { |
504 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 603 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
@@ -514,6 +613,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
514 | sta->flags |= WLAN_STA_WME; | 613 | sta->flags |= WLAN_STA_WME; |
515 | } | 614 | } |
516 | 615 | ||
616 | /* | ||
617 | * FIXME: updating the following information is racy when this | ||
618 | * function is called from ieee80211_change_station(). | ||
619 | * However, all this information should be static so | ||
620 | * maybe we should just reject attemps to change it. | ||
621 | */ | ||
622 | |||
517 | if (params->aid) { | 623 | if (params->aid) { |
518 | sta->aid = params->aid; | 624 | sta->aid = params->aid; |
519 | if (sta->aid > IEEE80211_MAX_AID) | 625 | if (sta->aid > IEEE80211_MAX_AID) |
@@ -525,15 +631,27 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
525 | 631 | ||
526 | if (params->supported_rates) { | 632 | if (params->supported_rates) { |
527 | rates = 0; | 633 | rates = 0; |
528 | mode = local->oper_hw_mode; | 634 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
635 | |||
529 | for (i = 0; i < params->supported_rates_len; i++) { | 636 | for (i = 0; i < params->supported_rates_len; i++) { |
530 | int rate = (params->supported_rates[i] & 0x7f) * 5; | 637 | int rate = (params->supported_rates[i] & 0x7f) * 5; |
531 | for (j = 0; j < mode->num_rates; j++) { | 638 | for (j = 0; j < sband->n_bitrates; j++) { |
532 | if (mode->rates[j].rate == rate) | 639 | if (sband->bitrates[j].bitrate == rate) |
533 | rates |= BIT(j); | 640 | rates |= BIT(j); |
534 | } | 641 | } |
535 | } | 642 | } |
536 | sta->supp_rates = rates; | 643 | sta->supp_rates[local->oper_channel->band] = rates; |
644 | } | ||
645 | |||
646 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | ||
647 | switch (params->plink_action) { | ||
648 | case PLINK_ACTION_OPEN: | ||
649 | mesh_plink_open(sta); | ||
650 | break; | ||
651 | case PLINK_ACTION_BLOCK: | ||
652 | mesh_plink_block(sta); | ||
653 | break; | ||
654 | } | ||
537 | } | 655 | } |
538 | } | 656 | } |
539 | 657 | ||
@@ -543,18 +661,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
543 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 661 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
544 | struct sta_info *sta; | 662 | struct sta_info *sta; |
545 | struct ieee80211_sub_if_data *sdata; | 663 | struct ieee80211_sub_if_data *sdata; |
664 | int err; | ||
546 | 665 | ||
547 | /* Prevent a race with changing the rate control algorithm */ | 666 | /* Prevent a race with changing the rate control algorithm */ |
548 | if (!netif_running(dev)) | 667 | if (!netif_running(dev)) |
549 | return -ENETDOWN; | 668 | return -ENETDOWN; |
550 | 669 | ||
551 | /* XXX: get sta belonging to dev */ | ||
552 | sta = sta_info_get(local, mac); | ||
553 | if (sta) { | ||
554 | sta_info_put(sta); | ||
555 | return -EEXIST; | ||
556 | } | ||
557 | |||
558 | if (params->vlan) { | 670 | if (params->vlan) { |
559 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 671 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
560 | 672 | ||
@@ -564,22 +676,36 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
564 | } else | 676 | } else |
565 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 677 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
566 | 678 | ||
567 | sta = sta_info_add(local, dev, mac, GFP_KERNEL); | 679 | if (compare_ether_addr(mac, dev->dev_addr) == 0) |
680 | return -EINVAL; | ||
681 | |||
682 | if (is_multicast_ether_addr(mac)) | ||
683 | return -EINVAL; | ||
684 | |||
685 | sta = sta_info_alloc(sdata, mac, GFP_KERNEL); | ||
568 | if (!sta) | 686 | if (!sta) |
569 | return -ENOMEM; | 687 | return -ENOMEM; |
570 | 688 | ||
571 | sta->dev = sdata->dev; | ||
572 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | ||
573 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
574 | ieee80211_send_layer2_update(sta); | ||
575 | |||
576 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 689 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; |
577 | 690 | ||
578 | sta_apply_parameters(local, sta, params); | 691 | sta_apply_parameters(local, sta, params); |
579 | 692 | ||
580 | rate_control_rate_init(sta, local); | 693 | rate_control_rate_init(sta, local); |
581 | 694 | ||
582 | sta_info_put(sta); | 695 | rcu_read_lock(); |
696 | |||
697 | err = sta_info_insert(sta); | ||
698 | if (err) { | ||
699 | /* STA has been freed */ | ||
700 | rcu_read_unlock(); | ||
701 | return err; | ||
702 | } | ||
703 | |||
704 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | ||
705 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
706 | ieee80211_send_layer2_update(sta); | ||
707 | |||
708 | rcu_read_unlock(); | ||
583 | 709 | ||
584 | return 0; | 710 | return 0; |
585 | } | 711 | } |
@@ -587,7 +713,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
587 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 713 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
588 | u8 *mac) | 714 | u8 *mac) |
589 | { | 715 | { |
590 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 716 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
717 | struct ieee80211_local *local = sdata->local; | ||
591 | struct sta_info *sta; | 718 | struct sta_info *sta; |
592 | 719 | ||
593 | if (mac) { | 720 | if (mac) { |
@@ -596,10 +723,10 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
596 | if (!sta) | 723 | if (!sta) |
597 | return -ENOENT; | 724 | return -ENOENT; |
598 | 725 | ||
599 | sta_info_free(sta); | 726 | sta_info_unlink(&sta); |
600 | sta_info_put(sta); | 727 | sta_info_destroy(sta); |
601 | } else | 728 | } else |
602 | sta_info_flush(local, dev); | 729 | sta_info_flush(local, sdata); |
603 | 730 | ||
604 | return 0; | 731 | return 0; |
605 | } | 732 | } |
@@ -618,23 +745,190 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
618 | if (!sta) | 745 | if (!sta) |
619 | return -ENOENT; | 746 | return -ENOENT; |
620 | 747 | ||
621 | if (params->vlan && params->vlan != sta->dev) { | 748 | if (params->vlan && params->vlan != sta->sdata->dev) { |
622 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 749 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
623 | 750 | ||
624 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || | 751 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || |
625 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) | 752 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) |
626 | return -EINVAL; | 753 | return -EINVAL; |
627 | 754 | ||
628 | sta->dev = params->vlan; | 755 | sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
629 | ieee80211_send_layer2_update(sta); | 756 | ieee80211_send_layer2_update(sta); |
630 | } | 757 | } |
631 | 758 | ||
632 | sta_apply_parameters(local, sta, params); | 759 | sta_apply_parameters(local, sta, params); |
633 | 760 | ||
634 | sta_info_put(sta); | 761 | return 0; |
762 | } | ||
763 | |||
764 | #ifdef CONFIG_MAC80211_MESH | ||
765 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
766 | u8 *dst, u8 *next_hop) | ||
767 | { | ||
768 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
769 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
770 | struct mesh_path *mpath; | ||
771 | struct sta_info *sta; | ||
772 | int err; | ||
773 | |||
774 | if (!netif_running(dev)) | ||
775 | return -ENETDOWN; | ||
776 | |||
777 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
778 | return -ENOTSUPP; | ||
779 | |||
780 | rcu_read_lock(); | ||
781 | sta = sta_info_get(local, next_hop); | ||
782 | if (!sta) { | ||
783 | rcu_read_unlock(); | ||
784 | return -ENOENT; | ||
785 | } | ||
786 | |||
787 | err = mesh_path_add(dst, dev); | ||
788 | if (err) { | ||
789 | rcu_read_unlock(); | ||
790 | return err; | ||
791 | } | ||
792 | |||
793 | mpath = mesh_path_lookup(dst, dev); | ||
794 | if (!mpath) { | ||
795 | rcu_read_unlock(); | ||
796 | return -ENXIO; | ||
797 | } | ||
798 | mesh_path_fix_nexthop(mpath, sta); | ||
799 | |||
800 | rcu_read_unlock(); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
805 | u8 *dst) | ||
806 | { | ||
807 | if (dst) | ||
808 | return mesh_path_del(dst, dev); | ||
809 | |||
810 | mesh_path_flush(dev); | ||
811 | return 0; | ||
812 | } | ||
635 | 813 | ||
814 | static int ieee80211_change_mpath(struct wiphy *wiphy, | ||
815 | struct net_device *dev, | ||
816 | u8 *dst, u8 *next_hop) | ||
817 | { | ||
818 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
819 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
820 | struct mesh_path *mpath; | ||
821 | struct sta_info *sta; | ||
822 | |||
823 | if (!netif_running(dev)) | ||
824 | return -ENETDOWN; | ||
825 | |||
826 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
827 | return -ENOTSUPP; | ||
828 | |||
829 | rcu_read_lock(); | ||
830 | |||
831 | sta = sta_info_get(local, next_hop); | ||
832 | if (!sta) { | ||
833 | rcu_read_unlock(); | ||
834 | return -ENOENT; | ||
835 | } | ||
836 | |||
837 | mpath = mesh_path_lookup(dst, dev); | ||
838 | if (!mpath) { | ||
839 | rcu_read_unlock(); | ||
840 | return -ENOENT; | ||
841 | } | ||
842 | |||
843 | mesh_path_fix_nexthop(mpath, sta); | ||
844 | |||
845 | rcu_read_unlock(); | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | ||
850 | struct mpath_info *pinfo) | ||
851 | { | ||
852 | if (mpath->next_hop) | ||
853 | memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN); | ||
854 | else | ||
855 | memset(next_hop, 0, ETH_ALEN); | ||
856 | |||
857 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | ||
858 | MPATH_INFO_DSN | | ||
859 | MPATH_INFO_METRIC | | ||
860 | MPATH_INFO_EXPTIME | | ||
861 | MPATH_INFO_DISCOVERY_TIMEOUT | | ||
862 | MPATH_INFO_DISCOVERY_RETRIES | | ||
863 | MPATH_INFO_FLAGS; | ||
864 | |||
865 | pinfo->frame_qlen = mpath->frame_queue.qlen; | ||
866 | pinfo->dsn = mpath->dsn; | ||
867 | pinfo->metric = mpath->metric; | ||
868 | if (time_before(jiffies, mpath->exp_time)) | ||
869 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | ||
870 | pinfo->discovery_timeout = | ||
871 | jiffies_to_msecs(mpath->discovery_timeout); | ||
872 | pinfo->discovery_retries = mpath->discovery_retries; | ||
873 | pinfo->flags = 0; | ||
874 | if (mpath->flags & MESH_PATH_ACTIVE) | ||
875 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | ||
876 | if (mpath->flags & MESH_PATH_RESOLVING) | ||
877 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | ||
878 | if (mpath->flags & MESH_PATH_DSN_VALID) | ||
879 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | ||
880 | if (mpath->flags & MESH_PATH_FIXED) | ||
881 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | ||
882 | if (mpath->flags & MESH_PATH_RESOLVING) | ||
883 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | ||
884 | |||
885 | pinfo->flags = mpath->flags; | ||
886 | } | ||
887 | |||
888 | static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
889 | u8 *dst, u8 *next_hop, struct mpath_info *pinfo) | ||
890 | |||
891 | { | ||
892 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
893 | struct mesh_path *mpath; | ||
894 | |||
895 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
896 | return -ENOTSUPP; | ||
897 | |||
898 | rcu_read_lock(); | ||
899 | mpath = mesh_path_lookup(dst, dev); | ||
900 | if (!mpath) { | ||
901 | rcu_read_unlock(); | ||
902 | return -ENOENT; | ||
903 | } | ||
904 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
905 | mpath_set_pinfo(mpath, next_hop, pinfo); | ||
906 | rcu_read_unlock(); | ||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
911 | int idx, u8 *dst, u8 *next_hop, | ||
912 | struct mpath_info *pinfo) | ||
913 | { | ||
914 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
915 | struct mesh_path *mpath; | ||
916 | |||
917 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | ||
918 | return -ENOTSUPP; | ||
919 | |||
920 | rcu_read_lock(); | ||
921 | mpath = mesh_path_lookup_by_idx(idx, dev); | ||
922 | if (!mpath) { | ||
923 | rcu_read_unlock(); | ||
924 | return -ENOENT; | ||
925 | } | ||
926 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
927 | mpath_set_pinfo(mpath, next_hop, pinfo); | ||
928 | rcu_read_unlock(); | ||
636 | return 0; | 929 | return 0; |
637 | } | 930 | } |
931 | #endif | ||
638 | 932 | ||
639 | struct cfg80211_ops mac80211_config_ops = { | 933 | struct cfg80211_ops mac80211_config_ops = { |
640 | .add_virtual_intf = ieee80211_add_iface, | 934 | .add_virtual_intf = ieee80211_add_iface, |
@@ -651,4 +945,12 @@ struct cfg80211_ops mac80211_config_ops = { | |||
651 | .del_station = ieee80211_del_station, | 945 | .del_station = ieee80211_del_station, |
652 | .change_station = ieee80211_change_station, | 946 | .change_station = ieee80211_change_station, |
653 | .get_station = ieee80211_get_station, | 947 | .get_station = ieee80211_get_station, |
948 | .dump_station = ieee80211_dump_station, | ||
949 | #ifdef CONFIG_MAC80211_MESH | ||
950 | .add_mpath = ieee80211_add_mpath, | ||
951 | .del_mpath = ieee80211_del_mpath, | ||
952 | .change_mpath = ieee80211_change_mpath, | ||
953 | .get_mpath = ieee80211_get_mpath, | ||
954 | .dump_mpath = ieee80211_dump_mpath, | ||
955 | #endif | ||
654 | }; | 956 | }; |