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