diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 400 |
1 files changed, 341 insertions, 59 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 22c9619ba776..6b183a3526b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -15,6 +15,7 @@ | |||
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 "ieee80211_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,7 @@ 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; |
113 | 138 | ||
114 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 139 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
115 | 140 | ||
@@ -128,21 +153,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
128 | return -EINVAL; | 153 | return -EINVAL; |
129 | } | 154 | } |
130 | 155 | ||
156 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | ||
157 | if (!key) | ||
158 | return -ENOMEM; | ||
159 | |||
131 | if (mac_addr) { | 160 | if (mac_addr) { |
132 | sta = sta_info_get(sdata->local, mac_addr); | 161 | sta = sta_info_get(sdata->local, mac_addr); |
133 | if (!sta) | 162 | if (!sta) { |
163 | ieee80211_key_free(key); | ||
134 | return -ENOENT; | 164 | return -ENOENT; |
165 | } | ||
135 | } | 166 | } |
136 | 167 | ||
137 | ret = 0; | 168 | 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 | |||
142 | if (sta) | ||
143 | sta_info_put(sta); | ||
144 | 169 | ||
145 | return ret; | 170 | return 0; |
146 | } | 171 | } |
147 | 172 | ||
148 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 173 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -160,12 +185,12 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
160 | return -ENOENT; | 185 | return -ENOENT; |
161 | 186 | ||
162 | ret = 0; | 187 | ret = 0; |
163 | if (sta->key) | 188 | if (sta->key) { |
164 | ieee80211_key_free(sta->key); | 189 | ieee80211_key_free(sta->key); |
165 | else | 190 | WARN_ON(sta->key); |
191 | } else | ||
166 | ret = -ENOENT; | 192 | ret = -ENOENT; |
167 | 193 | ||
168 | sta_info_put(sta); | ||
169 | return ret; | 194 | return ret; |
170 | } | 195 | } |
171 | 196 | ||
@@ -173,6 +198,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
173 | return -ENOENT; | 198 | return -ENOENT; |
174 | 199 | ||
175 | ieee80211_key_free(sdata->keys[key_idx]); | 200 | ieee80211_key_free(sdata->keys[key_idx]); |
201 | WARN_ON(sdata->keys[key_idx]); | ||
176 | 202 | ||
177 | return 0; | 203 | return 0; |
178 | } | 204 | } |
@@ -254,8 +280,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
254 | err = 0; | 280 | err = 0; |
255 | 281 | ||
256 | out: | 282 | out: |
257 | if (sta) | ||
258 | sta_info_put(sta); | ||
259 | return err; | 283 | return err; |
260 | } | 284 | } |
261 | 285 | ||
@@ -271,29 +295,73 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
271 | return 0; | 295 | return 0; |
272 | } | 296 | } |
273 | 297 | ||
298 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
299 | { | ||
300 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
301 | |||
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 | |||
310 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
311 | #ifdef CONFIG_MAC80211_MESH | ||
312 | 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; | ||
319 | #endif | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
324 | static 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; | ||
329 | int ret = -ENOENT; | ||
330 | |||
331 | rcu_read_lock(); | ||
332 | |||
333 | sta = sta_info_get_by_idx(local, idx, dev); | ||
334 | if (sta) { | ||
335 | ret = 0; | ||
336 | memcpy(mac, sta->addr, ETH_ALEN); | ||
337 | sta_set_sinfo(sta, sinfo); | ||
338 | } | ||
339 | |||
340 | rcu_read_unlock(); | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
274 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 345 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
275 | u8 *mac, struct station_stats *stats) | 346 | u8 *mac, struct station_info *sinfo) |
276 | { | 347 | { |
277 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 348 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
278 | struct sta_info *sta; | 349 | struct sta_info *sta; |
350 | int ret = -ENOENT; | ||
279 | 351 | ||
280 | sta = sta_info_get(local, mac); | 352 | rcu_read_lock(); |
281 | if (!sta) | ||
282 | return -ENOENT; | ||
283 | 353 | ||
284 | /* XXX: verify sta->dev == dev */ | 354 | /* XXX: verify sta->dev == dev */ |
285 | 355 | ||
286 | stats->filled = STATION_STAT_INACTIVE_TIME | | 356 | sta = sta_info_get(local, mac); |
287 | STATION_STAT_RX_BYTES | | 357 | if (sta) { |
288 | STATION_STAT_TX_BYTES; | 358 | ret = 0; |
289 | 359 | sta_set_sinfo(sta, sinfo); | |
290 | stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 360 | } |
291 | stats->rx_bytes = sta->rx_bytes; | ||
292 | stats->tx_bytes = sta->tx_bytes; | ||
293 | 361 | ||
294 | sta_info_put(sta); | 362 | rcu_read_unlock(); |
295 | 363 | ||
296 | return 0; | 364 | return ret; |
297 | } | 365 | } |
298 | 366 | ||
299 | /* | 367 | /* |
@@ -486,8 +554,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
486 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ | 554 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ |
487 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ | 555 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ |
488 | 556 | ||
489 | skb->dev = sta->dev; | 557 | skb->dev = sta->sdata->dev; |
490 | skb->protocol = eth_type_trans(skb, sta->dev); | 558 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
491 | memset(skb->cb, 0, sizeof(skb->cb)); | 559 | memset(skb->cb, 0, sizeof(skb->cb)); |
492 | netif_rx(skb); | 560 | netif_rx(skb); |
493 | } | 561 | } |
@@ -498,7 +566,14 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
498 | { | 566 | { |
499 | u32 rates; | 567 | u32 rates; |
500 | int i, j; | 568 | int i, j; |
501 | struct ieee80211_hw_mode *mode; | 569 | struct ieee80211_supported_band *sband; |
570 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
571 | |||
572 | /* | ||
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 | */ | ||
502 | 577 | ||
503 | if (params->station_flags & STATION_FLAG_CHANGED) { | 578 | if (params->station_flags & STATION_FLAG_CHANGED) { |
504 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 579 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
@@ -514,6 +589,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
514 | sta->flags |= WLAN_STA_WME; | 589 | sta->flags |= WLAN_STA_WME; |
515 | } | 590 | } |
516 | 591 | ||
592 | /* | ||
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 | |||
517 | if (params->aid) { | 599 | if (params->aid) { |
518 | sta->aid = params->aid; | 600 | sta->aid = params->aid; |
519 | if (sta->aid > IEEE80211_MAX_AID) | 601 | if (sta->aid > IEEE80211_MAX_AID) |
@@ -525,15 +607,27 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
525 | 607 | ||
526 | if (params->supported_rates) { | 608 | if (params->supported_rates) { |
527 | rates = 0; | 609 | rates = 0; |
528 | mode = local->oper_hw_mode; | 610 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
611 | |||
529 | for (i = 0; i < params->supported_rates_len; i++) { | 612 | for (i = 0; i < params->supported_rates_len; i++) { |
530 | int rate = (params->supported_rates[i] & 0x7f) * 5; | 613 | int rate = (params->supported_rates[i] & 0x7f) * 5; |
531 | for (j = 0; j < mode->num_rates; j++) { | 614 | for (j = 0; j < sband->n_bitrates; j++) { |
532 | if (mode->rates[j].rate == rate) | 615 | if (sband->bitrates[j].bitrate == rate) |
533 | rates |= BIT(j); | 616 | rates |= BIT(j); |
534 | } | 617 | } |
535 | } | 618 | } |
536 | sta->supp_rates = rates; | 619 | sta->supp_rates[local->oper_channel->band] = rates; |
620 | } | ||
621 | |||
622 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | ||
623 | 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 | } | ||
537 | } | 631 | } |
538 | } | 632 | } |
539 | 633 | ||
@@ -543,18 +637,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
543 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 637 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
544 | struct sta_info *sta; | 638 | struct sta_info *sta; |
545 | struct ieee80211_sub_if_data *sdata; | 639 | struct ieee80211_sub_if_data *sdata; |
640 | int err; | ||
546 | 641 | ||
547 | /* Prevent a race with changing the rate control algorithm */ | 642 | /* Prevent a race with changing the rate control algorithm */ |
548 | if (!netif_running(dev)) | 643 | if (!netif_running(dev)) |
549 | return -ENETDOWN; | 644 | return -ENETDOWN; |
550 | 645 | ||
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) { | 646 | if (params->vlan) { |
559 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 647 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
560 | 648 | ||
@@ -564,22 +652,36 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
564 | } else | 652 | } else |
565 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 653 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
566 | 654 | ||
567 | sta = sta_info_add(local, dev, mac, GFP_KERNEL); | 655 | 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); | ||
568 | if (!sta) | 662 | if (!sta) |
569 | return -ENOMEM; | 663 | return -ENOMEM; |
570 | 664 | ||
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; | 665 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; |
577 | 666 | ||
578 | sta_apply_parameters(local, sta, params); | 667 | sta_apply_parameters(local, sta, params); |
579 | 668 | ||
580 | rate_control_rate_init(sta, local); | 669 | rate_control_rate_init(sta, local); |
581 | 670 | ||
582 | sta_info_put(sta); | 671 | 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(); | ||
583 | 685 | ||
584 | return 0; | 686 | return 0; |
585 | } | 687 | } |
@@ -587,7 +689,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, | 689 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
588 | u8 *mac) | 690 | u8 *mac) |
589 | { | 691 | { |
590 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 692 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
693 | struct ieee80211_local *local = sdata->local; | ||
591 | struct sta_info *sta; | 694 | struct sta_info *sta; |
592 | 695 | ||
593 | if (mac) { | 696 | if (mac) { |
@@ -596,10 +699,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
596 | if (!sta) | 699 | if (!sta) |
597 | return -ENOENT; | 700 | return -ENOENT; |
598 | 701 | ||
599 | sta_info_free(sta); | 702 | sta_info_unlink(&sta); |
600 | sta_info_put(sta); | 703 | |
704 | if (sta) { | ||
705 | synchronize_rcu(); | ||
706 | sta_info_destroy(sta); | ||
707 | } | ||
601 | } else | 708 | } else |
602 | sta_info_flush(local, dev); | 709 | sta_info_flush(local, sdata); |
603 | 710 | ||
604 | return 0; | 711 | return 0; |
605 | } | 712 | } |
@@ -618,23 +725,190 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
618 | if (!sta) | 725 | if (!sta) |
619 | return -ENOENT; | 726 | return -ENOENT; |
620 | 727 | ||
621 | if (params->vlan && params->vlan != sta->dev) { | 728 | if (params->vlan && params->vlan != sta->sdata->dev) { |
622 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 729 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
623 | 730 | ||
624 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || | 731 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || |
625 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) | 732 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) |
626 | return -EINVAL; | 733 | return -EINVAL; |
627 | 734 | ||
628 | sta->dev = params->vlan; | 735 | sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
629 | ieee80211_send_layer2_update(sta); | 736 | ieee80211_send_layer2_update(sta); |
630 | } | 737 | } |
631 | 738 | ||
632 | sta_apply_parameters(local, sta, params); | 739 | sta_apply_parameters(local, sta, params); |
633 | 740 | ||
634 | sta_info_put(sta); | 741 | return 0; |
742 | } | ||
743 | |||
744 | #ifdef CONFIG_MAC80211_MESH | ||
745 | static 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 | |||
760 | rcu_read_lock(); | ||
761 | sta = sta_info_get(local, next_hop); | ||
762 | if (!sta) { | ||
763 | rcu_read_unlock(); | ||
764 | return -ENOENT; | ||
765 | } | ||
766 | |||
767 | err = mesh_path_add(dst, dev); | ||
768 | if (err) { | ||
769 | rcu_read_unlock(); | ||
770 | return err; | ||
771 | } | ||
772 | |||
773 | mpath = mesh_path_lookup(dst, dev); | ||
774 | if (!mpath) { | ||
775 | rcu_read_unlock(); | ||
776 | return -ENXIO; | ||
777 | } | ||
778 | mesh_path_fix_nexthop(mpath, sta); | ||
779 | |||
780 | rcu_read_unlock(); | ||
781 | return 0; | ||
782 | } | ||
635 | 783 | ||
784 | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | ||
785 | u8 *dst) | ||
786 | { | ||
787 | if (dst) | ||
788 | return mesh_path_del(dst, dev); | ||
789 | |||
790 | mesh_path_flush(dev); | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static 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 | |||
809 | rcu_read_lock(); | ||
810 | |||
811 | sta = sta_info_get(local, next_hop); | ||
812 | if (!sta) { | ||
813 | rcu_read_unlock(); | ||
814 | return -ENOENT; | ||
815 | } | ||
816 | |||
817 | mpath = mesh_path_lookup(dst, dev); | ||
818 | if (!mpath) { | ||
819 | rcu_read_unlock(); | ||
820 | return -ENOENT; | ||
821 | } | ||
822 | |||
823 | mesh_path_fix_nexthop(mpath, sta); | ||
824 | |||
825 | rcu_read_unlock(); | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static 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 | |||
868 | static 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 | |||
890 | static 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(); | ||
636 | return 0; | 909 | return 0; |
637 | } | 910 | } |
911 | #endif | ||
638 | 912 | ||
639 | struct cfg80211_ops mac80211_config_ops = { | 913 | struct cfg80211_ops mac80211_config_ops = { |
640 | .add_virtual_intf = ieee80211_add_iface, | 914 | .add_virtual_intf = ieee80211_add_iface, |
@@ -651,4 +925,12 @@ struct cfg80211_ops mac80211_config_ops = { | |||
651 | .del_station = ieee80211_del_station, | 925 | .del_station = ieee80211_del_station, |
652 | .change_station = ieee80211_change_station, | 926 | .change_station = ieee80211_change_station, |
653 | .get_station = ieee80211_get_station, | 927 | .get_station = ieee80211_get_station, |
928 | .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 | ||
654 | }; | 936 | }; |