diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 260 |
1 files changed, 178 insertions, 82 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7b5131bd6fa1..edc872e22c9b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * mac80211 configuration hooks for cfg80211 | 2 | * mac80211 configuration hooks for cfg80211 |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | * | 5 | * |
6 | * This file is GPLv2 as found in COPYING. | 6 | * This file is GPLv2 as found in COPYING. |
7 | */ | 7 | */ |
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/ieee80211.h> | 9 | #include <linux/ieee80211.h> |
10 | #include <linux/nl80211.h> | 10 | #include <linux/nl80211.h> |
11 | #include <linux/rtnetlink.h> | 11 | #include <linux/rtnetlink.h> |
12 | #include <linux/slab.h> | ||
12 | #include <net/net_namespace.h> | 13 | #include <net/net_namespace.h> |
13 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
14 | #include <net/cfg80211.h> | 15 | #include <net/cfg80211.h> |
@@ -36,6 +37,15 @@ static bool nl80211_type_check(enum nl80211_iftype type) | |||
36 | } | 37 | } |
37 | } | 38 | } |
38 | 39 | ||
40 | static bool nl80211_params_check(enum nl80211_iftype type, | ||
41 | struct vif_params *params) | ||
42 | { | ||
43 | if (!nl80211_type_check(type)) | ||
44 | return false; | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
39 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 49 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
40 | enum nl80211_iftype type, u32 *flags, | 50 | enum nl80211_iftype type, u32 *flags, |
41 | struct vif_params *params) | 51 | struct vif_params *params) |
@@ -45,7 +55,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
45 | struct ieee80211_sub_if_data *sdata; | 55 | struct ieee80211_sub_if_data *sdata; |
46 | int err; | 56 | int err; |
47 | 57 | ||
48 | if (!nl80211_type_check(type)) | 58 | if (!nl80211_params_check(type, params)) |
49 | return -EINVAL; | 59 | return -EINVAL; |
50 | 60 | ||
51 | err = ieee80211_if_add(local, name, &dev, type, params); | 61 | err = ieee80211_if_add(local, name, &dev, type, params); |
@@ -69,17 +79,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
69 | enum nl80211_iftype type, u32 *flags, | 79 | enum nl80211_iftype type, u32 *flags, |
70 | struct vif_params *params) | 80 | struct vif_params *params) |
71 | { | 81 | { |
72 | struct ieee80211_sub_if_data *sdata; | 82 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
73 | int ret; | 83 | int ret; |
74 | 84 | ||
75 | if (netif_running(dev)) | 85 | if (ieee80211_sdata_running(sdata)) |
76 | return -EBUSY; | 86 | return -EBUSY; |
77 | 87 | ||
78 | if (!nl80211_type_check(type)) | 88 | if (!nl80211_params_check(type, params)) |
79 | return -EINVAL; | 89 | return -EINVAL; |
80 | 90 | ||
81 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
82 | |||
83 | ret = ieee80211_if_change_type(sdata, type); | 91 | ret = ieee80211_if_change_type(sdata, type); |
84 | if (ret) | 92 | if (ret) |
85 | return ret; | 93 | return ret; |
@@ -92,6 +100,13 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
92 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) | 100 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) |
93 | return 0; | 101 | return 0; |
94 | 102 | ||
103 | if (type == NL80211_IFTYPE_AP_VLAN && | ||
104 | params && params->use_4addr == 0) | ||
105 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
106 | else if (type == NL80211_IFTYPE_STATION && | ||
107 | params && params->use_4addr >= 0) | ||
108 | sdata->u.mgd.use_4addr = params->use_4addr; | ||
109 | |||
95 | sdata->u.mntr_flags = *flags; | 110 | sdata->u.mntr_flags = *flags; |
96 | return 0; | 111 | return 0; |
97 | } | 112 | } |
@@ -134,7 +149,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
134 | rcu_read_lock(); | 149 | rcu_read_lock(); |
135 | 150 | ||
136 | if (mac_addr) { | 151 | if (mac_addr) { |
137 | sta = sta_info_get(sdata->local, mac_addr); | 152 | sta = sta_info_get_bss(sdata, mac_addr); |
138 | if (!sta) { | 153 | if (!sta) { |
139 | ieee80211_key_free(key); | 154 | ieee80211_key_free(key); |
140 | err = -ENOENT; | 155 | err = -ENOENT; |
@@ -165,7 +180,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
165 | if (mac_addr) { | 180 | if (mac_addr) { |
166 | ret = -ENOENT; | 181 | ret = -ENOENT; |
167 | 182 | ||
168 | sta = sta_info_get(sdata->local, mac_addr); | 183 | sta = sta_info_get_bss(sdata, mac_addr); |
169 | if (!sta) | 184 | if (!sta) |
170 | goto out_unlock; | 185 | goto out_unlock; |
171 | 186 | ||
@@ -212,7 +227,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
212 | rcu_read_lock(); | 227 | rcu_read_lock(); |
213 | 228 | ||
214 | if (mac_addr) { | 229 | if (mac_addr) { |
215 | sta = sta_info_get(sdata->local, mac_addr); | 230 | sta = sta_info_get_bss(sdata, mac_addr); |
216 | if (!sta) | 231 | if (!sta) |
217 | goto out; | 232 | goto out; |
218 | 233 | ||
@@ -338,7 +353,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
338 | sinfo->rx_packets = sta->rx_packets; | 353 | sinfo->rx_packets = sta->rx_packets; |
339 | sinfo->tx_packets = sta->tx_packets; | 354 | sinfo->tx_packets = sta->tx_packets; |
340 | 355 | ||
341 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 356 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
357 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
342 | sinfo->filled |= STATION_INFO_SIGNAL; | 358 | sinfo->filled |= STATION_INFO_SIGNAL; |
343 | sinfo->signal = (s8)sta->last_signal; | 359 | sinfo->signal = (s8)sta->last_signal; |
344 | } | 360 | } |
@@ -377,13 +393,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
377 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 393 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
378 | int idx, u8 *mac, struct station_info *sinfo) | 394 | int idx, u8 *mac, struct station_info *sinfo) |
379 | { | 395 | { |
380 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 396 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
381 | struct sta_info *sta; | 397 | struct sta_info *sta; |
382 | int ret = -ENOENT; | 398 | int ret = -ENOENT; |
383 | 399 | ||
384 | rcu_read_lock(); | 400 | rcu_read_lock(); |
385 | 401 | ||
386 | sta = sta_info_get_by_idx(local, idx, dev); | 402 | sta = sta_info_get_by_idx(sdata, idx); |
387 | if (sta) { | 403 | if (sta) { |
388 | ret = 0; | 404 | ret = 0; |
389 | memcpy(mac, sta->sta.addr, ETH_ALEN); | 405 | memcpy(mac, sta->sta.addr, ETH_ALEN); |
@@ -398,15 +414,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
398 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 414 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
399 | u8 *mac, struct station_info *sinfo) | 415 | u8 *mac, struct station_info *sinfo) |
400 | { | 416 | { |
401 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 417 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
402 | struct sta_info *sta; | 418 | struct sta_info *sta; |
403 | int ret = -ENOENT; | 419 | int ret = -ENOENT; |
404 | 420 | ||
405 | rcu_read_lock(); | 421 | rcu_read_lock(); |
406 | 422 | ||
407 | /* XXX: verify sta->dev == dev */ | 423 | sta = sta_info_get_bss(sdata, mac); |
408 | |||
409 | sta = sta_info_get(local, mac); | ||
410 | if (sta) { | 424 | if (sta) { |
411 | ret = 0; | 425 | ret = 0; |
412 | sta_set_sinfo(sta, sinfo); | 426 | sta_set_sinfo(sta, sinfo); |
@@ -502,6 +516,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
502 | if (old) | 516 | if (old) |
503 | memcpy(new->tail, old->tail, new_tail_len); | 517 | memcpy(new->tail, old->tail, new_tail_len); |
504 | 518 | ||
519 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
520 | |||
505 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 521 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
506 | 522 | ||
507 | synchronize_rcu(); | 523 | synchronize_rcu(); |
@@ -715,7 +731,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
715 | } else | 731 | } else |
716 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 732 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
717 | 733 | ||
718 | if (compare_ether_addr(mac, dev->dev_addr) == 0) | 734 | if (compare_ether_addr(mac, sdata->vif.addr) == 0) |
719 | return -EINVAL; | 735 | return -EINVAL; |
720 | 736 | ||
721 | if (is_multicast_ether_addr(mac)) | 737 | if (is_multicast_ether_addr(mac)) |
@@ -734,17 +750,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
734 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 750 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
735 | sdata->vif.type == NL80211_IFTYPE_AP; | 751 | sdata->vif.type == NL80211_IFTYPE_AP; |
736 | 752 | ||
737 | rcu_read_lock(); | 753 | err = sta_info_insert_rcu(sta); |
738 | |||
739 | err = sta_info_insert(sta); | ||
740 | if (err) { | 754 | if (err) { |
741 | /* STA has been freed */ | ||
742 | if (err == -EEXIST && layer2_update) { | ||
743 | /* Need to update layer 2 devices on reassociation */ | ||
744 | sta = sta_info_get(local, mac); | ||
745 | if (sta) | ||
746 | ieee80211_send_layer2_update(sta); | ||
747 | } | ||
748 | rcu_read_unlock(); | 755 | rcu_read_unlock(); |
749 | return err; | 756 | return err; |
750 | } | 757 | } |
@@ -762,27 +769,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
762 | { | 769 | { |
763 | struct ieee80211_local *local = wiphy_priv(wiphy); | 770 | struct ieee80211_local *local = wiphy_priv(wiphy); |
764 | struct ieee80211_sub_if_data *sdata; | 771 | struct ieee80211_sub_if_data *sdata; |
765 | struct sta_info *sta; | ||
766 | 772 | ||
767 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 773 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
768 | 774 | ||
769 | if (mac) { | 775 | if (mac) |
770 | rcu_read_lock(); | 776 | return sta_info_destroy_addr_bss(sdata, mac); |
771 | |||
772 | /* XXX: get sta belonging to dev */ | ||
773 | sta = sta_info_get(local, mac); | ||
774 | if (!sta) { | ||
775 | rcu_read_unlock(); | ||
776 | return -ENOENT; | ||
777 | } | ||
778 | |||
779 | sta_info_unlink(&sta); | ||
780 | rcu_read_unlock(); | ||
781 | |||
782 | sta_info_destroy(sta); | ||
783 | } else | ||
784 | sta_info_flush(local, sdata); | ||
785 | 777 | ||
778 | sta_info_flush(local, sdata); | ||
786 | return 0; | 779 | return 0; |
787 | } | 780 | } |
788 | 781 | ||
@@ -791,14 +784,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
791 | u8 *mac, | 784 | u8 *mac, |
792 | struct station_parameters *params) | 785 | struct station_parameters *params) |
793 | { | 786 | { |
787 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
794 | struct ieee80211_local *local = wiphy_priv(wiphy); | 788 | struct ieee80211_local *local = wiphy_priv(wiphy); |
795 | struct sta_info *sta; | 789 | struct sta_info *sta; |
796 | struct ieee80211_sub_if_data *vlansdata; | 790 | struct ieee80211_sub_if_data *vlansdata; |
797 | 791 | ||
798 | rcu_read_lock(); | 792 | rcu_read_lock(); |
799 | 793 | ||
800 | /* XXX: get sta belonging to dev */ | 794 | sta = sta_info_get_bss(sdata, mac); |
801 | sta = sta_info_get(local, mac); | ||
802 | if (!sta) { | 795 | if (!sta) { |
803 | rcu_read_unlock(); | 796 | rcu_read_unlock(); |
804 | return -ENOENT; | 797 | return -ENOENT; |
@@ -813,6 +806,15 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
813 | return -EINVAL; | 806 | return -EINVAL; |
814 | } | 807 | } |
815 | 808 | ||
809 | if (params->vlan->ieee80211_ptr->use_4addr) { | ||
810 | if (vlansdata->u.vlan.sta) { | ||
811 | rcu_read_unlock(); | ||
812 | return -EBUSY; | ||
813 | } | ||
814 | |||
815 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); | ||
816 | } | ||
817 | |||
816 | sta->sdata = vlansdata; | 818 | sta->sdata = vlansdata; |
817 | ieee80211_send_layer2_update(sta); | 819 | ieee80211_send_layer2_update(sta); |
818 | } | 820 | } |
@@ -828,7 +830,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
828 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 830 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
829 | u8 *dst, u8 *next_hop) | 831 | u8 *dst, u8 *next_hop) |
830 | { | 832 | { |
831 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
832 | struct ieee80211_sub_if_data *sdata; | 833 | struct ieee80211_sub_if_data *sdata; |
833 | struct mesh_path *mpath; | 834 | struct mesh_path *mpath; |
834 | struct sta_info *sta; | 835 | struct sta_info *sta; |
@@ -837,7 +838,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
837 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 838 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
838 | 839 | ||
839 | rcu_read_lock(); | 840 | rcu_read_lock(); |
840 | sta = sta_info_get(local, next_hop); | 841 | sta = sta_info_get(sdata, next_hop); |
841 | if (!sta) { | 842 | if (!sta) { |
842 | rcu_read_unlock(); | 843 | rcu_read_unlock(); |
843 | return -ENOENT; | 844 | return -ENOENT; |
@@ -876,7 +877,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
876 | struct net_device *dev, | 877 | struct net_device *dev, |
877 | u8 *dst, u8 *next_hop) | 878 | u8 *dst, u8 *next_hop) |
878 | { | 879 | { |
879 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
880 | struct ieee80211_sub_if_data *sdata; | 880 | struct ieee80211_sub_if_data *sdata; |
881 | struct mesh_path *mpath; | 881 | struct mesh_path *mpath; |
882 | struct sta_info *sta; | 882 | struct sta_info *sta; |
@@ -885,7 +885,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
885 | 885 | ||
886 | rcu_read_lock(); | 886 | rcu_read_lock(); |
887 | 887 | ||
888 | sta = sta_info_get(local, next_hop); | 888 | sta = sta_info_get(sdata, next_hop); |
889 | if (!sta) { | 889 | if (!sta) { |
890 | rcu_read_unlock(); | 890 | rcu_read_unlock(); |
891 | return -ENOENT; | 891 | return -ENOENT; |
@@ -914,7 +914,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
914 | pinfo->generation = mesh_paths_generation; | 914 | pinfo->generation = mesh_paths_generation; |
915 | 915 | ||
916 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 916 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
917 | MPATH_INFO_DSN | | 917 | MPATH_INFO_SN | |
918 | MPATH_INFO_METRIC | | 918 | MPATH_INFO_METRIC | |
919 | MPATH_INFO_EXPTIME | | 919 | MPATH_INFO_EXPTIME | |
920 | MPATH_INFO_DISCOVERY_TIMEOUT | | 920 | MPATH_INFO_DISCOVERY_TIMEOUT | |
@@ -922,7 +922,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
922 | MPATH_INFO_FLAGS; | 922 | MPATH_INFO_FLAGS; |
923 | 923 | ||
924 | pinfo->frame_qlen = mpath->frame_queue.qlen; | 924 | pinfo->frame_qlen = mpath->frame_queue.qlen; |
925 | pinfo->dsn = mpath->dsn; | 925 | pinfo->sn = mpath->sn; |
926 | pinfo->metric = mpath->metric; | 926 | pinfo->metric = mpath->metric; |
927 | if (time_before(jiffies, mpath->exp_time)) | 927 | if (time_before(jiffies, mpath->exp_time)) |
928 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | 928 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); |
@@ -934,8 +934,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
934 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | 934 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; |
935 | if (mpath->flags & MESH_PATH_RESOLVING) | 935 | if (mpath->flags & MESH_PATH_RESOLVING) |
936 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 936 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; |
937 | if (mpath->flags & MESH_PATH_DSN_VALID) | 937 | if (mpath->flags & MESH_PATH_SN_VALID) |
938 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | 938 | pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID; |
939 | if (mpath->flags & MESH_PATH_FIXED) | 939 | if (mpath->flags & MESH_PATH_FIXED) |
940 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | 940 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; |
941 | if (mpath->flags & MESH_PATH_RESOLVING) | 941 | if (mpath->flags & MESH_PATH_RESOLVING) |
@@ -1008,7 +1008,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1008 | { | 1008 | { |
1009 | struct mesh_config *conf; | 1009 | struct mesh_config *conf; |
1010 | struct ieee80211_sub_if_data *sdata; | 1010 | struct ieee80211_sub_if_data *sdata; |
1011 | struct ieee80211_if_mesh *ifmsh; | ||
1012 | |||
1011 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1013 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1014 | ifmsh = &sdata->u.mesh; | ||
1012 | 1015 | ||
1013 | /* Set the config options which we are interested in setting */ | 1016 | /* Set the config options which we are interested in setting */ |
1014 | conf = &(sdata->u.mesh.mshcfg); | 1017 | conf = &(sdata->u.mesh.mshcfg); |
@@ -1043,6 +1046,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1043 | mask)) | 1046 | mask)) |
1044 | conf->dot11MeshHWMPnetDiameterTraversalTime = | 1047 | conf->dot11MeshHWMPnetDiameterTraversalTime = |
1045 | nconf->dot11MeshHWMPnetDiameterTraversalTime; | 1048 | nconf->dot11MeshHWMPnetDiameterTraversalTime; |
1049 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) { | ||
1050 | conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode; | ||
1051 | ieee80211_mesh_root_setup(ifmsh); | ||
1052 | } | ||
1046 | return 0; | 1053 | return 0; |
1047 | } | 1054 | } |
1048 | 1055 | ||
@@ -1066,6 +1073,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1066 | params->use_short_preamble; | 1073 | params->use_short_preamble; |
1067 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1074 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
1068 | } | 1075 | } |
1076 | |||
1077 | if (!sdata->vif.bss_conf.use_short_slot && | ||
1078 | sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
1079 | sdata->vif.bss_conf.use_short_slot = true; | ||
1080 | changed |= BSS_CHANGED_ERP_SLOT; | ||
1081 | } | ||
1082 | |||
1069 | if (params->use_short_slot_time >= 0) { | 1083 | if (params->use_short_slot_time >= 0) { |
1070 | sdata->vif.bss_conf.use_short_slot = | 1084 | sdata->vif.bss_conf.use_short_slot = |
1071 | params->use_short_slot_time; | 1085 | params->use_short_slot_time; |
@@ -1109,6 +1123,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1109 | p.cw_max = params->cwmax; | 1123 | p.cw_max = params->cwmax; |
1110 | p.cw_min = params->cwmin; | 1124 | p.cw_min = params->cwmin; |
1111 | p.txop = params->txop; | 1125 | p.txop = params->txop; |
1126 | |||
1127 | /* | ||
1128 | * Setting tx queue params disables u-apsd because it's only | ||
1129 | * called in master mode. | ||
1130 | */ | ||
1131 | p.uapsd = false; | ||
1132 | |||
1112 | if (drv_conf_tx(local, params->queue, &p)) { | 1133 | if (drv_conf_tx(local, params->queue, &p)) { |
1113 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1134 | printk(KERN_DEBUG "%s: failed to set TX queue " |
1114 | "parameters for queue %d\n", | 1135 | "parameters for queue %d\n", |
@@ -1211,6 +1232,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1211 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1232 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1212 | int err; | 1233 | int err; |
1213 | 1234 | ||
1235 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | ||
1236 | err = drv_set_coverage_class(local, wiphy->coverage_class); | ||
1237 | |||
1238 | if (err) | ||
1239 | return err; | ||
1240 | } | ||
1241 | |||
1214 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 1242 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
1215 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | 1243 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); |
1216 | 1244 | ||
@@ -1298,6 +1326,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) | |||
1298 | } | 1326 | } |
1299 | #endif | 1327 | #endif |
1300 | 1328 | ||
1329 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||
1330 | enum ieee80211_smps_mode smps_mode) | ||
1331 | { | ||
1332 | const u8 *ap; | ||
1333 | enum ieee80211_smps_mode old_req; | ||
1334 | int err; | ||
1335 | |||
1336 | old_req = sdata->u.mgd.req_smps; | ||
1337 | sdata->u.mgd.req_smps = smps_mode; | ||
1338 | |||
1339 | if (old_req == smps_mode && | ||
1340 | smps_mode != IEEE80211_SMPS_AUTOMATIC) | ||
1341 | return 0; | ||
1342 | |||
1343 | /* | ||
1344 | * If not associated, or current association is not an HT | ||
1345 | * association, there's no need to send an action frame. | ||
1346 | */ | ||
1347 | if (!sdata->u.mgd.associated || | ||
1348 | sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { | ||
1349 | mutex_lock(&sdata->local->iflist_mtx); | ||
1350 | ieee80211_recalc_smps(sdata->local, sdata); | ||
1351 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1352 | return 0; | ||
1353 | } | ||
1354 | |||
1355 | ap = sdata->u.mgd.associated->bssid; | ||
1356 | |||
1357 | if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
1358 | if (sdata->u.mgd.powersave) | ||
1359 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
1360 | else | ||
1361 | smps_mode = IEEE80211_SMPS_OFF; | ||
1362 | } | ||
1363 | |||
1364 | /* send SM PS frame to AP */ | ||
1365 | err = ieee80211_send_smps_action(sdata, smps_mode, | ||
1366 | ap, ap); | ||
1367 | if (err) | ||
1368 | sdata->u.mgd.req_smps = old_req; | ||
1369 | |||
1370 | return err; | ||
1371 | } | ||
1372 | |||
1301 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1373 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, |
1302 | bool enabled, int timeout) | 1374 | bool enabled, int timeout) |
1303 | { | 1375 | { |
@@ -1305,6 +1377,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1305 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1377 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1306 | struct ieee80211_conf *conf = &local->hw.conf; | 1378 | struct ieee80211_conf *conf = &local->hw.conf; |
1307 | 1379 | ||
1380 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1381 | return -EOPNOTSUPP; | ||
1382 | |||
1308 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | 1383 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) |
1309 | return -EOPNOTSUPP; | 1384 | return -EOPNOTSUPP; |
1310 | 1385 | ||
@@ -1315,6 +1390,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1315 | sdata->u.mgd.powersave = enabled; | 1390 | sdata->u.mgd.powersave = enabled; |
1316 | conf->dynamic_ps_timeout = timeout; | 1391 | conf->dynamic_ps_timeout = timeout; |
1317 | 1392 | ||
1393 | /* no change, but if automatic follow powersave */ | ||
1394 | mutex_lock(&sdata->u.mgd.mtx); | ||
1395 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | ||
1396 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1397 | |||
1318 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 1398 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
1319 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 1399 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
1320 | 1400 | ||
@@ -1330,39 +1410,52 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1330 | { | 1410 | { |
1331 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1411 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1332 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1412 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1333 | int i, err = -EINVAL; | 1413 | int i; |
1334 | u32 target_rate; | ||
1335 | struct ieee80211_supported_band *sband; | ||
1336 | 1414 | ||
1337 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1415 | /* |
1416 | * This _could_ be supported by providing a hook for | ||
1417 | * drivers for this function, but at this point it | ||
1418 | * doesn't seem worth bothering. | ||
1419 | */ | ||
1420 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
1421 | return -EOPNOTSUPP; | ||
1338 | 1422 | ||
1339 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1340 | * target_rate = X, rate->fixed = 1 means only rate X | ||
1341 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
1342 | sdata->max_ratectrl_rateidx = -1; | ||
1343 | sdata->force_unicast_rateidx = -1; | ||
1344 | 1423 | ||
1345 | if (mask->fixed) | 1424 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
1346 | target_rate = mask->fixed / 100; | 1425 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
1347 | else if (mask->maxrate) | ||
1348 | target_rate = mask->maxrate / 100; | ||
1349 | else | ||
1350 | return 0; | ||
1351 | 1426 | ||
1352 | for (i=0; i< sband->n_bitrates; i++) { | 1427 | return 0; |
1353 | struct ieee80211_rate *brate = &sband->bitrates[i]; | 1428 | } |
1354 | int this_rate = brate->bitrate; | ||
1355 | 1429 | ||
1356 | if (target_rate == this_rate) { | 1430 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
1357 | sdata->max_ratectrl_rateidx = i; | 1431 | struct net_device *dev, |
1358 | if (mask->fixed) | 1432 | struct ieee80211_channel *chan, |
1359 | sdata->force_unicast_rateidx = i; | 1433 | enum nl80211_channel_type channel_type, |
1360 | err = 0; | 1434 | unsigned int duration, |
1361 | break; | 1435 | u64 *cookie) |
1362 | } | 1436 | { |
1363 | } | 1437 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1364 | 1438 | ||
1365 | return err; | 1439 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, |
1440 | duration, cookie); | ||
1441 | } | ||
1442 | |||
1443 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | ||
1444 | struct net_device *dev, | ||
1445 | u64 cookie) | ||
1446 | { | ||
1447 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1448 | |||
1449 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | ||
1450 | } | ||
1451 | |||
1452 | static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | ||
1453 | struct ieee80211_channel *chan, | ||
1454 | enum nl80211_channel_type channel_type, | ||
1455 | const u8 *buf, size_t len, u64 *cookie) | ||
1456 | { | ||
1457 | return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, | ||
1458 | channel_type, buf, len, cookie); | ||
1366 | } | 1459 | } |
1367 | 1460 | ||
1368 | struct cfg80211_ops mac80211_config_ops = { | 1461 | struct cfg80211_ops mac80211_config_ops = { |
@@ -1411,4 +1504,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1411 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | 1504 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) |
1412 | .set_power_mgmt = ieee80211_set_power_mgmt, | 1505 | .set_power_mgmt = ieee80211_set_power_mgmt, |
1413 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | 1506 | .set_bitrate_mask = ieee80211_set_bitrate_mask, |
1507 | .remain_on_channel = ieee80211_remain_on_channel, | ||
1508 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | ||
1509 | .action = ieee80211_action, | ||
1414 | }; | 1510 | }; |