aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c400
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
19static enum ieee80211_if_types 20static enum ieee80211_if_types
20nl80211_type_to_mac80211_type(enum nl80211_iftype type) 21nl80211_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
36static int ieee80211_add_iface(struct wiphy *wiphy, char *name, 41static 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
52static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) 67static 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
71static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, 86static 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
148static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, 173static 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
298static 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
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;
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
274static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, 345static 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,
587static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, 689static 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
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
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
784static 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
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
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
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();
636 return 0; 909 return 0;
637} 910}
911#endif
638 912
639struct cfg80211_ops mac80211_config_ops = { 913struct 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};