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.c436
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
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,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
148static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, 181static 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
180static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, 223static 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
322static 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
348static 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
274static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, 369static 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,
587static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, 713static 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
765static 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
804static 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
814static 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
849static 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
888static 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
910static 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
639struct cfg80211_ops mac80211_config_ops = { 933struct 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};