From 0879fa44b54101c9955123582018cb511047a2b6 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 9 Aug 2011 18:02:26 -0700 Subject: cfg80211/mac80211: move information element parsing logic to cfg80211 Moving the parsing logic for retrieving the information elements stored in management frames, e.g. beacons or probe responses, and making it available to other cfg80211 drivers. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- net/wireless/util.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) (limited to 'net/wireless/util.c') diff --git a/net/wireless/util.c b/net/wireless/util.c index be75a3a0424..844ddb0aa65 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "core.h" @@ -1044,3 +1045,170 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, return 0; } + +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, + struct ieee802_11_elems *elems, + u64 filter, u32 crc) +{ + size_t left = len; + u8 *pos = start; + bool calc_crc = filter != 0; + + memset(elems, 0, sizeof(*elems)); + elems->ie_start = start; + elems->total_len = len; + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) + break; + + if (calc_crc && id < 64 && (filter & (1ULL << id))) + crc = crc32_be(crc, pos - 2, elen + 2); + + switch (id) { + case WLAN_EID_SSID: + elems->ssid = pos; + elems->ssid_len = elen; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = pos; + elems->supp_rates_len = elen; + break; + case WLAN_EID_FH_PARAMS: + elems->fh_params = pos; + elems->fh_params_len = elen; + break; + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_CF_PARAMS: + elems->cf_params = pos; + elems->cf_params_len = elen; + break; + case WLAN_EID_TIM: + if (elen >= sizeof(struct ieee80211_tim_ie)) { + elems->tim = (void *)pos; + elems->tim_len = elen; + } + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_CHALLENGE: + elems->challenge = pos; + elems->challenge_len = elen; + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { + /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + if (pos[3] == 1) { + /* OUI Type 1 - WPA IE */ + elems->wpa = pos; + elems->wpa_len = elen; + } else if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ + if (pos[4] == 0) { + elems->wmm_info = pos; + elems->wmm_info_len = elen; + } else if (pos[4] == 1) { + elems->wmm_param = pos; + elems->wmm_param_len = elen; + } + } + } + break; + case WLAN_EID_RSN: + elems->rsn = pos; + elems->rsn_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = pos; + elems->ext_supp_rates_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + if (elen >= sizeof(struct ieee80211_ht_cap)) + elems->ht_cap_elem = (void *)pos; + break; + case WLAN_EID_HT_INFORMATION: + if (elen >= sizeof(struct ieee80211_ht_info)) + elems->ht_info_elem = (void *)pos; + break; + case WLAN_EID_MESH_ID: + elems->mesh_id = pos; + elems->mesh_id_len = elen; + break; + case WLAN_EID_MESH_CONFIG: + if (elen >= sizeof(struct ieee80211_meshconf_ie)) + elems->mesh_config = (void *)pos; + break; + case WLAN_EID_PEER_LINK: + elems->peer_link = pos; + elems->peer_link_len = elen; + break; + case WLAN_EID_PREQ: + elems->preq = pos; + elems->preq_len = elen; + break; + case WLAN_EID_PREP: + elems->prep = pos; + elems->prep_len = elen; + break; + case WLAN_EID_PERR: + elems->perr = pos; + elems->perr_len = elen; + break; + case WLAN_EID_RANN: + if (elen >= sizeof(struct ieee80211_rann_ie)) + elems->rann = (void *)pos; + break; + case WLAN_EID_CHANNEL_SWITCH: + elems->ch_switch_elem = pos; + elems->ch_switch_elem_len = elen; + break; + case WLAN_EID_QUIET: + if (!elems->quiet_elem) { + elems->quiet_elem = pos; + elems->quiet_elem_len = elen; + } + elems->num_of_quiet_elem++; + break; + case WLAN_EID_COUNTRY: + elems->country_elem = pos; + elems->country_elem_len = elen; + break; + case WLAN_EID_PWR_CONSTRAINT: + elems->pwr_constr_elem = pos; + elems->pwr_constr_elem_len = elen; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + elems->timeout_int = pos; + elems->timeout_int_len = elen; + break; + default: + break; + } + + left -= elen; + pos += elen; + } + + return crc; +} +EXPORT_SYMBOL(ieee802_11_parse_elems_crc); -- cgit v1.2.3-70-g09d2 From 8db098507c5cbe499061d0f6aea426a36e7c72d7 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Fri, 12 Aug 2011 20:01:00 -0700 Subject: mac80211: update mesh peering frame format This patch updates the mesh peering frames to the format specified in the recently ratified 802.11s standard. Several changes took place to make this happen: - Change RX path to handle new self-protected frames - Add new Peering management IE - Remove old Peer Link IE - Remove old plink_action field in ieee80211_mgmt header These changes by themselves would either break peering, or work by coincidence, so squash them all into this patch. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 18 ---------- include/net/cfg80211.h | 4 +-- net/mac80211/mesh.c | 10 ++++-- net/mac80211/mesh_plink.c | 89 +++++++++++++++++++++++++---------------------- net/mac80211/rx.c | 18 ++++++++++ net/wireless/util.c | 6 ++-- 6 files changed, 79 insertions(+), 66 deletions(-) (limited to 'net/wireless/util.c') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0750987f2a1..819954a607f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -736,19 +736,6 @@ struct ieee80211_mgmt { __le16 params; __le16 reason_code; } __attribute__((packed)) delba; - struct{ - u8 action_code; - /* capab_info for open and confirm, - * reason for close - */ - __le16 aux; - /* Followed in plink_confirm by status - * code, AID and supported rates, - * and directly by supported rates in - * plink_open and plink_close - */ - u8 variable[0]; - } __attribute__((packed)) plink_action; struct { u8 action_code; u8 variable[0]; @@ -1200,11 +1187,6 @@ enum ieee80211_eid { WLAN_EID_MESH_ID = 114, WLAN_EID_LINK_METRIC_REPORT = 115, WLAN_EID_CONGESTION_NOTIFICATION = 116, - /* Note that the Peer Link IE has been replaced with the similar - * Peer Management IE. We will keep the former definition until mesh - * code is changed to comply with latest 802.11s drafts. - */ - WLAN_EID_PEER_LINK = 55, /* no longer in 802.11s drafts */ WLAN_EID_PEER_MGMT = 117, WLAN_EID_CHAN_SWITCH_PARAM = 118, WLAN_EID_MESH_AWAKE_WINDOW = 119, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d86a15d87e5..d29d11a31f5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2291,7 +2291,7 @@ struct ieee802_11_elems { struct ieee80211_ht_info *ht_info_elem; struct ieee80211_meshconf_ie *mesh_config; u8 *mesh_id; - u8 *peer_link; + u8 *peering; u8 *preq; u8 *prep; u8 *perr; @@ -2318,7 +2318,7 @@ struct ieee802_11_elems { u8 wmm_info_len; u8 wmm_param_len; u8 mesh_id_len; - u8 peer_link_len; + u8 peering_len; u8 preq_len; u8 prep_len; u8 perr_len; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1990869033e..da5e981c483 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -662,8 +662,14 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { - case WLAN_CATEGORY_MESH_ACTION: - mesh_rx_plink_frame(sdata, mgmt, len, rx_status); + case WLAN_CATEGORY_SELF_PROTECTED: + switch (mgmt->u.action.u.self_prot.action_code) { + case WLAN_SP_MESH_PEERING_OPEN: + case WLAN_SP_MESH_PEERING_CLOSE: + case WLAN_SP_MESH_PEERING_CONFIRM: + mesh_rx_plink_frame(sdata, mgmt, len, rx_status); + break; + } break; case WLAN_CATEGORY_MESH_PATH_SEL: mesh_rx_path_sel_frame(sdata, mgmt, len); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 2cf22127d32..1a00d0f701c 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -19,8 +19,8 @@ #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) #endif -#define PLINK_GET_LLID(p) (p + 4) -#define PLINK_GET_PLID(p) (p + 6) +#define PLINK_GET_LLID(p) (p + 2) +#define PLINK_GET_PLID(p) (p + 4) #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ jiffies + HZ * t / 1000)) @@ -147,9 +147,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, sdata->u.mesh.ie_len); struct ieee80211_mgmt *mgmt; bool include_plid = false; - static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; + int ie_len = 4; + u16 peering_proto = 0; u8 *pos; - int ie_len; if (!skb) return -1; @@ -158,24 +158,23 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, * common action part (1) */ mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action)); - memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action)); + skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot)); + memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot)); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); - mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; - mgmt->u.action.u.plink_action.action_code = action; + mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED; + mgmt->u.action.u.self_prot.action_code = action; - if (action == WLAN_SP_MESH_PEERING_CLOSE) - mgmt->u.action.u.plink_action.aux = reason; - else { - mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0); + if (action != WLAN_SP_MESH_PEERING_CLOSE) { + /* capability info */ + pos = skb_put(skb, 2); + memset(pos, 0, 2); if (action == WLAN_SP_MESH_PEERING_CONFIRM) { - pos = skb_put(skb, 4); - /* two-byte status code followed by two-byte AID */ - memset(pos, 0, 2); + /* AID */ + pos = skb_put(skb, 2); memcpy(pos + 2, &plid, 2); } if (mesh_add_srates_ie(skb, sdata) || @@ -184,42 +183,50 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) return -1; + } else { /* WLAN_SP_MESH_PEERING_CLOSE */ + if (mesh_add_meshid_ie(skb, sdata)) + return -1; } - /* Add Peer Link Management element */ + /* Add Mesh Peering Management element */ switch (action) { case WLAN_SP_MESH_PEERING_OPEN: - ie_len = 6; break; case WLAN_SP_MESH_PEERING_CONFIRM: - ie_len = 8; + ie_len += 2; include_plid = true; break; case WLAN_SP_MESH_PEERING_CLOSE: - default: - if (!plid) - ie_len = 8; - else { - ie_len = 10; + if (plid) { + ie_len += 2; include_plid = true; } + ie_len += 2; /* reason code */ break; + default: + return -EINVAL; } + if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) + return -ENOMEM; + pos = skb_put(skb, 2 + ie_len); - *pos++ = WLAN_EID_PEER_LINK; + *pos++ = WLAN_EID_PEER_MGMT; *pos++ = ie_len; - memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); - pos += 4; + memcpy(pos, &peering_proto, 2); + pos += 2; memcpy(pos, &llid, 2); + pos += 2; if (include_plid) { - pos += 2; memcpy(pos, &plid, 2); + pos += 2; } if (action == WLAN_SP_MESH_PEERING_CLOSE) { - pos += 2; memcpy(pos, &reason, 2); + pos += 2; } + if (mesh_add_vendor_ies(skb, sdata)) + return -1; ieee80211_tx_skb(sdata, skb); return 0; @@ -437,15 +444,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } - baseaddr = mgmt->u.action.u.plink_action.variable; - baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; - if (mgmt->u.action.u.plink_action.action_code == + baseaddr = mgmt->u.action.u.self_prot.variable; + baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; + if (mgmt->u.action.u.self_prot.action_code == WLAN_SP_MESH_PEERING_CONFIRM) { baseaddr += 4; baselen += 4; } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); - if (!elems.peer_link) { + if (!elems.peering) { mpl_dbg("Mesh plink: missing necessary peer link ie\n"); return; } @@ -455,12 +462,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } - ftype = mgmt->u.action.u.plink_action.action_code; - ie_len = elems.peer_link_len; - if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 6) || - (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 8) || - (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 8 - && ie_len != 10)) { + ftype = mgmt->u.action.u.self_prot.action_code; + ie_len = elems.peering_len; + if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || + (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || + (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 + && ie_len != 8)) { mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", ftype, ie_len); return; @@ -474,10 +481,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ - memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); + memcpy(&plid, PLINK_GET_LLID(elems.peering), 2); if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || - (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 10)) - memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); + (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) + memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); rcu_read_lock(); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe2c2a71779..3fb6dea3653 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2220,6 +2220,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) goto handled; } break; + case WLAN_CATEGORY_SELF_PROTECTED: + switch (mgmt->u.action.u.self_prot.action_code) { + case WLAN_SP_MESH_PEERING_OPEN: + case WLAN_SP_MESH_PEERING_CLOSE: + case WLAN_SP_MESH_PEERING_CONFIRM: + if (!ieee80211_vif_is_mesh(&sdata->vif)) + goto invalid; + if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) + /* userspace handles this frame */ + break; + goto queue; + case WLAN_SP_MGK_INFORM: + case WLAN_SP_MGK_ACK: + if (!ieee80211_vif_is_mesh(&sdata->vif)) + goto invalid; + break; + } + break; case WLAN_CATEGORY_MESH_ACTION: if (!ieee80211_vif_is_mesh(&sdata->vif)) break; diff --git a/net/wireless/util.c b/net/wireless/util.c index 844ddb0aa65..eef82f79554 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1158,9 +1158,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, if (elen >= sizeof(struct ieee80211_meshconf_ie)) elems->mesh_config = (void *)pos; break; - case WLAN_EID_PEER_LINK: - elems->peer_link = pos; - elems->peer_link_len = elen; + case WLAN_EID_PEER_MGMT: + elems->peering = pos; + elems->peering_len = elen; break; case WLAN_EID_PREQ: elems->preq = pos; -- cgit v1.2.3-70-g09d2 From 24616152b1d184864370c5ea21f8fdbd5a90d58d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Aug 2011 14:17:41 -0700 Subject: wireless: Remove unnecessary OOM logging messages Removing unnecessary messages saves code and text. Site specific OOM messages are duplications of a generic MM out of memory message and aren't really useful, so just delete them. Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- net/wireless/lib80211_crypt_ccmp.c | 2 -- net/wireless/lib80211_crypt_tkip.c | 4 ---- net/wireless/lib80211_crypt_wep.c | 4 ---- net/wireless/util.c | 5 ++--- 4 files changed, 2 insertions(+), 13 deletions(-) (limited to 'net/wireless/util.c') diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c index dacb3b4b1bd..755738d26bb 100644 --- a/net/wireless/lib80211_crypt_ccmp.c +++ b/net/wireless/lib80211_crypt_ccmp.c @@ -77,8 +77,6 @@ static void *lib80211_ccmp_init(int key_idx) priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tfm)) { - printk(KERN_DEBUG "lib80211_crypt_ccmp: could not allocate " - "crypto API aes\n"); priv->tfm = NULL; goto fail; } diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index 7ea4f2b0770..38734846c19 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -101,7 +101,6 @@ static void *lib80211_tkip_init(int key_idx) priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_arc4)) { - printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); priv->tx_tfm_arc4 = NULL; goto fail; } @@ -109,7 +108,6 @@ static void *lib80211_tkip_init(int key_idx) priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_michael)) { - printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); priv->tx_tfm_michael = NULL; goto fail; } @@ -117,7 +115,6 @@ static void *lib80211_tkip_init(int key_idx) priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_arc4)) { - printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); priv->rx_tfm_arc4 = NULL; goto fail; } @@ -125,7 +122,6 @@ static void *lib80211_tkip_init(int key_idx) priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_michael)) { - printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); priv->rx_tfm_michael = NULL; goto fail; } diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index 2f265e033ae..c1304018fc1 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c @@ -50,16 +50,12 @@ static void *lib80211_wep_init(int keyidx) priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm)) { - printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate " - "crypto API arc4\n"); priv->tx_tfm = NULL; goto fail; } priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm)) { - printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate " - "crypto API arc4\n"); priv->rx_tfm = NULL; goto fail; } diff --git a/net/wireless/util.c b/net/wireless/util.c index eef82f79554..39dbf4ad7ca 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -513,10 +513,9 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, if (head_need) skb_orphan(skb); - if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { - pr_err("failed to reallocate Tx buffer\n"); + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) return -ENOMEM; - } + skb->truesize += head_need; } -- cgit v1.2.3-70-g09d2 From 38ba3c57af1c737966fb58bcbeecdc71f5f4fa90 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 21 Sep 2011 18:14:56 +0300 Subject: cfg80211: Validate cipher suite against supported ciphers Instead of using a hardcoded list of cipher suites in nl80211.c, use a shared function in util.c to verify that the driver advertises support for the specified cipher. This provides more accurate validation of the values and allows vendor-specific cipher suites to be added in drivers. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- net/wireless/core.h | 1 + net/wireless/nl80211.c | 16 ++++------------ net/wireless/util.c | 16 ++++++++++------ 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'net/wireless/util.c') diff --git a/net/wireless/core.h b/net/wireless/core.h index 796a4bdf8b0..cb87b8bbceb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -406,6 +406,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); /* internal helpers */ +bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, bool pairwise, const u8 *mac_addr); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1722998f498..a3e26951fd8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4126,16 +4126,6 @@ static bool nl80211_valid_wpa_versions(u32 wpa_versions) NL80211_WPA_VERSION_2)); } -static bool nl80211_valid_cipher_suite(u32 cipher) -{ - return cipher == WLAN_CIPHER_SUITE_WEP40 || - cipher == WLAN_CIPHER_SUITE_WEP104 || - cipher == WLAN_CIPHER_SUITE_TKIP || - cipher == WLAN_CIPHER_SUITE_CCMP || - cipher == WLAN_CIPHER_SUITE_AES_CMAC; -} - - static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -4268,7 +4258,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, memcpy(settings->ciphers_pairwise, data, len); for (i = 0; i < settings->n_ciphers_pairwise; i++) - if (!nl80211_valid_cipher_suite( + if (!cfg80211_supported_cipher_suite( + &rdev->wiphy, settings->ciphers_pairwise[i])) return -EINVAL; } @@ -4276,7 +4267,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { settings->cipher_group = nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); - if (!nl80211_valid_cipher_suite(settings->cipher_group)) + if (!cfg80211_supported_cipher_suite(&rdev->wiphy, + settings->cipher_group)) return -EINVAL; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 39dbf4ad7ca..6304ed63588 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -151,12 +151,19 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) set_mandatory_flags_band(wiphy->bands[band], band); } +bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher) +{ + int i; + for (i = 0; i < wiphy->n_cipher_suites; i++) + if (cipher == wiphy->cipher_suites[i]) + return true; + return false; +} + int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, bool pairwise, const u8 *mac_addr) { - int i; - if (key_idx > 5) return -EINVAL; @@ -226,10 +233,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, } } - for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) - if (params->cipher == rdev->wiphy.cipher_suites[i]) - break; - if (i == rdev->wiphy.n_cipher_suites) + if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher)) return -EINVAL; return 0; -- cgit v1.2.3-70-g09d2 From 941c93cd039852b7ab02c74f4698c99d82bd6cfe Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 28 Sep 2011 14:12:54 +0300 Subject: mac80211: data path modification for TDLS peers Mark the STA entries of enabled TDLS peers with a new "peer authorized" flag. During link setup, allow special TDLS setup frames through the AP, but otherwise drop all packets destined to the peer. This is required by the TDLS (802.11z) specification in order to prevent reordering of MSDUs between the AP and direct paths. When setup completes and the peer is authorized, send data directly, bypassing the AP. In the Rx path, allow data to be received directly from TDLS peers. Signed-off-by: Arik Nemtsov Cc: Kalyan C Gaddam Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 10 ++++++++++ net/mac80211/sta_info.h | 5 ++++- net/mac80211/tx.c | 42 ++++++++++++++++++++++++++++++++++++++---- net/wireless/util.c | 5 +++-- 4 files changed, 55 insertions(+), 7 deletions(-) (limited to 'net/wireless/util.c') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 119a573af14..bdf9852eec5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2427,6 +2427,7 @@ fail: static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, u8 *peer, enum nl80211_tdls_operation oper) { + struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) @@ -2441,6 +2442,15 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, switch (oper) { case NL80211_TDLS_ENABLE_LINK: + rcu_read_lock(); + sta = sta_info_get(sdata, peer); + if (!sta) { + rcu_read_unlock(); + return -ENOLINK; + } + + set_sta_flags(sta, WLAN_STA_TDLS_PEER_AUTH); + rcu_read_unlock(); break; case NL80211_TDLS_DISABLE_LINK: return sta_info_destroy_addr(sdata, peer); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b6bd4e9d872..c10e2e8632b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -45,7 +45,9 @@ * station in power-save mode, reply when the driver unblocks. * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal * buffers. Automatically cleared on station wake-up. - * @WLAN_STA_TDLS_PEER: station is a TDLS peer. + * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. + * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct + * packets. This means the link is enabled. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -63,6 +65,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_PSPOLL = 1<<13, WLAN_STA_PS_DRIVER_BUF = 1<<14, WLAN_STA_TDLS_PEER = 1<<15, + WLAN_STA_TDLS_PEER_AUTH = 1<<16, }; #define STA_TID_NUM 16 diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 542272acfc1..0ca16880bbb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1726,6 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, struct sta_info *sta = NULL; u32 sta_flags = 0; struct sk_buff *tmp_skb; + bool tdls_direct = false; if (unlikely(skb->len < ETH_HLEN)) { ret = NETDEV_TX_OK; @@ -1837,11 +1838,43 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, break; #endif case NL80211_IFTYPE_STATION: - memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); - if (sdata->u.mgd.use_4addr && - cpu_to_be16(ethertype) != sdata->control_port_protocol) { - fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); + if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { + rcu_read_lock(); + sta = sta_info_get(sdata, skb->data); + if (sta) + sta_flags = get_sta_flags(sta); + rcu_read_unlock(); + + /* + * If the TDLS link is enabled, send everything + * directly. Otherwise, allow TDLS setup frames + * to be transmitted indirectly. + */ + tdls_direct = + (sta_flags & WLAN_STA_TDLS_PEER) && + ((sta_flags & WLAN_STA_TDLS_PEER_AUTH) || + !(ethertype == ETH_P_TDLS && skb->len > 14 && + skb->data[14] == WLAN_TDLS_SNAP_RFTYPE)); + } + + if (tdls_direct) { + /* link during setup - throw out frames to peer */ + if (!(sta_flags & WLAN_STA_TDLS_PEER_AUTH)) { + ret = NETDEV_TX_OK; + goto fail; + } + + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN); + hdrlen = 24; + } else if (sdata->u.mgd.use_4addr && + cpu_to_be16(ethertype) != sdata->control_port_protocol) { + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS); /* RA TA DA SA */ + memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); @@ -1849,6 +1882,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, } else { fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ + memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; diff --git a/net/wireless/util.c b/net/wireless/util.c index 6304ed63588..2f178f73943 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -396,8 +396,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, } break; case cpu_to_le16(0): - if (iftype != NL80211_IFTYPE_ADHOC) - return -1; + if (iftype != NL80211_IFTYPE_ADHOC && + iftype != NL80211_IFTYPE_STATION) + return -1; break; } -- cgit v1.2.3-70-g09d2