diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 15 | ||||
-rw-r--r-- | net/wireless/mlme.c | 39 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 22 | ||||
-rw-r--r-- | net/wireless/reg.c | 6 | ||||
-rw-r--r-- | net/wireless/sme.c | 15 | ||||
-rw-r--r-- | net/wireless/util.c | 24 |
6 files changed, 86 insertions, 35 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index d52da913145..b2234b436ea 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -293,13 +293,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx); + const u8 *key, int key_len, int key_idx, + bool local_state_change); int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx); + const u8 *key, int key_len, int key_idx, + bool local_state_change); int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, @@ -315,13 +317,16 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct cfg80211_crypto_settings *crypt); int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason); + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason); + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason); + const u8 *ie, int ie_len, u16 reason, + bool local_state_change); void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, struct net_device *dev); void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 4bb734a95f5..48ead6f0426 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -378,7 +378,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx) + const u8 *key, int key_len, int key_idx, + bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; @@ -408,6 +409,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, memset(&req, 0, sizeof(req)); + req.local_state_change = local_state_change; req.ie = ie; req.ie_len = ie_len; req.auth_type = auth_type; @@ -434,12 +436,18 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, goto out; } - wdev->authtry_bsses[slot] = bss; + if (local_state_change) + wdev->auth_bsses[slot] = bss; + else + wdev->authtry_bsses[slot] = bss; cfg80211_hold_bss(bss); err = rdev->ops->auth(&rdev->wiphy, dev, &req); if (err) { - wdev->authtry_bsses[slot] = NULL; + if (local_state_change) + wdev->auth_bsses[slot] = NULL; + else + wdev->authtry_bsses[slot] = NULL; cfg80211_unhold_bss(bss); } @@ -454,14 +462,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, const u8 *ie, int ie_len, - const u8 *key, int key_len, int key_idx) + const u8 *key, int key_len, int key_idx, + bool local_state_change) { int err; wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key, key_len, key_idx); + key, key_len, key_idx, local_state_change); wdev_unlock(dev->ieee80211_ptr); return err; @@ -555,7 +564,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_deauth_request req; @@ -565,6 +575,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, memset(&req, 0, sizeof(req)); req.reason_code = reason; + req.local_state_change = local_state_change; req.ie = ie; req.ie_len = ie_len; if (wdev->current_bss && @@ -591,13 +602,15 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); - err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); + err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason, + local_state_change); wdev_unlock(wdev); return err; @@ -605,7 +618,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_disassoc_request req; @@ -620,6 +634,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, memset(&req, 0, sizeof(req)); req.reason_code = reason; + req.local_state_change = local_state_change; req.ie = ie; req.ie_len = ie_len; if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) @@ -632,13 +647,15 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, - const u8 *ie, int ie_len, u16 reason) + const u8 *ie, int ie_len, u16 reason, + bool local_state_change) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); - err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); + err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason, + local_state_change); wdev_unlock(wdev); return err; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 596bf189549..356a84a5dae 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -151,6 +151,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, + [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, }; /* policy for the attributes */ @@ -2097,7 +2098,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) goto out_rtnl; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { err = -EINVAL; goto out; } @@ -3393,6 +3395,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) int err, ssid_len, ie_len = 0; enum nl80211_auth_type auth_type; struct key_parse key; + bool local_state_change; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3471,9 +3474,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, - key.p.key, key.p.key_len, key.idx); + key.p.key, key.p.key_len, key.idx, + local_state_change); out: cfg80211_unlock_rdev(rdev); @@ -3650,6 +3656,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) const u8 *ie = NULL, *bssid; int err, ie_len = 0; u16 reason_code; + bool local_state_change; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3695,7 +3702,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + + err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); out: cfg80211_unlock_rdev(rdev); @@ -3712,6 +3722,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) const u8 *ie = NULL, *bssid; int err, ie_len = 0; u16 reason_code; + bool local_state_change; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; @@ -3757,7 +3768,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); + local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; + + err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); out: cfg80211_unlock_rdev(rdev); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 422da20d1e5..8f0d97dd310 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2356,10 +2356,10 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) rdev->country_ie_alpha2[1]); } else printk(KERN_INFO "cfg80211: Current regulatory " - "domain intersected: \n"); + "domain intersected:\n"); } else - printk(KERN_INFO "cfg80211: Current regulatory " - "domain intersected: \n"); + printk(KERN_INFO "cfg80211: Current regulatory " + "domain intersected:\n"); } else if (is_world_regdom(rd->alpha2)) printk(KERN_INFO "cfg80211: World regulatory " "domain updated:\n"); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f4dfd5f5f2e..c2735775ec1 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -171,7 +171,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) params->ssid, params->ssid_len, NULL, 0, params->key, params->key_len, - params->key_idx); + params->key_idx, false); case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; @@ -186,12 +186,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) if (err) __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, NULL, 0, - WLAN_REASON_DEAUTH_LEAVING); + WLAN_REASON_DEAUTH_LEAVING, + false); return err; case CFG80211_CONN_DEAUTH_ASSOC_FAIL: __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, NULL, 0, - WLAN_REASON_DEAUTH_LEAVING); + WLAN_REASON_DEAUTH_LEAVING, false); /* return an error so that we call __cfg80211_connect_result() */ return -EINVAL; default: @@ -676,7 +677,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, continue; bssid = wdev->auth_bsses[i]->pub.bssid; ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, - WLAN_REASON_DEAUTH_LEAVING); + WLAN_REASON_DEAUTH_LEAVING, + false); WARN(ret, "deauth failed: %d\n", ret); } } @@ -935,7 +937,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, /* wdev->conn->params.bssid must be set if > SCANNING */ err = __cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, - NULL, 0, reason); + NULL, 0, reason, false); if (err) return err; } else { @@ -991,7 +993,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx) memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); if (__cfg80211_mlme_deauth(rdev, dev, bssid, - NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { + NULL, 0, WLAN_REASON_DEAUTH_LEAVING, + false)) { /* whatever -- assume gone anyway */ cfg80211_unhold_bss(wdev->auth_bsses[idx]); cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); diff --git a/net/wireless/util.c b/net/wireless/util.c index d3574a4eb3b..3416373a9c0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -331,11 +331,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, if (iftype == NL80211_IFTYPE_MESH_POINT) { struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); - hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + /* make sure meshdr->flags is on the linear part */ + if (!pskb_may_pull(skb, hdrlen + 1)) + return -1; if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { - memcpy(dst, meshdr->eaddr1, ETH_ALEN); - memcpy(src, meshdr->eaddr2, ETH_ALEN); + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr1), + dst, ETH_ALEN); + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr2), + src, ETH_ALEN); } + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); } break; case cpu_to_le16(IEEE80211_FCTL_FROMDS): @@ -347,9 +354,14 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, if (iftype == NL80211_IFTYPE_MESH_POINT) { struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); - hdrlen += ieee80211_get_mesh_hdrlen(meshdr); + /* make sure meshdr->flags is on the linear part */ + if (!pskb_may_pull(skb, hdrlen + 1)) + return -1; if (meshdr->flags & MESH_FLAGS_AE_A4) - memcpy(src, meshdr->eaddr1, ETH_ALEN); + skb_copy_bits(skb, hdrlen + + offsetof(struct ieee80211s_hdr, eaddr1), + src, ETH_ALEN); + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); } break; case cpu_to_le16(0): @@ -358,7 +370,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, break; } - if (unlikely(skb->len - hdrlen < 8)) + if (!pskb_may_pull(skb, hdrlen + 8)) return -1; payload = skb->data + hdrlen; |