From 94f9065648a2645b28187b44ec7778c30cf58758 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Sat, 21 Jan 2012 01:02:16 +0800 Subject: {nl,cfg,mac}80211: Add support of setting non-forwarding entity in Mesh A mesh node that joins the mesh network is by default a forwarding entity. This patch allows the mesh node to set as non-forwarding entity. Whenever dot11MeshForwarding is set to 0, the mesh node can prevent itself from forwarding the traffic which is not destined to him. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux/nl80211.h') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 0f5ff3739820..4f98fae13307 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -2104,6 +2104,9 @@ enum nl80211_mntr_flags { * TUs) during which a mesh STA can send only one Action frame containing a * PERR element. * + * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding + * or forwarding entity (default is TRUE - forwarding entity) + * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use @@ -2128,6 +2131,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_RANN_INTERVAL, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, + NL80211_MESHCONF_FORWARDING, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, -- cgit v1.3-14-g43fede From 24db78c05b1e3ccb5a78aedd17aa1008c91dab5a Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sat, 28 Jan 2012 17:25:32 +0100 Subject: nl80211: add support for mcs masks Allow to set mcs masks through nl80211. We also allow to set MCS rates but no legacy rates (and vice versa). Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: John W. Linville --- include/linux/nl80211.h | 4 ++++ include/net/cfg80211.h | 3 +-- net/wireless/nl80211.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) (limited to 'include/linux/nl80211.h') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 4f98fae13307..ad56e21a9f10 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1475,6 +1475,7 @@ enum nl80211_attrs { #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS #define NL80211_MAX_SUPP_RATES 32 +#define NL80211_MAX_SUPP_HT_RATES 77 #define NL80211_MAX_SUPP_REG_RULES 32 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 @@ -2405,12 +2406,15 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). + * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * in an array of MCS numbers. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, + NL80211_TXRATE_MCS, /* keep last */ __NL80211_TXRATE_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5bb3ed4f99f5..2964205332f4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1232,8 +1232,7 @@ enum wiphy_params_flags { struct cfg80211_bitrate_mask { struct { u32 legacy; - /* TODO: add support for masking MCS rates; e.g.: */ - /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; } control[IEEE80211_NUM_BANDS]; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c42173f947ef..c910b0750dc2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5393,9 +5393,39 @@ static u32 rateset_to_mask(struct ieee80211_supported_band *sband, return mask; } +static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, + u8 *rates, u8 rates_len, + u8 mcs[IEEE80211_HT_MCS_MASK_LEN]) +{ + u8 i; + + memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN); + + for (i = 0; i < rates_len; i++) { + int ridx, rbit; + + ridx = rates[i] / 8; + rbit = BIT(rates[i] % 8); + + /* check validity */ + if ((ridx < 0) || (ridx > IEEE80211_HT_MCS_MASK_LEN)) + return false; + + /* check availability */ + if (sband->ht_cap.mcs.rx_mask[ridx] & rbit) + mcs[ridx] |= rbit; + else + return false; + } + + return true; +} + static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, + [NL80211_TXRATE_MCS] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_HT_RATES }, }; static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, @@ -5421,12 +5451,20 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sband = rdev->wiphy.bands[i]; mask.control[i].legacy = sband ? (1 << sband->n_bitrates) - 1 : 0; + if (sband) + memcpy(mask.control[i].mcs, + sband->ht_cap.mcs.rx_mask, + sizeof(mask.control[i].mcs)); + else + memset(mask.control[i].mcs, 0, + sizeof(mask.control[i].mcs)); } /* * The nested attribute uses enum nl80211_band as the index. This maps * directly to the enum ieee80211_band values used in cfg80211. */ + BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { enum ieee80211_band band = nla_type(tx_rates); @@ -5442,7 +5480,28 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, sband, nla_data(tb[NL80211_TXRATE_LEGACY]), nla_len(tb[NL80211_TXRATE_LEGACY])); - if (mask.control[band].legacy == 0) + } + if (tb[NL80211_TXRATE_MCS]) { + if (!ht_rateset_to_mask( + sband, + nla_data(tb[NL80211_TXRATE_MCS]), + nla_len(tb[NL80211_TXRATE_MCS]), + mask.control[band].mcs)) + return -EINVAL; + } + + if (mask.control[band].legacy == 0) { + /* don't allow empty legacy rates if HT + * is not even supported. */ + if (!rdev->wiphy.bands[band]->ht_cap.ht_supported) + return -EINVAL; + + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) + if (mask.control[band].mcs[i]) + break; + + /* legacy and mcs rates may not be both empty */ + if (i == IEEE80211_HT_MCS_MASK_LEN) return -EINVAL; } } -- cgit v1.3-14-g43fede From 8860020e0be1f03d83dc9e9e93e18a4ddbe01038 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Feb 2012 15:17:18 +0100 Subject: cfg80211: restructure AP/GO mode API The AP/GO mode API isn't very clearly defined, it has "set beacon" and "new beacon" etc. Modify the API to the following: * start AP -- all settings * change beacon -- new beacon data * stop AP -- stop AP mode operation This also reflects in the nl80211 API, rename the commands there correspondingly (but keep the old names for compatibility.) Overall, this makes it much clearer what's going on in the API. Kalle developed the ath6kl changes, I created the rest of the patch. Signed-off-by: Kalle Valo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 82 ++++++---- include/linux/nl80211.h | 34 ++-- include/net/cfg80211.h | 70 ++++---- net/mac80211/cfg.c | 146 +++++++---------- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/tx.c | 13 +- net/wireless/nl80211.c | 255 ++++++++++++++++------------- 7 files changed, 316 insertions(+), 286 deletions(-) (limited to 'include/linux/nl80211.h') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index d1922d8eb3bb..5370333883e4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2269,25 +2269,11 @@ static int ath6kl_set_ap_probe_resp_ies(struct ath6kl_vif *vif, return ret; } -static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info, bool add) +static int ath6kl_set_ies(struct ath6kl_vif *vif, + struct cfg80211_beacon_data *info) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); - struct ieee80211_mgmt *mgmt; - u8 *ies; - int ies_len; - struct wmi_connect_cmd p; + struct ath6kl *ar = vif->ar; int res; - int i, ret; - - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); - - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; - - if (vif->next_mode != AP_NETWORK) - return -EOPNOTSUPP; if (info->beacon_ies) { res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, @@ -2297,12 +2283,14 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, if (res) return res; } + if (info->proberesp_ies) { res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, info->proberesp_ies_len); if (res) return res; } + if (info->assocresp_ies) { res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_ASSOC_RESP, @@ -2312,8 +2300,30 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, return res; } - if (!add) - return 0; + return 0; +} + +static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *info) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + struct ieee80211_mgmt *mgmt; + u8 *ies; + int ies_len; + struct wmi_connect_cmd p; + int res; + int i, ret; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + res = ath6kl_set_ies(vif, &info->beacon); ar->ap_mode_bkey.valid = false; @@ -2322,13 +2332,13 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, * info->dtim_period */ - if (info->head == NULL) + if (info->beacon.head == NULL) return -EINVAL; - mgmt = (struct ieee80211_mgmt *) info->head; + mgmt = (struct ieee80211_mgmt *) info->beacon.head; ies = mgmt->u.beacon.variable; - if (ies > info->head + info->head_len) + if (ies > info->beacon.head + info->beacon.head_len) return -EINVAL; - ies_len = info->head + info->head_len - ies; + ies_len = info->beacon.head + info->beacon.head_len - ies; if (info->ssid == NULL) return -EINVAL; @@ -2436,19 +2446,21 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) +static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) { - return ath6kl_ap_beacon(wiphy, dev, info, true); -} + struct ath6kl_vif *vif = netdev_priv(dev); -static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info) -{ - return ath6kl_ap_beacon(wiphy, dev, info, false); + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + if (vif->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + return ath6kl_set_ies(vif, beacon); } -static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -2783,9 +2795,9 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .resume = __ath6kl_cfg80211_resume, #endif .set_channel = ath6kl_set_channel, - .add_beacon = ath6kl_add_beacon, - .set_beacon = ath6kl_set_beacon, - .del_beacon = ath6kl_del_beacon, + .start_ap = ath6kl_start_ap, + .change_beacon = ath6kl_change_beacon, + .stop_ap = ath6kl_stop_ap, .del_station = ath6kl_del_station, .change_station = ath6kl_change_station, .remain_on_channel = ath6kl_remain_on_channel, diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index ad56e21a9f10..be35a68746a7 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -156,21 +156,23 @@ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX * or %NL80211_ATTR_MAC. * - * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a - * %NL80222_CMD_NEW_BEACON message) - * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface - * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, - * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. - * Following attributes are provided for drivers that generate full Beacon - * and Probe Response frames internally: %NL80211_ATTR_SSID, + * @NL80211_CMD_GET_BEACON: (not used) + * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface + * using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL + * attributes. For drivers that generate the beacon and probe responses + * internally, the following attributes must be provided: %NL80211_ATTR_IE, + * %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP. + * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters + * are like for %NL80211_CMD_SET_BEACON, and additionally parameters that + * do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL, + * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, - * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, - * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP, - * %NL80211_ATTR_IE_ASSOC_RESP. - * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, - * parameters are like for %NL80211_CMD_SET_BEACON. - * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and + * %NL80211_ATTR_AUTH_TYPE. + * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP + * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface + * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP * * @NL80211_CMD_GET_STATION: Get station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. @@ -565,8 +567,10 @@ enum nl80211_commands { NL80211_CMD_GET_BEACON, NL80211_CMD_SET_BEACON, - NL80211_CMD_NEW_BEACON, - NL80211_CMD_DEL_BEACON, + NL80211_CMD_START_AP, + NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP, + NL80211_CMD_STOP_AP, + NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP, NL80211_CMD_GET_STATION, NL80211_CMD_SET_STATION, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e0c9ff3a1977..755a7707a7c5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -366,25 +366,13 @@ struct cfg80211_crypto_settings { }; /** - * struct beacon_parameters - beacon parameters - * - * Used to configure the beacon for an interface. - * + * struct cfg80211_beacon_data - beacon data * @head: head portion of beacon (before TIM IE) * or %NULL if not changed * @tail: tail portion of beacon (after TIM IE) * or %NULL if not changed - * @interval: beacon interval or zero if not changed - * @dtim_period: DTIM period or zero if not changed * @head_len: length of @head * @tail_len: length of @tail - * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from - * user space) - * @ssid_len: length of @ssid - * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames - * @crypto: crypto settings - * @privacy: the BSS uses privacy - * @auth_type: Authentication type (algorithm) * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL * @beacon_ies_len: length of beacon_ies in octets * @proberesp_ies: extra information element(s) to add into Probe Response @@ -396,24 +384,46 @@ struct cfg80211_crypto_settings { * @probe_resp_len: length of probe response template (@probe_resp) * @probe_resp: probe response template (AP mode only) */ -struct beacon_parameters { - u8 *head, *tail; - int interval, dtim_period; - int head_len, tail_len; +struct cfg80211_beacon_data { + const u8 *head, *tail; + const u8 *beacon_ies; + const u8 *proberesp_ies; + const u8 *assocresp_ies; + const u8 *probe_resp; + + size_t head_len, tail_len; + size_t beacon_ies_len; + size_t proberesp_ies_len; + size_t assocresp_ies_len; + size_t probe_resp_len; +}; + +/** + * struct cfg80211_ap_settings - AP configuration + * + * Used to configure an AP interface. + * + * @beacon: beacon data + * @beacon_interval: beacon interval + * @dtim_period: DTIM period + * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from + * user space) + * @ssid_len: length of @ssid + * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames + * @crypto: crypto settings + * @privacy: the BSS uses privacy + * @auth_type: Authentication type (algorithm) + */ +struct cfg80211_ap_settings { + struct cfg80211_beacon_data beacon; + + int beacon_interval, dtim_period; const u8 *ssid; size_t ssid_len; enum nl80211_hidden_ssid hidden_ssid; struct cfg80211_crypto_settings crypto; bool privacy; enum nl80211_auth_type auth_type; - const u8 *beacon_ies; - size_t beacon_ies_len; - const u8 *proberesp_ies; - size_t proberesp_ies_len; - const u8 *assocresp_ies; - size_t assocresp_ies_len; - int probe_resp_len; - u8 *probe_resp; }; /** @@ -1518,11 +1528,11 @@ struct cfg80211_ops { struct net_device *netdev, u8 key_index); - int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); + int (*start_ap)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings); + int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *info); + int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev); int (*add_station)(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c3de921c8cfd..f7eb25aabf8f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -489,27 +489,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) -{ - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - - bss_conf->ssid_len = params->ssid_len; - - if (params->ssid_len) - memcpy(bss_conf->ssid, params->ssid, params->ssid_len); - - bss_conf->hidden_ssid = - (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); -} - static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, - u8 *resp, size_t resp_len) + const u8 *resp, size_t resp_len) { struct sk_buff *new, *old; if (!resp || !resp_len) - return -EINVAL; + return 1; old = rtnl_dereference(sdata->u.ap.probe_resp); @@ -520,50 +506,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, memcpy(skb_put(new, resp_len), resp, resp_len); rcu_assign_pointer(sdata->u.ap.probe_resp, new); - synchronize_rcu(); - - if (old) + if (old) { + /* TODO: use call_rcu() */ + synchronize_rcu(); dev_kfree_skb(old); + } return 0; } -/* - * This handles both adding a beacon and setting new beacon info - */ -static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, - struct beacon_parameters *params) +static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params) { struct beacon_data *new, *old; int new_head_len, new_tail_len; - int size; - int err = -EINVAL; - u32 changed = 0; + int size, err; + u32 changed = BSS_CHANGED_BEACON; old = rtnl_dereference(sdata->u.ap.beacon); - /* head must not be zero-length */ - if (params->head && !params->head_len) - return -EINVAL; - - /* - * This is a kludge. beacon interval should really be part - * of the beacon information. - */ - if (params->interval && - (sdata->vif.bss_conf.beacon_int != params->interval)) { - sdata->vif.bss_conf.beacon_int = params->interval; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BEACON_INT); - } - /* Need to have a beacon head if we don't have one yet */ if (!params->head && !old) - return err; - - /* sorry, no way to start beaconing without dtim period */ - if (!params->dtim_period && !old) - return err; + return -EINVAL; /* new or old head? */ if (params->head) @@ -586,12 +550,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, /* start filling the new info now */ - /* new or old dtim period? */ - if (params->dtim_period) - new->dtim_period = params->dtim_period; - else - new->dtim_period = old->dtim_period; - /* * pointers go into the block we allocated, * memory is | beacon_data | head | tail | @@ -614,46 +572,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, if (old) memcpy(new->tail, old->tail, new_tail_len); - sdata->vif.bss_conf.dtim_period = new->dtim_period; - - rcu_assign_pointer(sdata->u.ap.beacon, new); - - synchronize_rcu(); - - kfree(old); - err = ieee80211_set_probe_resp(sdata, params->probe_resp, params->probe_resp_len); - if (!err) + if (err < 0) + return err; + if (err == 0) changed |= BSS_CHANGED_AP_PROBE_RESP; - ieee80211_config_ap_ssid(sdata, params); - changed |= BSS_CHANGED_BEACON_ENABLED | - BSS_CHANGED_BEACON | - BSS_CHANGED_SSID; + rcu_assign_pointer(sdata->u.ap.beacon, new); + + if (old) + kfree_rcu(old, rcu_head); - ieee80211_bss_info_change_notify(sdata, changed); - return 0; + return changed; } -static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *params) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct beacon_data *old; struct ieee80211_sub_if_data *vlan; - int ret; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u32 changed = BSS_CHANGED_BEACON_INT | + BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON | + BSS_CHANGED_SSID; + int err; old = rtnl_dereference(sdata->u.ap.beacon); if (old) return -EALREADY; - ret = ieee80211_config_beacon(sdata, params); - if (ret) - return ret; - /* * Apply control port protocol, this allows us to * not encrypt dynamic WEP control frames. @@ -667,14 +616,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_no_encrypt; } + sdata->vif.bss_conf.beacon_int = params->beacon_interval; + sdata->vif.bss_conf.dtim_period = params->dtim_period; + + sdata->vif.bss_conf.ssid_len = params->ssid_len; + if (params->ssid_len) + memcpy(sdata->vif.bss_conf.ssid, params->ssid, + params->ssid_len); + sdata->vif.bss_conf.hidden_ssid = + (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon); + if (err < 0) + return err; + changed |= err; + + ieee80211_bss_info_change_notify(sdata, changed); + return 0; } -static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *params) +static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *params) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; + int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -682,10 +649,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, if (!old) return -ENOENT; - return ieee80211_config_beacon(sdata, params); + err = ieee80211_assign_beacon(sdata, params); + if (err < 0) + return err; + ieee80211_bss_info_change_notify(sdata, err); + return 0; } -static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata; struct beacon_data *old; @@ -697,10 +668,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) return -ENOENT; RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(old); + + kfree_rcu(old, rcu_head); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + return 0; } @@ -2699,9 +2671,9 @@ struct cfg80211_ops mac80211_config_ops = { .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, .set_default_mgmt_key = ieee80211_config_default_mgmt_key, - .add_beacon = ieee80211_add_beacon, - .set_beacon = ieee80211_set_beacon, - .del_beacon = ieee80211_del_beacon, + .start_ap = ieee80211_start_ap, + .change_beacon = ieee80211_change_beacon, + .stop_ap = ieee80211_stop_ap, .add_station = ieee80211_add_station, .del_station = ieee80211_del_station, .change_station = ieee80211_change_station, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 74594f012cd3..67aed1eff135 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,7 +228,7 @@ struct ieee80211_rx_data { struct beacon_data { u8 *head, *tail; int head_len, tail_len; - int dtim_period; + struct rcu_head rcu_head; }; struct ieee80211_if_ap { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1be0ca2b5936..c6eadac9ca4e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2206,7 +2206,8 @@ void ieee80211_tx_pending(unsigned long data) /* functions for drivers to get certain frames */ -static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, +static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, + struct ieee80211_if_ap *bss, struct sk_buff *skb, struct beacon_data *beacon) { @@ -2223,7 +2224,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, IEEE80211_MAX_AID+1); if (bss->dtim_count == 0) - bss->dtim_count = beacon->dtim_period - 1; + bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1; else bss->dtim_count--; @@ -2231,7 +2232,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = bss->dtim_count; - *pos++ = beacon->dtim_period; + *pos++ = sdata->vif.bss_conf.dtim_period; if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) aid0 = 1; @@ -2324,12 +2325,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); } else { unsigned long flags; spin_lock_irqsave(&local->tim_lock, flags); - ieee80211_beacon_add_tim(ap, skb, beacon); + ieee80211_beacon_add_tim(sdata, ap, skb, + beacon); spin_unlock_irqrestore(&local->tim_lock, flags); } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fe2747653564..1998c3682774 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -871,7 +871,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(add_virtual_intf, NEW_INTERFACE); CMD(change_virtual_intf, SET_INTERFACE); CMD(add_key, NEW_KEY); - CMD(add_beacon, NEW_BEACON); + CMD(start_ap, START_AP); CMD(add_station, NEW_STATION); CMD(add_mpath, NEW_MPATH); CMD(update_mesh_config, SET_MESH_CONFIG); @@ -2075,15 +2075,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) return err; } -static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) +static int nl80211_parse_beacon(struct genl_info *info, + struct cfg80211_beacon_data *bcn) { - int (*call)(struct wiphy *wiphy, struct net_device *dev, - struct beacon_parameters *info); - struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; - struct wireless_dev *wdev = dev->ieee80211_ptr; - struct beacon_parameters params; - int haveinfo = 0, err; + bool haveinfo = false; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) || !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) || @@ -2091,149 +2086,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP])) return -EINVAL; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) - return -EOPNOTSUPP; - - memset(¶ms, 0, sizeof(params)); - - switch (info->genlhdr->cmd) { - case NL80211_CMD_NEW_BEACON: - /* these are required for NEW_BEACON */ - if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || - !info->attrs[NL80211_ATTR_DTIM_PERIOD] || - !info->attrs[NL80211_ATTR_BEACON_HEAD]) - return -EINVAL; - - params.interval = - nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); - params.dtim_period = - nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); - - err = cfg80211_validate_beacon_int(rdev, params.interval); - if (err) - return err; - - /* - * In theory, some of these attributes could be required for - * NEW_BEACON, but since they were not used when the command was - * originally added, keep them optional for old user space - * programs to work with drivers that do not need the additional - * information. - */ - if (info->attrs[NL80211_ATTR_SSID]) { - params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); - params.ssid_len = - nla_len(info->attrs[NL80211_ATTR_SSID]); - if (params.ssid_len == 0 || - params.ssid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - } - - if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { - params.hidden_ssid = nla_get_u32( - info->attrs[NL80211_ATTR_HIDDEN_SSID]); - if (params.hidden_ssid != - NL80211_HIDDEN_SSID_NOT_IN_USE && - params.hidden_ssid != - NL80211_HIDDEN_SSID_ZERO_LEN && - params.hidden_ssid != - NL80211_HIDDEN_SSID_ZERO_CONTENTS) - return -EINVAL; - } - - params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; - - if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { - params.auth_type = nla_get_u32( - info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(params.auth_type)) - return -EINVAL; - } else - params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - - err = nl80211_crypto_settings(rdev, info, ¶ms.crypto, - NL80211_MAX_NR_CIPHER_SUITES); - if (err) - return err; - - call = rdev->ops->add_beacon; - break; - case NL80211_CMD_SET_BEACON: - call = rdev->ops->set_beacon; - break; - default: - WARN_ON(1); - return -EOPNOTSUPP; - } - - if (!call) - return -EOPNOTSUPP; + memset(bcn, 0, sizeof(*bcn)); if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { - params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); - params.head_len = - nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); - haveinfo = 1; + bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); + bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); + if (!bcn->head_len) + return -EINVAL; + haveinfo = true; } if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { - params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); - params.tail_len = + bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); + bcn->tail_len = nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); - haveinfo = 1; + haveinfo = true; } if (!haveinfo) return -EINVAL; if (info->attrs[NL80211_ATTR_IE]) { - params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); - params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); + bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]); + bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); } if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) { - params.proberesp_ies = + bcn->proberesp_ies = nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); - params.proberesp_ies_len = + bcn->proberesp_ies_len = nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]); } if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) { - params.assocresp_ies = + bcn->assocresp_ies = nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); - params.assocresp_ies_len = + bcn->assocresp_ies_len = nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]); } if (info->attrs[NL80211_ATTR_PROBE_RESP]) { - params.probe_resp = + bcn->probe_resp = nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]); - params.probe_resp_len = + bcn->probe_resp_len = nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]); } - err = call(&rdev->wiphy, dev, ¶ms); - if (!err && params.interval) - wdev->beacon_interval = params.interval; + return 0; +} + +static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_ap_settings params; + int err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!rdev->ops->start_ap) + return -EOPNOTSUPP; + + if (wdev->beacon_interval) + return -EALREADY; + + memset(¶ms, 0, sizeof(params)); + + /* these are required for START_AP */ + if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || + !info->attrs[NL80211_ATTR_DTIM_PERIOD] || + !info->attrs[NL80211_ATTR_BEACON_HEAD]) + return -EINVAL; + + err = nl80211_parse_beacon(info, ¶ms.beacon); + if (err) + return err; + + params.beacon_interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + params.dtim_period = + nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); + + err = cfg80211_validate_beacon_int(rdev, params.beacon_interval); + if (err) + return err; + + /* + * In theory, some of these attributes should be required here + * but since they were not used when the command was originally + * added, keep them optional for old user space programs to let + * them continue to work with drivers that do not need the + * additional information -- drivers must check! + */ + if (info->attrs[NL80211_ATTR_SSID]) { + params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); + params.ssid_len = + nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid_len == 0 || + params.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) { + params.hidden_ssid = nla_get_u32( + info->attrs[NL80211_ATTR_HIDDEN_SSID]); + if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE && + params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN && + params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS) + return -EINVAL; + } + + params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + + if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { + params.auth_type = nla_get_u32( + info->attrs[NL80211_ATTR_AUTH_TYPE]); + if (!nl80211_valid_auth_type(params.auth_type)) + return -EINVAL; + } else + params.auth_type = NL80211_AUTHTYPE_AUTOMATIC; + + err = nl80211_crypto_settings(rdev, info, ¶ms.crypto, + NL80211_MAX_NR_CIPHER_SUITES); + if (err) + return err; + + err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); + if (!err) + wdev->beacon_interval = params.beacon_interval; return err; } -static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) +static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_beacon_data params; + int err; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!rdev->ops->change_beacon) + return -EOPNOTSUPP; + + if (!wdev->beacon_interval) + return -EINVAL; + + err = nl80211_parse_beacon(info, ¶ms); + if (err) + return err; + + return rdev->ops->change_beacon(&rdev->wiphy, dev, ¶ms); +} + +static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; int err; - if (!rdev->ops->del_beacon) + if (!rdev->ops->stop_ap) return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - err = rdev->ops->del_beacon(&rdev->wiphy, dev); + if (!wdev->beacon_interval) + return -ENOENT; + + err = rdev->ops->stop_ap(&rdev->wiphy, dev); if (!err) wdev->beacon_interval = 0; return err; @@ -6357,23 +6386,23 @@ static struct genl_ops nl80211_ops[] = { .cmd = NL80211_CMD_SET_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_addset_beacon, + .doit = nl80211_set_beacon, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, { - .cmd = NL80211_CMD_NEW_BEACON, + .cmd = NL80211_CMD_START_AP, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_addset_beacon, + .doit = nl80211_start_ap, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, { - .cmd = NL80211_CMD_DEL_BEACON, + .cmd = NL80211_CMD_STOP_AP, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .doit = nl80211_del_beacon, + .doit = nl80211_stop_ap, .internal_flags = NL80211_FLAG_NEED_NETDEV | NL80211_FLAG_NEED_RTNL, }, -- cgit v1.3-14-g43fede From 5533513784a88049e19dd2ab380a452b61e5171e Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Tue, 28 Feb 2012 17:04:08 -0800 Subject: {nl,cfg,mac}80211: Implement RSSI threshold for mesh peering Mesh peer links are established only if average rssi of the peer candidate satisfies the threshold. This is not in 802.11s specification but was requested by David Fulgham, an open80211s user. This is a way to avoid marginal peer links with stations that are barely within range. This patch adds a new mesh configuration parameter, mesh_rssi_threshold. This feature is supported only for hardwares that report signal in dBm. Signed-off-by: Ashok Nagarajan Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- include/linux/nl80211.h | 5 +++++ include/net/cfg80211.h | 1 + net/mac80211/cfg.c | 8 ++++++++ net/mac80211/debugfs_netdev.c | 2 ++ net/mac80211/mesh_plink.c | 16 +++++++++++++++- net/wireless/mesh.c | 3 +++ net/wireless/nl80211.c | 5 +++++ 7 files changed, 39 insertions(+), 1 deletion(-) (limited to 'include/linux/nl80211.h') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index be35a68746a7..38fda5ee57f5 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -2112,6 +2112,10 @@ enum nl80211_mntr_flags { * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding * or forwarding entity (default is TRUE - forwarding entity) * + * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the + * threshold for average signal strength of candidate station to establish + * a peer link. + * * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use @@ -2137,6 +2141,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_GATE_ANNOUNCEMENTS, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, NL80211_MESHCONF_FORWARDING, + NL80211_MESHCONF_RSSI_THRESHOLD, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0178c7489373..b4e015c90885 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -809,6 +809,7 @@ struct mesh_config { * Still keeping the same nomenclature to be in sync with the spec. */ bool dot11MeshGateAnnouncementProtocol; bool dot11MeshForwarding; + s32 rssi_threshold; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6a77d4c910f9..ab31cc56a2fb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1314,6 +1314,14 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, } if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) conf->dot11MeshForwarding = nconf->dot11MeshForwarding; + if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { + /* our RSSI threshold implementation is supported only for + * devices that report signal in dBm. + */ + if (!(sdata->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)) + return -ENOTSUPP; + conf->rssi_threshold = nconf->rssi_threshold; + } return 0; } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 510ed1dab3c7..9f484d8905fd 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -443,6 +443,7 @@ IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); +IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); #endif @@ -581,6 +582,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPRootMode); MESHPARAMS_ADD(dot11MeshHWMPRannInterval); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); + MESHPARAMS_ADD(rssi_threshold); #undef MESHPARAMS_ADD } #endif diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8806e5ef8ffe..80ce52772538 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -31,6 +31,11 @@ #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) +#define sta_meets_rssi_threshold(sta, sdata) \ + (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ + (s8) -ewma_read(&sta->avg_signal) > \ + sdata->u.mesh.mshcfg.rssi_threshold) + enum plink_event { PLINK_UNDEFINED, OPN_ACPT, @@ -301,7 +306,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, if (mesh_peer_accepts_plinks(elems) && sta->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && - sdata->u.mesh.mshcfg.auto_open_plinks) + sdata->u.mesh.mshcfg.auto_open_plinks && + sta_meets_rssi_threshold(sta, sdata)) mesh_plink_open(sta); rcu_read_unlock(); @@ -531,6 +537,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } + if (ftype == WLAN_SP_MESH_PEERING_OPEN && + !sta_meets_rssi_threshold(sta, sdata)) { + mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", + sta->sta.addr); + rcu_read_unlock(); + return; + } + if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); rcu_read_unlock(); diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 9d3e3b6bfcf4..ba21ab22187b 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -23,6 +23,8 @@ #define MESH_PERR_MIN_INT 100 #define MESH_DIAM_TRAVERSAL_TIME 50 +#define MESH_RSSI_THRESHOLD 0 + /* * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds * before timing out. This way it will remain ACTIVE and no data frames @@ -56,6 +58,7 @@ const struct mesh_config default_mesh_config = { .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL, .dot11MeshGateAnnouncementProtocol = false, .dot11MeshForwarding = true, + .rssi_threshold = MESH_RSSI_THRESHOLD, }; const struct mesh_setup default_mesh_setup = { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1998c3682774..25a470abd21d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3290,6 +3290,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, cur_params.dot11MeshGateAnnouncementProtocol); NLA_PUT_U8(msg, NL80211_MESHCONF_FORWARDING, cur_params.dot11MeshForwarding); + NLA_PUT_U32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, + cur_params.rssi_threshold); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); return genlmsg_reply(msg, info); @@ -3322,6 +3324,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, + [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, }; static const struct nla_policy @@ -3413,6 +3416,8 @@ do {\ nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, + mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); if (mask_out) *mask_out = mask; -- cgit v1.3-14-g43fede From 1b658f118b11de3c4052ed8cbdd5803cd1fa5670 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 2 Mar 2012 15:50:02 +0530 Subject: cfg80211: Add an attribute to set inactivity timeout in AP mode This patch adds an attribute, NL80211_ATTR_INACTIVITY_TIMEOUT, to set the inactivity timeout which can be used to remove the station in AP mode. This can be passed in NL80211_CMD_START_AP and used by the drivers which have AP MLME in firmware but don't support get_station() properly. To disable inactivity timer in userspace, wpa_s for example, there is a new flag, NL80211_FEATURE_INACTIVITY_TIMER, in nl80211_feature_flags through which drivers can register their capability to use the inactivity timeout to free the stations. Signed-off-by: Vasanthakumar Thiagarajan Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 15 +++++++++++++-- include/net/cfg80211.h | 2 ++ net/wireless/nl80211.c | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include/linux/nl80211.h') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 38fda5ee57f5..9f46c62b1eee 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -168,8 +168,8 @@ * %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID, * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, - * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY and - * %NL80211_ATTR_AUTH_TYPE. + * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, + * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT. * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP @@ -1197,6 +1197,12 @@ enum nl80211_commands { * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of * up to 16 TIDs. * + * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be + * used by the drivers which has MLME in firmware and does not have support + * to report per station tx/rx activity to free up the staion entry from + * the list. This needs to be used when the driver advertises the + * capability to timeout the stations. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1442,6 +1448,8 @@ enum nl80211_attrs { NL80211_ATTR_NOACK_MAP, + NL80211_ATTR_INACTIVITY_TIMEOUT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2809,10 +2817,13 @@ enum nl80211_ap_sme_features { * TX status to the socket error queue when requested with the * socket option. * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. + * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up + * the connected inactive stations in AP mode. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, + NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d640a39d9513..804805827736 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -413,6 +413,7 @@ struct cfg80211_beacon_data { * @crypto: crypto settings * @privacy: the BSS uses privacy * @auth_type: Authentication type (algorithm) + * @inactivity_timeout: time in seconds to determine station's inactivity. */ struct cfg80211_ap_settings { struct cfg80211_beacon_data beacon; @@ -424,6 +425,7 @@ struct cfg80211_ap_settings { struct cfg80211_crypto_settings crypto; bool privacy; enum nl80211_auth_type auth_type; + int inactivity_timeout; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 25a470abd21d..4b6afc338aac 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -204,6 +204,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { .len = NL80211_HT_CAPABILITY_LEN }, [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, + [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, }; /* policy for the key attributes */ @@ -2214,6 +2215,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (err) return err; + if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) { + if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) + return -EOPNOTSUPP; + params.inactivity_timeout = nla_get_u16( + info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); + } + err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); if (!err) wdev->beacon_interval = params.beacon_interval; -- cgit v1.3-14-g43fede From 804483e90794256f9ed53e795ffbf1e94de237c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Mar 2012 22:18:41 +0100 Subject: cfg80211/mac80211: report signal strength for mgmt frames Add the signal strength (in dBm only for now) to frames that are received via nl80211's various frame APIs. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath6kl/wmi.c | 6 ++++-- include/linux/nl80211.h | 6 ++++++ include/net/cfg80211.h | 8 +++++--- net/mac80211/rx.c | 13 +++++++++++-- net/wireless/mlme.c | 7 ++++--- net/wireless/nl80211.c | 9 +++++++-- net/wireless/nl80211.h | 3 ++- 7 files changed, 39 insertions(+), 13 deletions(-) (limited to 'include/linux/nl80211.h') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 18fa9aa8af92..97abf4699b41 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -556,7 +556,8 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } @@ -595,7 +596,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, ev->data, dlen, GFP_ATOMIC); + cfg80211_rx_mgmt(vif->ndev, freq, 0, + ev->data, dlen, GFP_ATOMIC); return 0; } diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9f46c62b1eee..c37d67add090 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1203,6 +1203,10 @@ enum nl80211_commands { * the list. This needs to be used when the driver advertises the * capability to timeout the stations. * + * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int); + * this attribute is (depending on the driver capabilities) added to + * received frames indicated with %NL80211_CMD_FRAME. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1450,6 +1454,8 @@ enum nl80211_attrs { NL80211_ATTR_INACTIVITY_TIMEOUT, + NL80211_ATTR_RX_SIGNAL_DBM, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 804805827736..4682c35a92c4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3189,6 +3189,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * cfg80211_rx_mgmt - notification of received, unprocessed management frame * @dev: network device * @freq: Frequency on which the frame was received in MHz + * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) * @len: length of the frame data * @gfp: context flags @@ -3201,8 +3202,8 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * This function is called whenever an Action frame is received for a station * mode interface, but is not processed in kernel. */ -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp); +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, + const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame @@ -3315,6 +3316,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, * @frame: the frame * @len: length of the frame * @freq: frequency the frame was received on + * @sig_dbm: signal strength in mBm, or 0 if unknown * @gfp: allocation flags * * Use this function to report to userspace when a beacon was @@ -3323,7 +3325,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, */ void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, gfp_t gfp); + int freq, int sig_dbm, gfp_t gfp); /* * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 10bbbd33b314..5f6e32ca0858 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2188,9 +2188,14 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { + int sig = 0; + + if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sig = status->signal; + cfg80211_report_obss_beacon(rx->local->hw.wiphy, rx->skb->data, rx->skb->len, - status->freq, GFP_ATOMIC); + status->freq, sig, GFP_ATOMIC); rx->flags |= IEEE80211_RX_BEACON_REPORTED; } @@ -2414,6 +2419,7 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + int sig = 0; /* skip known-bad action frames and return them in the next handler */ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) @@ -2426,7 +2432,10 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) * it transmitted were processed or returned. */ - if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, + if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sig = status->signal; + + if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, rx->skb->data, rx->skb->len, GFP_ATOMIC)) { if (rx->sta) diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index fb1e72179117..f5a7ac3a0939 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -814,8 +814,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, cookie); } -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, - size_t len, gfp_t gfp) +bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, + const u8 *buf, size_t len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -854,7 +854,8 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, + if (nl80211_send_mgmt(rdev, dev, reg->nlpid, + freq, sig_mbm, buf, len, gfp)) continue; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4b6afc338aac..39dbdf2adb12 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7686,7 +7686,8 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, - int freq, const u8 *buf, size_t len, gfp_t gfp) + int freq, int sig_dbm, + const u8 *buf, size_t len, gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -7704,6 +7705,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (sig_dbm) + NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm); NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); genlmsg_end(msg, hdr); @@ -7965,7 +7968,7 @@ EXPORT_SYMBOL(cfg80211_probe_status); void cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, size_t len, - int freq, gfp_t gfp) + int freq, int sig_dbm, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct sk_buff *msg; @@ -7988,6 +7991,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); if (freq) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); + if (sig_dbm) + NLA_PUT_U32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm); NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame); genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 12bf4d185abe..4ffe50df9f31 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -92,7 +92,8 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, int freq, + struct net_device *netdev, u32 nlpid, + int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, struct net_device *netdev, u64 cookie, -- cgit v1.3-14-g43fede From 4486ea987efdaa546bdda569e3dfacdc14a9fb13 Mon Sep 17 00:00:00 2001 From: Bala Shanmugam Date: Wed, 7 Mar 2012 17:27:12 +0530 Subject: cfg80211: Add background scan period attribute. Receive background scan period as part of connect command and pass the same to the driver. Signed-off-by: Bala Shanmugam Signed-off-by: John W. Linville --- include/linux/nl80211.h | 10 ++++++++++ include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 8 ++++++++ net/wireless/wext-sme.c | 3 +++ 4 files changed, 24 insertions(+) (limited to 'include/linux/nl80211.h') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c37d67add090..e474f6e780cc 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -369,6 +369,11 @@ * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * Background scan period can optionally be + * specified in %NL80211_ATTR_BG_SCAN_PERIOD, + * if not specified default background scan configuration + * in driver is used and if period value is 0, bg scan will be disabled. + * This attribute is ignored if driver does not support roam scan. * It is also sent as an event, with the BSSID and response IEs when the * connection is established or failed to be established. This can be * determined by the STATUS_CODE attribute. @@ -1207,6 +1212,9 @@ enum nl80211_commands { * this attribute is (depending on the driver capabilities) added to * received frames indicated with %NL80211_CMD_FRAME. * + * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds + * or 0 to disable background scan. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1456,6 +1464,8 @@ enum nl80211_attrs { NL80211_ATTR_RX_SIGNAL_DBM, + NL80211_ATTR_BG_SCAN_PERIOD, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 57c9fddc2acf..66f460325e24 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1203,6 +1203,8 @@ struct cfg80211_ibss_params { * @key_idx: index of WEP key for shared key authentication * @key: WEP key for shared key authentication * @flags: See &enum cfg80211_assoc_req_flags + * @bg_scan_period: Background scan period in seconds + * or -1 to indicate that default value is to be used. * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask * will be used in ht_capa. Un-supported values will be ignored. * @ht_capa_mask: The bits of ht_capa which are to be used. @@ -1220,6 +1222,7 @@ struct cfg80211_connect_params { const u8 *key; u8 key_len, key_idx; u32 flags; + int bg_scan_period; struct ieee80211_ht_cap ht_capa; struct ieee80211_ht_cap ht_capa_mask; }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 39dbdf2adb12..4c1eb9472ddb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -205,6 +205,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { }, [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, }; /* policy for the key attributes */ @@ -5116,6 +5117,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) wiphy = &rdev->wiphy; + connect.bg_scan_period = -1; + if (info->attrs[NL80211_ATTR_BG_SCAN_PERIOD] && + (wiphy->flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)) { + connect.bg_scan_period = + nla_get_u16(info->attrs[NL80211_ATTR_BG_SCAN_PERIOD]); + } + if (info->attrs[NL80211_ATTR_MAC]) connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 326750b99151..7c01c2f3b6cf 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -30,6 +30,9 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, wdev->wext.connect.ie = wdev->wext.ie; wdev->wext.connect.ie_len = wdev->wext.ie_len; + /* Use default background scan period */ + wdev->wext.connect.bg_scan_period = -1; + if (wdev->wext.keys) { wdev->wext.keys->def = wdev->wext.default_key; wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; -- cgit v1.3-14-g43fede