From 97c8b013da7a8ec7aa0a192489d4e7a33c4127fc Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 28 Oct 2008 15:58:31 +0800 Subject: mac80211: print reason code for deauth/dissoc frames The patch prints reason code for deauth/dissoc frames to give users more ideas what's happened for the disconnection. Signed-off-by: Zhu Yi Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29fafbe440b..9e6c75abc92 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1123,7 +1123,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) - printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", + sdata->dev->name, reason_code); if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || @@ -1154,7 +1155,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); if (ifsta->flags & IEEE80211_STA_ASSOCIATED) - printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", + sdata->dev->name, reason_code); if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; -- cgit v1.2.3 From 1239cd58d237fa6ad501acaec8776262a5784ec8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 11:12:57 +0100 Subject: wireless: move mesh config length constant This is a constant from the 802.11 specification. Signed-off-by: Johannes Berg Cc: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 2 +- net/mac80211/mesh.h | 5 +---- net/mac80211/scan.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index d3b6e1a648b..82f568e9436 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -238,7 +238,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) pos = skb_put(skb, 21); *pos++ = WLAN_EID_MESH_CONFIG; - *pos++ = MESH_CFG_LEN; + *pos++ = IEEE80211_MESH_CONFIG_LEN; /* Version */ *pos++ = 1; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e10471c6ba4..c197ab545e5 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -145,9 +145,6 @@ struct mesh_rmc { }; -/* Mesh IEs constants */ -#define MESH_CFG_LEN 19 - /* * MESH_CFG_COMP_LEN Includes: * - Active path selection protocol ID. @@ -157,7 +154,7 @@ struct mesh_rmc { * Does not include mesh capabilities, which may vary across nodes in the same * mesh */ -#define MESH_CFG_CMP_LEN 17 +#define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) /* Default values, timeouts in ms */ #define MESH_TTL 5 diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 7372d7abb8c..f5c7c337192 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -159,7 +159,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i { struct ieee80211_bss *bss; - if (mesh_config_len != MESH_CFG_LEN) + if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN) return NULL; bss = kzalloc(sizeof(*bss), GFP_ATOMIC); -- cgit v1.2.3 From 2df78167ade3d0542f0f95be7cc58861343cce3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Oct 2008 16:49:41 +0100 Subject: wireless: fix a few sparse warnings Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 2 +- net/mac80211/tx.c | 1 - net/wireless/reg.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index c643e373fc5..2b3b490a607 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -225,7 +225,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) return sample_ndx; } -void +static void minstrel_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d6392af9cd2..0d81b2cfd1a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -698,7 +698,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) left = payload_len - per_fragm; for (i = 0; i < num_fragm - 1; i++) { struct ieee80211_hdr *fhdr; - struct ieee80211_tx_info *info; size_t copylen; if (left <= 0) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9dff716d1b0..8e5d23975a0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -638,7 +638,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) print_rd_rules(rd); } -void print_regdomain_info(const struct ieee80211_regdomain *rd) +static void print_regdomain_info(const struct ieee80211_regdomain *rd) { printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]); -- cgit v1.2.3 From 41bb73eeac5ff5fb217257ba33b654747b3abf11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 01:09:37 +0100 Subject: mac80211: remove SSID driver code Remove the SSID from the driver API since now there is no driver that requires knowing the SSID and I think it's unlikely that any hardware design that does require the SSID will play well with mac80211. This also removes support for setting the SSID in master mode which will require a patch to hostapd to not try. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 --- net/mac80211/main.c | 15 +++------------ net/mac80211/mlme.c | 14 -------------- net/mac80211/wext.c | 16 ---------------- 4 files changed, 3 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2c91108e390..155a2041001 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -212,9 +212,6 @@ struct ieee80211_if_ap { struct list_head vlans; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index fa0cc7a1e6b..d631dc96c32 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -171,19 +171,13 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) conf.changed = changed; if (sdata->vif.type == NL80211_IFTYPE_STATION || - sdata->vif.type == NL80211_IFTYPE_ADHOC) { + sdata->vif.type == NL80211_IFTYPE_ADHOC) conf.bssid = sdata->u.sta.bssid; - conf.ssid = sdata->u.sta.ssid; - conf.ssid_len = sdata->u.sta.ssid_len; - } else if (sdata->vif.type == NL80211_IFTYPE_AP) { + else if (sdata->vif.type == NL80211_IFTYPE_AP) conf.bssid = sdata->dev->dev_addr; - conf.ssid = sdata->u.ap.ssid; - conf.ssid_len = sdata->u.ap.ssid_len; - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + else if (ieee80211_vif_is_mesh(&sdata->vif)) { u8 zero[ETH_ALEN] = { 0 }; conf.bssid = zero; - conf.ssid = zero; - conf.ssid_len = 0; } else { WARN_ON(1); return -EINVAL; @@ -192,9 +186,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) return -EINVAL; - if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID))) - return -EINVAL; - return local->ops->config_interface(local_to_hw(local), &sdata->vif, &conf); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9e6c75abc92..708eb4502ed 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2416,7 +2416,6 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) { struct ieee80211_if_sta *ifsta; - int res; if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; @@ -2428,19 +2427,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size memcpy(ifsta->ssid, ssid, len); ifsta->ssid_len = len; ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - - res = 0; - /* - * Hack! MLME code needs to be cleaned up to have different - * entry points for configuration and internal selection change - */ - if (netif_running(sdata->dev)) - res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); - if (res) { - printk(KERN_DEBUG "%s: Failed to config new SSID to " - "the low-level driver\n", sdata->dev->name); - return res; - } } if (len) diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 231cab57351..63f36e9d1af 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -407,13 +407,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, return 0; } - if (sdata->vif.type == NL80211_IFTYPE_AP) { - memcpy(sdata->u.ap.ssid, ssid, len); - memset(sdata->u.ap.ssid + len, 0, - IEEE80211_MAX_SSID_LEN - len); - sdata->u.ap.ssid_len = len; - return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); - } return -EOPNOTSUPP; } @@ -437,15 +430,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, return res; } - if (sdata->vif.type == NL80211_IFTYPE_AP) { - len = sdata->u.ap.ssid_len; - if (len > IW_ESSID_MAX_SIZE) - len = IW_ESSID_MAX_SIZE; - memcpy(ssid, sdata->u.ap.ssid, len); - data->length = len; - data->flags = 1; - return 0; - } return -EOPNOTSUPP; } -- cgit v1.2.3 From 8469cdef1f123e2e3e56645f1ac26c7cfb333d9c Mon Sep 17 00:00:00 2001 From: Sujith Date: Wed, 29 Oct 2008 10:19:28 +0530 Subject: mac80211: Add a new event in ieee80211_ampdu_mlme_action Send a notification to the driver on succesful reception of an ADDBA response, add IEEE80211_AMPDU_TX_RESUME for this purpose. Signed-off-by: Sujith Signed-off-by: John W. Linville --- net/mac80211/ht.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 08009d4b7d6..3e231d75677 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -987,7 +987,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, { struct ieee80211_hw *hw = &local->hw; u16 capab; - u16 tid; + u16 tid, start_seq_num; u8 *state; capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); @@ -1024,6 +1024,14 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, local->hw.ampdu_queues) ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + if (local->ops->ampdu_action) { + (void)local->ops->ampdu_action(hw, + IEEE80211_AMPDU_TX_RESUME, + &sta->sta, tid, &start_seq_num); + } +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ spin_unlock_bh(&sta->lock); } else { sta->ampdu_mlme.addba_req_num[tid]++; -- cgit v1.2.3 From 2a941ecb5178cb8c94190f17a42f35a772cbc5c6 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 29 Oct 2008 09:43:50 +0100 Subject: wireless: fix two bad print_ssid conversions This patch fixes two current compilation problems. They showed up with CONFIG_IEEE80211_DEBUG defined. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_wx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 29eb41695a8..7cc4e5ee366 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -399,6 +399,10 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, /* If a new key was provided, set it up */ if (erq->length > 0) { +#ifdef CONFIG_IEEE80211_DEBUG + DECLARE_SSID_BUF(ssid); +#endif + len = erq->length <= 5 ? 5 : 13; memcpy(sec.keys[key], keybuf, erq->length); if (len > erq->length) -- cgit v1.2.3 From bd815252720e4b667d9946d050d003ec89bda099 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Oct 2008 20:00:45 +0100 Subject: wireless: implement basic rate helper function This adds a helper function that, given a bitmap of basic rates and a bitrate returns the response rate for this rate. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/util.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'net') diff --git a/net/wireless/util.c b/net/wireless/util.c index f54424693a3..e76cc28b034 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -7,6 +7,25 @@ #include #include "core.h" +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u64 basic_rates, int bitrate) +{ + struct ieee80211_rate *result = &sband->bitrates[0]; + int i; + + for (i = 0; i < sband->n_bitrates; i++) { + if (!(basic_rates & BIT(i))) + continue; + if (sband->bitrates[i].bitrate > bitrate) + continue; + result = &sband->bitrates[i]; + } + + return result; +} +EXPORT_SYMBOL(ieee80211_get_response_rate); + int ieee80211_channel_to_frequency(int chan) { if (chan < 14) -- cgit v1.2.3 From 90c97a040d6b08cc4890328aa262fdc37336ab01 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 16:59:22 +0200 Subject: nl80211: Add basic rate configuration for AP mode Add a new attribute, NL80211_ATTR_BSS_BASIC_RATES, that can be used with NL80211_CMD_SET_BSS for userspace (e.g., hostapd) to set which rates are in the basic rate set. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 18 ++++++++++++++++++ net/wireless/nl80211.c | 8 ++++++++ 2 files changed, 26 insertions(+) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 91f56a48e2b..442a4d7b180 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1046,6 +1046,24 @@ static int ieee80211_change_bss(struct wiphy *wiphy, changed |= BSS_CHANGED_ERP_SLOT; } + if (params->basic_rates) { + int i, j; + u32 rates = 0; + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_supported_band *sband = + wiphy->bands[local->oper_channel->band]; + + for (i = 0; i < params->basic_rates_len; i++) { + int rate = (params->basic_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) + rates |= BIT(j); + } + } + sdata->vif.bss_conf.basic_rates = rates; + changed |= BSS_CHANGED_BASIC_RATES; + } + ieee80211_bss_info_change_notify(sdata, changed); return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e1d658a8b5..1ea5e3fd393 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -95,6 +95,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, @@ -1613,6 +1615,12 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) params.use_short_slot_time = nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); + if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { + params.basic_rates = + nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + params.basic_rates_len = + nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + } err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); if (err) -- cgit v1.2.3 From 318884875bdddca663ecc373c813cf8e117d9e43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 16:59:24 +0200 Subject: nl80211: Add TX queue parameter configuration Add a new attribute, NL80211_ATTR_WIPHY_TXQ_PARAMS, that can be used with NL80211_CMD_SET_WIPHY for userspace (e.g., hostapd) to set TX queue parameters (txop, cwmin, cwmax, aifs). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 25 +++++++++++++++++++ net/wireless/nl80211.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 442a4d7b180..fe672faa819 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1069,6 +1069,30 @@ static int ieee80211_change_bss(struct wiphy *wiphy, return 0; } +static int ieee80211_set_txq_params(struct wiphy *wiphy, + struct ieee80211_txq_params *params) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_tx_queue_params p; + + if (!local->ops->conf_tx) + return -EOPNOTSUPP; + + memset(&p, 0, sizeof(p)); + p.aifs = params->aifs; + p.cw_max = params->cwmax; + p.cw_min = params->cwmin; + p.txop = params->txop; + if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { + printk(KERN_DEBUG "%s: failed to set TX queue " + "parameters for queue %d\n", local->mdev->name, + params->queue); + return -EINVAL; + } + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1095,4 +1119,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_mesh_params = ieee80211_get_mesh_params, #endif .change_bss = ieee80211_change_bss, + .set_txq_params = ieee80211_set_txq_params, }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1ea5e3fd393..e3e1494e769 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -58,6 +58,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, .len = BUS_ID_SIZE-1 }, + [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -286,20 +287,76 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } +static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { + [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, + [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, +}; + +static int parse_txq_params(struct nlattr *tb[], + struct ieee80211_txq_params *txq_params) +{ + if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || + !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || + !tb[NL80211_TXQ_ATTR_AIFS]) + return -EINVAL; + + txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); + txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); + txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); + txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); + txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); + + return 0; +} + static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; - int result; - - if (!info->attrs[NL80211_ATTR_WIPHY_NAME]) - return -EINVAL; + int result = 0, rem_txq_params = 0; + struct nlattr *nl_txq_params; rdev = cfg80211_get_dev_from_info(info); if (IS_ERR(rdev)) return PTR_ERR(rdev); - result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { + result = cfg80211_dev_rename( + rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + if (result) + goto bad_res; + } + + if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { + struct ieee80211_txq_params txq_params; + struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; + + if (!rdev->ops->set_txq_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + nla_for_each_nested(nl_txq_params, + info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], + rem_txq_params) { + nla_parse(tb, NL80211_TXQ_ATTR_MAX, + nla_data(nl_txq_params), + nla_len(nl_txq_params), + txq_params_policy); + result = parse_txq_params(tb, &txq_params); + if (result) + goto bad_res; + + result = rdev->ops->set_txq_params(&rdev->wiphy, + &txq_params); + if (result) + goto bad_res; + } + } +bad_res: cfg80211_put_dev(rdev); return result; } -- cgit v1.2.3 From d61272cbb35fa1c08fe94898583d880256f2dbd3 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 30 Oct 2008 17:08:08 +0200 Subject: mac80211: fix basic rates setting from association response In previous code all the rates were marked as basic. Signed-off-by: Tomas Winkler Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 708eb4502ed..dee6448c4eb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1291,29 +1291,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(elems.supp_rates[i] & 0x80); if (rate > 110) have_higher_than_11mbit = true; for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) + if (sband->bitrates[j].bitrate == rate) { rates |= BIT(j); - if (elems.supp_rates[i] & 0x80) - basic_rates |= BIT(j); + if (is_basic) + basic_rates |= BIT(j); + break; + } } } for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(elems.supp_rates[i] & 0x80); if (rate > 110) have_higher_than_11mbit = true; for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) + if (sband->bitrates[j].bitrate == rate) { rates |= BIT(j); - if (elems.ext_supp_rates[i] & 0x80) - basic_rates |= BIT(j); + if (is_basic) + basic_rates |= BIT(j); + break; + } } } -- cgit v1.2.3 From fbf189273926d83d71c4c321f1215162569506ac Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Oct 2008 19:50:30 +0200 Subject: mac80211: Allow AP mode to be enabled With the addition of basic rate set and TX queue parameter configuration and confirmation that power save buffering is working again, mac80211 is now in state that allows AP mode to be used without major problems. Consequently, it is time to allow this mode to be enabled without having to patch the kernel. AP mode requires hostapd for management frame processing and as such, configuring this mode is only allowed through cfg80211 (not with iwconfig and WEXT). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fe672faa819..16423f94801 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -26,6 +26,8 @@ static bool nl80211_type_check(enum nl80211_iftype type) #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: #endif + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: return true; default: -- cgit v1.2.3 From d71aaf6053e380996e40c9ecfe39a8dced52694c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Oct 2008 13:33:52 -0700 Subject: cfg80211: a reg rule is invalid if freq diff is 0 A regulatory rule is invalid when the frequency difference between the end of the frequency range and the start is 0. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8e5d23975a0..34983a825ac 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -321,7 +321,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; - if (freq_range->max_bandwidth_khz > freq_diff) + if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff) return false; return true; -- cgit v1.2.3 From 9c96477d10763d4314012425ecc8a3cff9e60ea9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Oct 2008 13:33:53 -0700 Subject: cfg80211: Add regulatory domain intersection capability There are certain scenerios where we require intersecting two regulatory domains. This adds intersection support. When we enable 802.11d support we will use this to intersect the regulatory domain from the AP's country IE and what our regulatory agent believes is correct for a country. This patch enables intersection for now in the case where the last regdomain was set by a country IE which was parsed and the user then wants to set the regulatory domain. Since we don't support country IE parsing yet this code path will not be hit, however this allows us to pave the way for 11d support. Intersection code has been tested in userspace with CRDA. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 158 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 34983a825ac..3f18a1d03a5 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -50,6 +50,7 @@ struct regulatory_request { struct wiphy *wiphy; enum reg_set_by initiator; char alpha2[2]; + bool intersect; }; static struct regulatory_request *last_request; @@ -359,6 +360,143 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, return 0; } +/* Helper for regdom_intersect(), this does the real + * mathematical intersection fun */ +static int reg_rules_intersect( + const struct ieee80211_reg_rule *rule1, + const struct ieee80211_reg_rule *rule2, + struct ieee80211_reg_rule *intersected_rule) +{ + const struct ieee80211_freq_range *freq_range1, *freq_range2; + struct ieee80211_freq_range *freq_range; + const struct ieee80211_power_rule *power_rule1, *power_rule2; + struct ieee80211_power_rule *power_rule; + u32 freq_diff; + + freq_range1 = &rule1->freq_range; + freq_range2 = &rule2->freq_range; + freq_range = &intersected_rule->freq_range; + + power_rule1 = &rule1->power_rule; + power_rule2 = &rule2->power_rule; + power_rule = &intersected_rule->power_rule; + + freq_range->start_freq_khz = max(freq_range1->start_freq_khz, + freq_range2->start_freq_khz); + freq_range->end_freq_khz = min(freq_range1->end_freq_khz, + freq_range2->end_freq_khz); + freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, + freq_range2->max_bandwidth_khz); + + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; + if (freq_range->max_bandwidth_khz > freq_diff) + freq_range->max_bandwidth_khz = freq_diff; + + power_rule->max_eirp = min(power_rule1->max_eirp, + power_rule2->max_eirp); + power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, + power_rule2->max_antenna_gain); + + intersected_rule->flags = (rule1->flags | rule2->flags); + + if (!is_valid_reg_rule(intersected_rule)) + return -EINVAL; + + return 0; +} + +/** + * regdom_intersect - do the intersection between two regulatory domains + * @rd1: first regulatory domain + * @rd2: second regulatory domain + * + * Use this function to get the intersection between two regulatory domains. + * Once completed we will mark the alpha2 for the rd as intersected, "98", + * as no one single alpha2 can represent this regulatory domain. + * + * Returns a pointer to the regulatory domain structure which will hold the + * resulting intersection of rules between rd1 and rd2. We will + * kzalloc() this structure for you. + */ +static struct ieee80211_regdomain *regdom_intersect( + const struct ieee80211_regdomain *rd1, + const struct ieee80211_regdomain *rd2) +{ + int r, size_of_regd; + unsigned int x, y; + unsigned int num_rules = 0, rule_idx = 0; + const struct ieee80211_reg_rule *rule1, *rule2; + struct ieee80211_reg_rule *intersected_rule; + struct ieee80211_regdomain *rd; + /* This is just a dummy holder to help us count */ + struct ieee80211_reg_rule irule; + + /* Uses the stack temporarily for counter arithmetic */ + intersected_rule = &irule; + + memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule)); + + if (!rd1 || !rd2) + return NULL; + + /* First we get a count of the rules we'll need, then we actually + * build them. This is to so we can malloc() and free() a + * regdomain once. The reason we use reg_rules_intersect() here + * is it will return -EINVAL if the rule computed makes no sense. + * All rules that do check out OK are valid. */ + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + if (!reg_rules_intersect(rule1, rule2, + intersected_rule)) + num_rules++; + memset(intersected_rule, 0, + sizeof(struct ieee80211_reg_rule)); + } + } + + if (!num_rules) + return NULL; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((num_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + rd = kzalloc(size_of_regd, GFP_KERNEL); + if (!rd) + return NULL; + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + /* This time around instead of using the stack lets + * write to the target rule directly saving ourselves + * a memcpy() */ + intersected_rule = &rd->reg_rules[rule_idx]; + r = reg_rules_intersect(rule1, rule2, + intersected_rule); + /* No need to memset here the intersected rule here as + * we're not using the stack anymore */ + if (r) + continue; + rule_idx++; + } + } + + if (rule_idx != num_rules) { + kfree(rd); + return NULL; + } + + rd->n_reg_rules = num_rules; + rd->alpha2[0] = '9'; + rd->alpha2[1] = '8'; + + return rd; +} + /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may * want to just have the channel structure use these */ static u32 map_regdom_flags(u32 rd_flags) @@ -468,6 +606,10 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) } } +/* Return value which can be used by ignore_request() to indicate + * it has been determined we should intersect two regulatory domains */ +#define REG_INTERSECT 1 + /* This has the logic which determines when a new request * should be ignored. */ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, @@ -517,14 +659,8 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, return -EALREADY; return 0; case REGDOM_SET_BY_USER: - /* - * If the user wants to override the AP's hint, we may - * need to follow both and use the intersection. For now, - * reject any such attempt (but we don't support country - * IEs right now anyway.) - */ if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) - return -EOPNOTSUPP; + return REG_INTERSECT; return 0; } @@ -536,10 +672,14 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, const char *alpha2) { struct regulatory_request *request; + bool intersect = false; int r = 0; r = ignore_request(wiphy, set_by, alpha2); - if (r) + + if (r == REG_INTERSECT) + intersect = true; + else if (r) return r; switch (set_by) { @@ -556,6 +696,7 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, request->alpha2[1] = alpha2[1]; request->initiator = set_by; request->wiphy = wiphy; + request->intersect = intersect; kfree(last_request); last_request = request; @@ -648,6 +789,7 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) /* Takes ownership of rd only if it doesn't fail */ static int __set_regdom(const struct ieee80211_regdomain *rd) { + const struct ieee80211_regdomain *intersected_rd = NULL; /* Some basic sanity checks first */ if (is_world_regdom(rd->alpha2)) { @@ -697,6 +839,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) return -EOPNOTSUPP; } + if (unlikely(last_request->intersect)) { + intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + if (!intersected_rd) + return -EINVAL; + kfree(rd); + rd = intersected_rd; + } + /* Tada! */ cfg80211_regdomain = rd; -- cgit v1.2.3 From 5166ccd220f187b2e9edfc5f01eb49f4a0ebf586 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Oct 2008 13:33:56 -0700 Subject: cfg80211: Add kdoc for struct regulatory_request As regulatory_request gets bigger there will be more questions of what things means, so clarify documenation for it and keep track of the special alpha2 codes we use internally and on the userspace regulatory agents. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/wireless/reg.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3f18a1d03a5..4c7e39d466c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -42,9 +42,24 @@ #include "core.h" #include "reg.h" -/* - * wiphy is set if this request's initiator is - * REGDOM_SET_BY_COUNTRY_IE or _DRIVER +/** + * struct regulatory_request - receipt of last regulatory request + * + * @wiphy: this is set if this request's initiator is + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. + * @initiator: indicates who sent this request, could be any of + * of those set in reg_set_by, %REGDOM_SET_BY_* + * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains + * @intersect: indicates whether the wireless core should intersect + * the requested regulatory domain with the presently set regulatory + * domain. */ struct regulatory_request { struct wiphy *wiphy; @@ -53,6 +68,7 @@ struct regulatory_request { bool intersect; }; +/* Receipt of information from last regulatory request */ static struct regulatory_request *last_request; /* To trigger userspace events */ -- cgit v1.2.3