diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 194 |
1 files changed, 174 insertions, 20 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 855126a3039d..9d4e4d846ec1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -17,13 +17,6 @@ | |||
17 | #include "rate.h" | 17 | #include "rate.h" |
18 | #include "mesh.h" | 18 | #include "mesh.h" |
19 | 19 | ||
20 | struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy) | ||
21 | { | ||
22 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
23 | return &local->hw; | ||
24 | } | ||
25 | EXPORT_SYMBOL(wiphy_to_hw); | ||
26 | |||
27 | static bool nl80211_type_check(enum nl80211_iftype type) | 20 | static bool nl80211_type_check(enum nl80211_iftype type) |
28 | { | 21 | { |
29 | switch (type) { | 22 | switch (type) { |
@@ -33,6 +26,8 @@ static bool nl80211_type_check(enum nl80211_iftype type) | |||
33 | #ifdef CONFIG_MAC80211_MESH | 26 | #ifdef CONFIG_MAC80211_MESH |
34 | case NL80211_IFTYPE_MESH_POINT: | 27 | case NL80211_IFTYPE_MESH_POINT: |
35 | #endif | 28 | #endif |
29 | case NL80211_IFTYPE_AP: | ||
30 | case NL80211_IFTYPE_AP_VLAN: | ||
36 | case NL80211_IFTYPE_WDS: | 31 | case NL80211_IFTYPE_WDS: |
37 | return true; | 32 | return true; |
38 | default: | 33 | default: |
@@ -315,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
315 | 310 | ||
316 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 311 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
317 | STATION_INFO_RX_BYTES | | 312 | STATION_INFO_RX_BYTES | |
318 | STATION_INFO_TX_BYTES; | 313 | STATION_INFO_TX_BYTES | |
314 | STATION_INFO_TX_BITRATE; | ||
319 | 315 | ||
320 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 316 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
321 | sinfo->rx_bytes = sta->rx_bytes; | 317 | sinfo->rx_bytes = sta->rx_bytes; |
322 | sinfo->tx_bytes = sta->tx_bytes; | 318 | sinfo->tx_bytes = sta->tx_bytes; |
323 | 319 | ||
320 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | ||
321 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
322 | sinfo->signal = (s8)sta->last_signal; | ||
323 | } | ||
324 | |||
325 | sinfo->txrate.flags = 0; | ||
326 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) | ||
327 | sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; | ||
328 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
329 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
330 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | ||
331 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
332 | |||
333 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | ||
334 | struct ieee80211_supported_band *sband; | ||
335 | sband = sta->local->hw.wiphy->bands[ | ||
336 | sta->local->hw.conf.channel->band]; | ||
337 | sinfo->txrate.legacy = | ||
338 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | ||
339 | } else | ||
340 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | ||
341 | |||
324 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 342 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
325 | #ifdef CONFIG_MAC80211_MESH | 343 | #ifdef CONFIG_MAC80211_MESH |
326 | sinfo->filled |= STATION_INFO_LLID | | 344 | sinfo->filled |= STATION_INFO_LLID | |
@@ -401,8 +419,10 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
401 | */ | 419 | */ |
402 | if (params->interval) { | 420 | if (params->interval) { |
403 | sdata->local->hw.conf.beacon_int = params->interval; | 421 | sdata->local->hw.conf.beacon_int = params->interval; |
404 | if (ieee80211_hw_config(sdata->local)) | 422 | err = ieee80211_hw_config(sdata->local, |
405 | return -EINVAL; | 423 | IEEE80211_CONF_CHANGE_BEACON_INTERVAL); |
424 | if (err < 0) | ||
425 | return err; | ||
406 | /* | 426 | /* |
407 | * We updated some parameter so if below bails out | 427 | * We updated some parameter so if below bails out |
408 | * it's not an error. | 428 | * it's not an error. |
@@ -589,6 +609,8 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
589 | struct ieee80211_supported_band *sband; | 609 | struct ieee80211_supported_band *sband; |
590 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 610 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
591 | 611 | ||
612 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||
613 | |||
592 | /* | 614 | /* |
593 | * FIXME: updating the flags is racy when this function is | 615 | * FIXME: updating the flags is racy when this function is |
594 | * called from ieee80211_change_station(), this will | 616 | * called from ieee80211_change_station(), this will |
@@ -629,7 +651,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
629 | 651 | ||
630 | if (params->supported_rates) { | 652 | if (params->supported_rates) { |
631 | rates = 0; | 653 | rates = 0; |
632 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||
633 | 654 | ||
634 | for (i = 0; i < params->supported_rates_len; i++) { | 655 | for (i = 0; i < params->supported_rates_len; i++) { |
635 | int rate = (params->supported_rates[i] & 0x7f) * 5; | 656 | int rate = (params->supported_rates[i] & 0x7f) * 5; |
@@ -641,10 +662,10 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
641 | sta->sta.supp_rates[local->oper_channel->band] = rates; | 662 | sta->sta.supp_rates[local->oper_channel->band] = rates; |
642 | } | 663 | } |
643 | 664 | ||
644 | if (params->ht_capa) { | 665 | if (params->ht_capa) |
645 | ieee80211_ht_cap_ie_to_ht_info(params->ht_capa, | 666 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, |
646 | &sta->sta.ht_info); | 667 | params->ht_capa, |
647 | } | 668 | &sta->sta.ht_cap); |
648 | 669 | ||
649 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 670 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { |
650 | switch (params->plink_action) { | 671 | switch (params->plink_action) { |
@@ -665,6 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
665 | struct sta_info *sta; | 686 | struct sta_info *sta; |
666 | struct ieee80211_sub_if_data *sdata; | 687 | struct ieee80211_sub_if_data *sdata; |
667 | int err; | 688 | int err; |
689 | int layer2_update; | ||
668 | 690 | ||
669 | /* Prevent a race with changing the rate control algorithm */ | 691 | /* Prevent a race with changing the rate control algorithm */ |
670 | if (!netif_running(dev)) | 692 | if (!netif_running(dev)) |
@@ -695,17 +717,25 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
695 | 717 | ||
696 | rate_control_rate_init(sta); | 718 | rate_control_rate_init(sta); |
697 | 719 | ||
720 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||
721 | sdata->vif.type == NL80211_IFTYPE_AP; | ||
722 | |||
698 | rcu_read_lock(); | 723 | rcu_read_lock(); |
699 | 724 | ||
700 | err = sta_info_insert(sta); | 725 | err = sta_info_insert(sta); |
701 | if (err) { | 726 | if (err) { |
702 | /* STA has been freed */ | 727 | /* STA has been freed */ |
728 | if (err == -EEXIST && layer2_update) { | ||
729 | /* Need to update layer 2 devices on reassociation */ | ||
730 | sta = sta_info_get(local, mac); | ||
731 | if (sta) | ||
732 | ieee80211_send_layer2_update(sta); | ||
733 | } | ||
703 | rcu_read_unlock(); | 734 | rcu_read_unlock(); |
704 | return err; | 735 | return err; |
705 | } | 736 | } |
706 | 737 | ||
707 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 738 | if (layer2_update) |
708 | sdata->vif.type == NL80211_IFTYPE_AP) | ||
709 | ieee80211_send_layer2_update(sta); | 739 | ieee80211_send_layer2_update(sta); |
710 | 740 | ||
711 | rcu_read_unlock(); | 741 | rcu_read_unlock(); |
@@ -957,6 +987,72 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
957 | rcu_read_unlock(); | 987 | rcu_read_unlock(); |
958 | return 0; | 988 | return 0; |
959 | } | 989 | } |
990 | |||
991 | static int ieee80211_get_mesh_params(struct wiphy *wiphy, | ||
992 | struct net_device *dev, | ||
993 | struct mesh_config *conf) | ||
994 | { | ||
995 | struct ieee80211_sub_if_data *sdata; | ||
996 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
997 | |||
998 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
999 | return -ENOTSUPP; | ||
1000 | memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | ||
1005 | { | ||
1006 | return (mask >> (parm-1)) & 0x1; | ||
1007 | } | ||
1008 | |||
1009 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | ||
1010 | struct net_device *dev, | ||
1011 | const struct mesh_config *nconf, u32 mask) | ||
1012 | { | ||
1013 | struct mesh_config *conf; | ||
1014 | struct ieee80211_sub_if_data *sdata; | ||
1015 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1016 | |||
1017 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
1018 | return -ENOTSUPP; | ||
1019 | |||
1020 | /* Set the config options which we are interested in setting */ | ||
1021 | conf = &(sdata->u.mesh.mshcfg); | ||
1022 | if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) | ||
1023 | conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout; | ||
1024 | if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask)) | ||
1025 | conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout; | ||
1026 | if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask)) | ||
1027 | conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout; | ||
1028 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask)) | ||
1029 | conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks; | ||
1030 | if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask)) | ||
1031 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; | ||
1032 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | ||
1033 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | ||
1034 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | ||
1035 | conf->auto_open_plinks = nconf->auto_open_plinks; | ||
1036 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | ||
1037 | conf->dot11MeshHWMPmaxPREQretries = | ||
1038 | nconf->dot11MeshHWMPmaxPREQretries; | ||
1039 | if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask)) | ||
1040 | conf->path_refresh_time = nconf->path_refresh_time; | ||
1041 | if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask)) | ||
1042 | conf->min_discovery_timeout = nconf->min_discovery_timeout; | ||
1043 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask)) | ||
1044 | conf->dot11MeshHWMPactivePathTimeout = | ||
1045 | nconf->dot11MeshHWMPactivePathTimeout; | ||
1046 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask)) | ||
1047 | conf->dot11MeshHWMPpreqMinInterval = | ||
1048 | nconf->dot11MeshHWMPpreqMinInterval; | ||
1049 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | ||
1050 | mask)) | ||
1051 | conf->dot11MeshHWMPnetDiameterTraversalTime = | ||
1052 | nconf->dot11MeshHWMPnetDiameterTraversalTime; | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
960 | #endif | 1056 | #endif |
961 | 1057 | ||
962 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1058 | static int ieee80211_change_bss(struct wiphy *wiphy, |
@@ -972,25 +1068,79 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
972 | return -EINVAL; | 1068 | return -EINVAL; |
973 | 1069 | ||
974 | if (params->use_cts_prot >= 0) { | 1070 | if (params->use_cts_prot >= 0) { |
975 | sdata->bss_conf.use_cts_prot = params->use_cts_prot; | 1071 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; |
976 | changed |= BSS_CHANGED_ERP_CTS_PROT; | 1072 | changed |= BSS_CHANGED_ERP_CTS_PROT; |
977 | } | 1073 | } |
978 | if (params->use_short_preamble >= 0) { | 1074 | if (params->use_short_preamble >= 0) { |
979 | sdata->bss_conf.use_short_preamble = | 1075 | sdata->vif.bss_conf.use_short_preamble = |
980 | params->use_short_preamble; | 1076 | params->use_short_preamble; |
981 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1077 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
982 | } | 1078 | } |
983 | if (params->use_short_slot_time >= 0) { | 1079 | if (params->use_short_slot_time >= 0) { |
984 | sdata->bss_conf.use_short_slot = | 1080 | sdata->vif.bss_conf.use_short_slot = |
985 | params->use_short_slot_time; | 1081 | params->use_short_slot_time; |
986 | changed |= BSS_CHANGED_ERP_SLOT; | 1082 | changed |= BSS_CHANGED_ERP_SLOT; |
987 | } | 1083 | } |
988 | 1084 | ||
1085 | if (params->basic_rates) { | ||
1086 | int i, j; | ||
1087 | u32 rates = 0; | ||
1088 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1089 | struct ieee80211_supported_band *sband = | ||
1090 | wiphy->bands[local->oper_channel->band]; | ||
1091 | |||
1092 | for (i = 0; i < params->basic_rates_len; i++) { | ||
1093 | int rate = (params->basic_rates[i] & 0x7f) * 5; | ||
1094 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1095 | if (sband->bitrates[j].bitrate == rate) | ||
1096 | rates |= BIT(j); | ||
1097 | } | ||
1098 | } | ||
1099 | sdata->vif.bss_conf.basic_rates = rates; | ||
1100 | changed |= BSS_CHANGED_BASIC_RATES; | ||
1101 | } | ||
1102 | |||
989 | ieee80211_bss_info_change_notify(sdata, changed); | 1103 | ieee80211_bss_info_change_notify(sdata, changed); |
990 | 1104 | ||
991 | return 0; | 1105 | return 0; |
992 | } | 1106 | } |
993 | 1107 | ||
1108 | static int ieee80211_set_txq_params(struct wiphy *wiphy, | ||
1109 | struct ieee80211_txq_params *params) | ||
1110 | { | ||
1111 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1112 | struct ieee80211_tx_queue_params p; | ||
1113 | |||
1114 | if (!local->ops->conf_tx) | ||
1115 | return -EOPNOTSUPP; | ||
1116 | |||
1117 | memset(&p, 0, sizeof(p)); | ||
1118 | p.aifs = params->aifs; | ||
1119 | p.cw_max = params->cwmax; | ||
1120 | p.cw_min = params->cwmin; | ||
1121 | p.txop = params->txop; | ||
1122 | if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { | ||
1123 | printk(KERN_DEBUG "%s: failed to set TX queue " | ||
1124 | "parameters for queue %d\n", local->mdev->name, | ||
1125 | params->queue); | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int ieee80211_set_channel(struct wiphy *wiphy, | ||
1133 | struct ieee80211_channel *chan, | ||
1134 | enum nl80211_channel_type channel_type) | ||
1135 | { | ||
1136 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1137 | |||
1138 | local->oper_channel = chan; | ||
1139 | local->oper_channel_type = channel_type; | ||
1140 | |||
1141 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1142 | } | ||
1143 | |||
994 | struct cfg80211_ops mac80211_config_ops = { | 1144 | struct cfg80211_ops mac80211_config_ops = { |
995 | .add_virtual_intf = ieee80211_add_iface, | 1145 | .add_virtual_intf = ieee80211_add_iface, |
996 | .del_virtual_intf = ieee80211_del_iface, | 1146 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1013,6 +1163,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1013 | .change_mpath = ieee80211_change_mpath, | 1163 | .change_mpath = ieee80211_change_mpath, |
1014 | .get_mpath = ieee80211_get_mpath, | 1164 | .get_mpath = ieee80211_get_mpath, |
1015 | .dump_mpath = ieee80211_dump_mpath, | 1165 | .dump_mpath = ieee80211_dump_mpath, |
1166 | .set_mesh_params = ieee80211_set_mesh_params, | ||
1167 | .get_mesh_params = ieee80211_get_mesh_params, | ||
1016 | #endif | 1168 | #endif |
1017 | .change_bss = ieee80211_change_bss, | 1169 | .change_bss = ieee80211_change_bss, |
1170 | .set_txq_params = ieee80211_set_txq_params, | ||
1171 | .set_channel = ieee80211_set_channel, | ||
1018 | }; | 1172 | }; |