From c61029c77fb68d7a182c0ae010f0f9dcae4e196c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 5 Aug 2010 14:26:24 -0400 Subject: wireless: upcase alpha2 values in queue_regulatory_request This provides a little more flexibility for human users, and it allows us to use isalpha rather than the custom is_alpha_upper. Signed-off-by: John W. Linville --- net/wireless/reg.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f180db0de66..b0d9a08447c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -181,14 +182,6 @@ static bool is_alpha2_set(const char *alpha2) return false; } -static bool is_alpha_upper(char letter) -{ - /* ASCII A - Z */ - if (letter >= 65 && letter <= 90) - return true; - return false; -} - static bool is_unknown_alpha2(const char *alpha2) { if (!alpha2) @@ -220,7 +213,7 @@ static bool is_an_alpha2(const char *alpha2) { if (!alpha2) return false; - if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1])) + if (isalpha(alpha2[0]) && isalpha(alpha2[1])) return true; return false; } @@ -1399,6 +1392,11 @@ static DECLARE_WORK(reg_work, reg_todo); static void queue_regulatory_request(struct regulatory_request *request) { + if (isalpha(request->alpha2[0])) + request->alpha2[0] = toupper(request->alpha2[0]); + if (isalpha(request->alpha2[1])) + request->alpha2[1] = toupper(request->alpha2[1]); + spin_lock(®_requests_lock); list_add_tail(&request->list, ®_requests_list); spin_unlock(®_requests_lock); -- cgit v1.2.3 From 3f3b6a8d90b6e762e2bb83e6a9e86d9534b56cdc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2010 10:20:27 +0200 Subject: cfg80211: deauth doesn't always imply disconnect When an AP sends a deauth frame, or we send one to an AP, that only means we lost our connection if we were actually connected to that AP. Check this to avoid sending spurious "disconnected" events and breaking "iw ... link" reporting. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d1a3fb99fdf..ee0af32ed59 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -149,7 +149,7 @@ void __cfg80211_send_deauth(struct net_device *dev, struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; const u8 *bssid = mgmt->bssid; int i; - bool found = false; + bool found = false, was_current = false; ASSERT_WDEV_LOCK(wdev); @@ -159,6 +159,7 @@ void __cfg80211_send_deauth(struct net_device *dev, cfg80211_put_bss(&wdev->current_bss->pub); wdev->current_bss = NULL; found = true; + was_current = true; } else for (i = 0; i < MAX_AUTH_BSSES; i++) { if (wdev->auth_bsses[i] && memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { @@ -183,7 +184,7 @@ void __cfg80211_send_deauth(struct net_device *dev, nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); - if (wdev->sme_state == CFG80211_SME_CONNECTED) { + if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { u16 reason_code; bool from_ap; -- cgit v1.2.3 From 04600794958f1833f5571c6cde40f260ab557f55 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 5 Aug 2010 17:45:15 +0200 Subject: cfg80211: support sysfs namespaces Enable using network namespaces with wireless devices even when sysfs is enabled using the same infrastructure that was built for netdevs. Signed-off-by: Johannes Berg Acked-by: "Eric W. Biederman" Signed-off-by: John W. Linville --- net/wireless/core.c | 7 ++++++- net/wireless/sysfs.c | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index 541e2fff5e9..c70909c3eae 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -253,11 +253,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, WARN_ON(err); wdev->netdev->features |= NETIF_F_NETNS_LOCAL; } + + return err; } wiphy_net_set(&rdev->wiphy, net); - return err; + err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); + WARN_ON(err); + + return 0; } static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 9f2cef3e0ca..74a9e3cce45 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -110,6 +110,13 @@ static int wiphy_resume(struct device *dev) return ret; } +static const void *wiphy_namespace(struct device *d) +{ + struct wiphy *wiphy = container_of(d, struct wiphy, dev); + + return wiphy_net(wiphy); +} + struct class ieee80211_class = { .name = "ieee80211", .owner = THIS_MODULE, @@ -120,6 +127,8 @@ struct class ieee80211_class = { #endif .suspend = wiphy_suspend, .resume = wiphy_resume, + .ns_type = &net_ns_type_operations, + .namespace = wiphy_namespace, }; int wiphy_sysfs_init(void) -- cgit v1.2.3 From afea0b7af7a0c070da8b2029d721abc930e5f96f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 Aug 2010 09:46:42 +0200 Subject: cfg80211: check if WEP is available for shared key auth When shared key auth is requested, cfg80211 should verify that the device is capable of WEP crypto which is required. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37902a54e9c..bb5b78eebeb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3572,6 +3572,21 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; + if (key.idx >= 0) { + int i; + bool ok = false; + for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) { + if (key.p.cipher == rdev->wiphy.cipher_suites[i]) { + ok = true; + break; + } + } + if (!ok) { + err = -EINVAL; + goto out; + } + } + if (!rdev->ops->auth) { err = -EOPNOTSUPP; goto out; -- cgit v1.2.3 From 633adf1ad1c92c02bd3f10bbd73737a969179378 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 Aug 2010 14:49:58 +0200 Subject: cfg80211: mark ieee80211_hdrlen const This function analyses only its single, value-passed argument, and has no side effects. Thus it can be const, which makes mac80211 smaller, for example: text data bss dec hex filename 362518 16720 884 380122 5ccda mac80211.ko (before) 362358 16720 884 379962 5cc3a mac80211.ko (after) a 160 byte saving in text size, and an optimisation because the function won't be called as often. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/util.c b/net/wireless/util.c index 0c8a1e8b769..1eb24162be6 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -221,7 +221,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); -unsigned int ieee80211_hdrlen(__le16 fc) +unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) { unsigned int hdrlen = 24; -- cgit v1.2.3 From 2e161f78e5f63a7f9fd25a766bb7f816a01eb14a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 Aug 2010 15:38:38 +0200 Subject: cfg80211/mac80211: extensible frame processing Allow userspace to register for more than just action frames by giving the frame subtype, and make it possible to use this in various modes as well. With some tweaks and some added functionality this will, in the future, also be usable in AP mode and be able to replace the cooked monitor interface currently used in that case. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.c | 8 +-- net/wireless/core.h | 21 ++++---- net/wireless/mlme.c | 144 ++++++++++++++++++++++++++++++++----------------- net/wireless/nl80211.c | 108 +++++++++++++++++++++++++++---------- net/wireless/nl80211.h | 14 ++--- net/wireless/util.c | 2 +- 6 files changed, 197 insertions(+), 100 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index c70909c3eae..d52630bbab0 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -433,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy) /* sanity check ifmodes */ WARN_ON(!ifmodes); - ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; + ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; if (WARN_ON(ifmodes != wiphy->interface_modes)) wiphy->interface_modes = ifmodes; @@ -685,8 +685,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); INIT_LIST_HEAD(&wdev->event_list); spin_lock_init(&wdev->event_lock); - INIT_LIST_HEAD(&wdev->action_registrations); - spin_lock_init(&wdev->action_registrations_lock); + INIT_LIST_HEAD(&wdev->mgmt_registrations); + spin_lock_init(&wdev->mgmt_registrations_lock); mutex_lock(&rdev->devlist_mtx); list_add_rcu(&wdev->list, &rdev->netdev_list); @@ -806,7 +806,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_rcu(&wdev->list); rdev->devlist_generation++; - cfg80211_mlme_purge_actions(wdev); + cfg80211_mlme_purge_registrations(wdev); #ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.keys); #endif diff --git a/net/wireless/core.h b/net/wireless/core.h index 63d57ae399c..58ab2c791d2 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -331,16 +331,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *resp_ie, size_t resp_ie_len, u16 status, bool wextev, struct cfg80211_bss *bss); -int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, - const u8 *match_data, int match_len); -void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); -void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); -int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, - const u8 *buf, size_t len, u64 *cookie); +int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, + u16 frame_type, const u8 *match_data, + int match_len); +void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); +void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); +int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, + const u8 *buf, size_t len, u64 *cookie); /* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ee0af32ed59..8515b1e5c57 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -748,31 +748,51 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, } EXPORT_SYMBOL(cfg80211_new_sta); -struct cfg80211_action_registration { +struct cfg80211_mgmt_registration { struct list_head list; u32 nlpid; int match_len; + __le16 frame_type; + u8 match[]; }; -int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, - const u8 *match_data, int match_len) +int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, + u16 frame_type, const u8 *match_data, + int match_len) { - struct cfg80211_action_registration *reg, *nreg; + struct cfg80211_mgmt_registration *reg, *nreg; int err = 0; + u16 mgmt_type; + + if (!wdev->wiphy->mgmt_stypes) + return -EOPNOTSUPP; + + if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) + return -EINVAL; + + if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) + return -EINVAL; + + mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; + if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) + return -EINVAL; nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); if (!nreg) return -ENOMEM; - spin_lock_bh(&wdev->action_registrations_lock); + spin_lock_bh(&wdev->mgmt_registrations_lock); - list_for_each_entry(reg, &wdev->action_registrations, list) { + list_for_each_entry(reg, &wdev->mgmt_registrations, list) { int mlen = min(match_len, reg->match_len); + if (frame_type != le16_to_cpu(reg->frame_type)) + continue; + if (memcmp(reg->match, match_data, mlen) == 0) { err = -EALREADY; break; @@ -787,62 +807,75 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, memcpy(nreg->match, match_data, match_len); nreg->match_len = match_len; nreg->nlpid = snd_pid; - list_add(&nreg->list, &wdev->action_registrations); + nreg->frame_type = cpu_to_le16(frame_type); + list_add(&nreg->list, &wdev->mgmt_registrations); out: - spin_unlock_bh(&wdev->action_registrations_lock); + spin_unlock_bh(&wdev->mgmt_registrations_lock); return err; } -void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) +void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) { - struct cfg80211_action_registration *reg, *tmp; + struct cfg80211_mgmt_registration *reg, *tmp; - spin_lock_bh(&wdev->action_registrations_lock); + spin_lock_bh(&wdev->mgmt_registrations_lock); - list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { if (reg->nlpid == nlpid) { list_del(®->list); kfree(reg); } } - spin_unlock_bh(&wdev->action_registrations_lock); + spin_unlock_bh(&wdev->mgmt_registrations_lock); } -void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) +void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) { - struct cfg80211_action_registration *reg, *tmp; + struct cfg80211_mgmt_registration *reg, *tmp; - spin_lock_bh(&wdev->action_registrations_lock); + spin_lock_bh(&wdev->mgmt_registrations_lock); - list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { + list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { list_del(®->list); kfree(reg); } - spin_unlock_bh(&wdev->action_registrations_lock); + spin_unlock_bh(&wdev->mgmt_registrations_lock); } -int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, - struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - bool channel_type_valid, - const u8 *buf, size_t len, u64 *cookie) +int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, + const u8 *buf, size_t len, u64 *cookie) { struct wireless_dev *wdev = dev->ieee80211_ptr; const struct ieee80211_mgmt *mgmt; + u16 stype; + + if (!wdev->wiphy->mgmt_stypes) + return -EOPNOTSUPP; - if (rdev->ops->action == NULL) + if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; + if (len < 24 + 1) return -EINVAL; mgmt = (const struct ieee80211_mgmt *) buf; - if (!ieee80211_is_action(mgmt->frame_control)) + + if (!ieee80211_is_mgmt(mgmt->frame_control)) return -EINVAL; - if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { + + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; + if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) + return -EINVAL; + + if (ieee80211_is_action(mgmt->frame_control) && + mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { /* Verify that we are associated with the destination AP */ wdev_lock(wdev); @@ -863,64 +896,75 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, return -EINVAL; /* Transmit the Action frame as requested by user space */ - return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, - channel_type_valid, buf, len, cookie); + return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, + channel_type_valid, buf, len, cookie); } -bool cfg80211_rx_action(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, const u8 *buf, + size_t len, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct cfg80211_action_registration *reg; - const u8 *action_data; - int action_data_len; + struct cfg80211_mgmt_registration *reg; + const struct ieee80211_txrx_stypes *stypes = + &wiphy->mgmt_stypes[wdev->iftype]; + struct ieee80211_mgmt *mgmt = (void *)buf; + const u8 *data; + int data_len; bool result = false; + __le16 ftype = mgmt->frame_control & + cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + u16 stype; - /* frame length - min size excluding category */ - action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); + stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; - /* action data starts with category */ - action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; + if (!(stypes->rx & BIT(stype))) + return false; - spin_lock_bh(&wdev->action_registrations_lock); + data = buf + ieee80211_hdrlen(mgmt->frame_control); + data_len = len - ieee80211_hdrlen(mgmt->frame_control); + + spin_lock_bh(&wdev->mgmt_registrations_lock); + + list_for_each_entry(reg, &wdev->mgmt_registrations, list) { + if (reg->frame_type != ftype) + continue; - list_for_each_entry(reg, &wdev->action_registrations, list) { - if (reg->match_len > action_data_len) + if (reg->match_len > data_len) continue; - if (memcmp(reg->match, action_data, reg->match_len)) + if (memcmp(reg->match, data, reg->match_len)) continue; /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_action(rdev, dev, reg->nlpid, freq, - buf, len, gfp)) + if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, + buf, len, gfp)) continue; result = true; break; } - spin_unlock_bh(&wdev->action_registrations_lock); + spin_unlock_bh(&wdev->mgmt_registrations_lock); return result; } -EXPORT_SYMBOL(cfg80211_rx_action); +EXPORT_SYMBOL(cfg80211_rx_mgmt); -void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, - const u8 *buf, size_t len, bool ack, gfp_t gfp) +void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, + const u8 *buf, size_t len, bool ack, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); /* Indicate TX status of the Action frame to user space */ - nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); + nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); } -EXPORT_SYMBOL(cfg80211_action_tx_status); +EXPORT_SYMBOL(cfg80211_mgmt_tx_status); void cfg80211_cqm_rssi_notify(struct net_device *dev, enum nl80211_cqm_rssi_threshold_event rssi_event, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bb5b78eebeb..927ffbd2aeb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -156,6 +156,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, + [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, }; /* policy for the attributes */ @@ -437,6 +438,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct ieee80211_rate *rate; int i; u16 ifmodes = dev->wiphy.interface_modes; + const struct ieee80211_txrx_stypes *mgmt_stypes = + dev->wiphy.mgmt_stypes; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); if (!hdr) @@ -587,7 +590,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(flush_pmksa, FLUSH_PMKSA); CMD(remain_on_channel, REMAIN_ON_CHANNEL); CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); - CMD(action, ACTION); + CMD(mgmt_tx, FRAME); if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); @@ -608,6 +611,53 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_cmds); + if (mgmt_stypes) { + u16 stypes; + struct nlattr *nl_ftypes, *nl_ifs; + enum nl80211_iftype ift; + + nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); + if (!nl_ifs) + goto nla_put_failure; + + for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { + nl_ftypes = nla_nest_start(msg, ift); + if (!nl_ftypes) + goto nla_put_failure; + i = 0; + stypes = mgmt_stypes[ift].tx; + while (stypes) { + if (stypes & 1) + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, + (i << 4) | IEEE80211_FTYPE_MGMT); + stypes >>= 1; + i++; + } + nla_nest_end(msg, nl_ftypes); + } + + nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); + if (!nl_ifs) + goto nla_put_failure; + + for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { + nl_ftypes = nla_nest_start(msg, ift); + if (!nl_ftypes) + goto nla_put_failure; + i = 0; + stypes = mgmt_stypes[ift].rx; + while (stypes) { + if (stypes & 1) + NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, + (i << 4) | IEEE80211_FTYPE_MGMT); + stypes >>= 1; + i++; + } + nla_nest_end(msg, nl_ftypes); + } + nla_nest_end(msg, nl_ifs); + } + return genlmsg_end(msg, hdr); nla_put_failure: @@ -4732,17 +4782,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, return err; } -static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) +static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; struct net_device *dev; + u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; int err; if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) return -EINVAL; - if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) - return -EINVAL; + if (info->attrs[NL80211_ATTR_FRAME_TYPE]) + frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); rtnl_lock(); @@ -4757,12 +4808,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) } /* not much point in registering if we can't reply */ - if (!rdev->ops->action) { + if (!rdev->ops->mgmt_tx) { err = -EOPNOTSUPP; goto out; } - err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, + err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, + frame_type, nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); out: @@ -4773,7 +4825,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) return err; } -static int nl80211_action(struct sk_buff *skb, struct genl_info *info) +static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; struct net_device *dev; @@ -4796,7 +4848,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - if (!rdev->ops->action) { + if (!rdev->ops->mgmt_tx) { err = -EOPNOTSUPP; goto out; } @@ -4839,17 +4891,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) } hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, - NL80211_CMD_ACTION); + NL80211_CMD_FRAME); if (IS_ERR(hdr)) { err = PTR_ERR(hdr); goto free_msg; } - err = cfg80211_mlme_action(rdev, dev, chan, channel_type, - channel_type_valid, - nla_data(info->attrs[NL80211_ATTR_FRAME]), - nla_len(info->attrs[NL80211_ATTR_FRAME]), - &cookie); + err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, + channel_type_valid, + nla_data(info->attrs[NL80211_ATTR_FRAME]), + nla_len(info->attrs[NL80211_ATTR_FRAME]), + &cookie); if (err) goto free_msg; @@ -5348,14 +5400,14 @@ static struct genl_ops nl80211_ops[] = { .flags = GENL_ADMIN_PERM, }, { - .cmd = NL80211_CMD_REGISTER_ACTION, - .doit = nl80211_register_action, + .cmd = NL80211_CMD_REGISTER_FRAME, + .doit = nl80211_register_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, { - .cmd = NL80211_CMD_ACTION, - .doit = nl80211_action, + .cmd = NL80211_CMD_FRAME, + .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, @@ -6055,9 +6107,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, nl80211_mlme_mcgrp.id, gfp); } -int nl80211_send_action(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, - int freq, const u8 *buf, size_t len, gfp_t gfp) +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) { struct sk_buff *msg; void *hdr; @@ -6067,7 +6119,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, if (!msg) return -ENOMEM; - hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); if (!hdr) { nlmsg_free(msg); return -ENOMEM; @@ -6095,10 +6147,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, return -ENOBUFS; } -void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - const u8 *buf, size_t len, bool ack, - gfp_t gfp) +void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -6107,7 +6159,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, if (!msg) return; - hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); if (!hdr) { nlmsg_free(msg); return; @@ -6194,7 +6246,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) - cfg80211_mlme_unregister_actions(wdev, notify->pid); + cfg80211_mlme_unregister_socket(wdev, notify->pid); rcu_read_unlock(); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2ad7fbc7d9f..30d2f939150 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); -int nl80211_send_action(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, int freq, - const u8 *buf, size_t len, gfp_t gfp); -void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, - const u8 *buf, size_t len, bool ack, - gfp_t gfp); +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); +void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u64 cookie, + const u8 *buf, size_t len, bool ack, + gfp_t gfp); void nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/util.c b/net/wireless/util.c index 1eb24162be6..8d961cc4ae9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -823,7 +823,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, /* monitor can't bridge anyway */ break; case NL80211_IFTYPE_UNSPECIFIED: - case __NL80211_IFTYPE_AFTER_LAST: + case NUM_NL80211_IFTYPES: /* not happening */ break; } -- cgit v1.2.3 From 74b70a4e38d542843fccfb367dce1ac861cc3890 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 24 Aug 2010 12:15:53 +0200 Subject: nl80211: fix missing nesting commit 95a6ccbb46c70cff376684c752831c014c87029d Author: Johannes Berg Date: Thu Aug 12 15:38:38 2010 +0200 cfg80211/mac80211: extensible frame processing introduced a netlink bug that caused parsing errors in userspace because it forgot to close a nesting, which would advertise a nesting length of zero to userspace, which then completely threw off parsing and led to Illegal nla->nla_type == 0 being printed by libnl. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 927ffbd2aeb..49f5ca35e78 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -636,6 +636,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_ftypes); } + nla_nest_end(msg, nl_ifs); + nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); if (!nl_ifs) goto nla_put_failure; -- cgit v1.2.3 From 7d64b7cc1fc33bab24567903a93f699d11649c0b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Aug 2010 14:26:51 +0300 Subject: cfg80211: allow vendor specific cipher suites cfg80211 currently rejects all cipher suites it doesn't know about for key length checking purposes. This can lead to inconsistencies when a driver advertises an algorithm that cfg80211 doesn't know about. Remove this rejection so drivers can specify any algorithm they like. Signed-off-by: Johannes Berg Signed-off-by: Juuso Oikarinen Signed-off-by: John W. Linville --- net/wireless/util.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/util.c b/net/wireless/util.c index 8d961cc4ae9..bca32eb8f44 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -183,7 +183,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, return -EINVAL; break; default: - return -EINVAL; + /* + * We don't know anything about this algorithm, + * allow using it -- but the driver must check + * all parameters! We still check below whether + * or not the driver supports this algorithm, + * of course. + */ + break; } if (params->seq) { -- cgit v1.2.3 From c0692b8fe29fb4d4dad33487aabf3ed7e1e880c0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Aug 2010 14:26:53 +0300 Subject: cfg80211: allow changing port control protocol Some vendor specified mechanisms for 802.1X-style functionality use a different protocol than EAP (even if EAP is vendor-extensible). Allow setting the ethertype for the protocol when a driver has support for this. The default if unspecified is EAP, of course. Note: This is suitable only for station mode, not for AP implementation. Signed-off-by: Johannes Berg Signed-off-by: Juuso Oikarinen Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 25 ++++++++++++++++++++++--- net/wireless/wext-sme.c | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 49f5ca35e78..85a23de7bff 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -136,6 +136,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { .len = sizeof(struct nl80211_sta_flag_update), }, [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, + [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 }, + [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -474,6 +476,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, dev->wiphy.max_num_pmkids); + if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) + NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); + nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); if (!nl_modes) goto nla_put_failure; @@ -3691,7 +3696,8 @@ unlock_rtnl: return err; } -static int nl80211_crypto_settings(struct genl_info *info, +static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, + struct genl_info *info, struct cfg80211_crypto_settings *settings, int cipher_limit) { @@ -3699,6 +3705,19 @@ static int nl80211_crypto_settings(struct genl_info *info, settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; + if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { + u16 proto; + proto = nla_get_u16( + info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + settings->control_port_ethertype = cpu_to_be16(proto); + if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && + proto != ETH_P_PAE) + return -EINVAL; + if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) + settings->control_port_no_encrypt = true; + } else + settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); + if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { void *data; int len, i; @@ -3826,7 +3845,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_PREV_BSSID]) prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); - err = nl80211_crypto_settings(info, &crypto, 1); + err = nl80211_crypto_settings(rdev, info, &crypto, 1); if (!err) err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, ssid, ssid_len, ie, ie_len, use_mfp, @@ -4303,7 +4322,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; - err = nl80211_crypto_settings(info, &connect.crypto, + err = nl80211_crypto_settings(rdev, info, &connect.crypto, NL80211_MAX_NR_CIPHER_SUITES); if (err) return err; diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 9818198add8..6fffe62d7c2 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, wdev->wext.connect.ssid_len = len; wdev->wext.connect.crypto.control_port = false; + wdev->wext.connect.crypto.control_port_ethertype = + cpu_to_be16(ETH_P_PAE); err = cfg80211_mgd_wext_connect(rdev, wdev); out: -- cgit v1.2.3 From 3653910714a4a9b19aadb202c24f7b1ae61d3556 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 28 Aug 2010 17:41:06 +0200 Subject: net/wireless: Remove double test The same expression is tested twice and the result is the same each time. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @expression@ expression E; @@ ( * E || ... || E | * E && ... && E ) // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- net/wireless/wext-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 0ef17bc42ba..40385936e28 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) #endif #ifdef CONFIG_CFG80211_WEXT - if (dev->ieee80211_ptr && dev->ieee80211_ptr && + if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy && dev->ieee80211_ptr->wiphy->wext && dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) -- cgit v1.2.3 From 942623166df3256821e8451273bc07737745e3cb Mon Sep 17 00:00:00 2001 From: Nikitas Angelinas Date: Wed, 8 Sep 2010 22:29:53 +0100 Subject: net/wireless: use ARRAY_SIZE macro in radiotap.c Replace sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]) with ARRAY_SIZE(rtap_namespace_sizes) in net/wireless/radiotap.c Signed-off-by: Nikitas Angelinas Signed-off-by: John W. Linville --- net/wireless/radiotap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index 1332c445d1c..c774bc0f155 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c @@ -14,6 +14,7 @@ * See COPYING for more details. */ +#include #include #include #include @@ -45,7 +46,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = { }; static const struct ieee80211_radiotap_namespace radiotap_ns = { - .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), + .n_bits = ARRAY_SIZE(rtap_namespace_sizes), .align_size = rtap_namespace_sizes, }; -- cgit v1.2.3 From a1e567c83f541432e687142570215b75bebb1338 Mon Sep 17 00:00:00 2001 From: Bill Jordan Date: Fri, 10 Sep 2010 11:22:32 -0400 Subject: nl80211: Uninitialized variable There is a path in nl80211_set_wiphy where result is tested but uninitialized. I am hitting this path when I attempt: sh# iw dev wlan0 set channel 10 command failed: Unknown error 1069727332 (-1069727332) Signed-off-by: William Jordan Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 85a23de7bff..1d6ef24254f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -833,7 +833,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev; struct net_device *netdev = NULL; struct wireless_dev *wdev; - int result, rem_txq_params = 0; + int result = 0, rem_txq_params = 0; struct nlattr *nl_txq_params; u32 changed; u8 retry_short = 0, retry_long = 0; -- cgit v1.2.3 From 9c376639297d3dd82d40e54c9cdca8da9dfc22f1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 20 Aug 2010 15:13:59 -0700 Subject: include/net/cfg80211.h: wiphy_ messages use dev_printk The output becomes: [ 41.261941] ieee80211 phy0: Selected rate control algorithm 'minstrel_ht' Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- net/wireless/core.c | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index d52630bbab0..b8191cf8622 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -912,52 +912,3 @@ static void __exit cfg80211_exit(void) destroy_workqueue(cfg80211_wq); } module_exit(cfg80211_exit); - -static int ___wiphy_printk(const char *level, const struct wiphy *wiphy, - struct va_format *vaf) -{ - if (!wiphy) - return printk("%s(NULL wiphy *): %pV", level, vaf); - - return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf); -} - -int __wiphy_printk(const char *level, const struct wiphy *wiphy, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int r; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - r = ___wiphy_printk(level, wiphy, &vaf); - va_end(args); - - return r; -} -EXPORT_SYMBOL(__wiphy_printk); - -#define define_wiphy_printk_level(func, kern_level) \ -int func(const struct wiphy *wiphy, const char *fmt, ...) \ -{ \ - struct va_format vaf; \ - va_list args; \ - int r; \ - \ - va_start(args, fmt); \ - \ - vaf.fmt = fmt; \ - vaf.va = &args; \ - \ - r = ___wiphy_printk(kern_level, wiphy, &vaf); \ - va_end(args); \ - \ - return r; \ -} \ -EXPORT_SYMBOL(func); - -define_wiphy_printk_level(wiphy_debug, KERN_DEBUG); -- cgit v1.2.3 From 46a5ebaf02d69e26ee0f47a0b8d2d9bc619240d4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Sep 2010 13:28:15 +0200 Subject: cfg80211/mac80211: use lockdep_assert_held Instead of using a WARN_ON(!mutex_is_locked()) use lockdep_assert_held() which compiles away completely when lockdep isn't enabled, and also is a more accurate assertion since it checks that the current thread is holding the mutex. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 9 ++++++--- net/wireless/reg.c | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.h b/net/wireless/core.h index 58ab2c791d2..37580e090a3 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -95,7 +95,10 @@ extern struct mutex cfg80211_mutex; extern struct list_head cfg80211_rdev_list; extern int cfg80211_rdev_list_generation; -#define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) +static inline void assert_cfg80211_lock(void) +{ + lockdep_assert_held(&cfg80211_mutex); +} /* * You can use this to mark a wiphy_idx as not having an associated wiphy. @@ -202,8 +205,8 @@ static inline void wdev_unlock(struct wireless_dev *wdev) mutex_unlock(&wdev->mtx); } -#define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); -#define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); +#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) +#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) enum cfg80211_event_type { EVENT_CONNECT_RESULT, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b0d9a08447c..d14bbf960c1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -74,7 +74,11 @@ const struct ieee80211_regdomain *cfg80211_regdomain; * - last_request */ static DEFINE_MUTEX(reg_mutex); -#define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) + +static inline void assert_reg_lock(void) +{ + lockdep_assert_held(®_mutex); +} /* Used to queue up regulatory hints */ static LIST_HEAD(reg_requests_list); -- cgit v1.2.3 From 074ac8df9f93f2a35a356d92fd7f16cd846f0a03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 16 Sep 2010 14:58:22 +0200 Subject: cfg80211/nl80211: introduce p2p device types This adds P2P-STA and P2P-GO as device types so we can distinguish between those and normal STA or AP (respectively) type interfaces. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.c | 2 ++ net/wireless/mlme.c | 3 ++- net/wireless/nl80211.c | 56 +++++++++++++++++++++++++++++++++++--------------- net/wireless/sme.c | 9 +++++--- net/wireless/util.c | 15 +++++++++++--- 5 files changed, 61 insertions(+), 24 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index b8191cf8622..ff9615a7ee7 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -726,6 +726,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, dev->ethtool_ops = &cfg80211_ethtool_ops; if ((wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) dev->priv_flags |= IFF_DONT_BRIDGE; break; @@ -734,6 +735,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, true); break; + case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8515b1e5c57..46f37116089 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -882,7 +882,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (!wdev->current_bss || memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, ETH_ALEN) != 0 || - (wdev->iftype == NL80211_IFTYPE_STATION && + ((wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && memcmp(wdev->current_bss->pub.bssid, mgmt->da, ETH_ALEN) != 0)) { wdev_unlock(wdev); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1d6ef24254f..f15b1af2c76 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -410,12 +410,14 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: break; case NL80211_IFTYPE_ADHOC: if (!wdev->current_bss) return -ENOLINK; break; case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: if (wdev->sme_state != CFG80211_SME_CONNECTED) return -ENOLINK; break; @@ -766,7 +768,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_AP || wdev->iftype == NL80211_IFTYPE_WDS || wdev->iftype == NL80211_IFTYPE_MESH_POINT || - wdev->iftype == NL80211_IFTYPE_MONITOR; + wdev->iftype == NL80211_IFTYPE_MONITOR || + wdev->iftype == NL80211_IFTYPE_P2P_GO; } static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, @@ -1693,7 +1696,8 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } @@ -1785,7 +1789,8 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } @@ -2128,10 +2133,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: /* disallow mesh-specific things */ if (params.plink_action) err = -EINVAL; break; + case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: /* disallow everything but AUTHORIZED flag */ if (params.plink_action) @@ -2233,7 +2240,8 @@ static int nl80211_new_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_P2P_GO) { err = -EINVAL; goto out; } @@ -2286,7 +2294,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EINVAL; goto out; } @@ -2660,7 +2669,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } @@ -3363,6 +3373,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, } switch (wdev->iftype) { + case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: if (intbss == wdev->current_bss) NLA_PUT_U32(msg, NL80211_BSS_STATUS, @@ -3649,7 +3660,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -3804,7 +3816,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -3888,7 +3901,8 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -3954,7 +3968,8 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) goto out; } - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4332,7 +4347,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4408,7 +4424,8 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4496,7 +4513,8 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4541,7 +4559,8 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) if (err) goto out_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4823,7 +4842,8 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) goto unlock_rtnl; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -4875,7 +4895,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto out; } @@ -5093,7 +5114,8 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, goto unlock_rdev; } - if (wdev->iftype != NL80211_IFTYPE_STATION) { + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { err = -EOPNOTSUPP; goto unlock_rdev; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index a8c2d6b877a..f161b984454 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -411,7 +411,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, ASSERT_WDEV_LOCK(wdev); - if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) return; if (wdev->sme_state != CFG80211_SME_CONNECTING) @@ -548,7 +549,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, ASSERT_WDEV_LOCK(wdev); - if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) return; if (wdev->sme_state != CFG80211_SME_CONNECTED) @@ -644,7 +646,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, ASSERT_WDEV_LOCK(wdev); - if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) return; if (wdev->sme_state != CFG80211_SME_CONNECTED) diff --git a/net/wireless/util.c b/net/wireless/util.c index bca32eb8f44..fb5448f7d55 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -326,7 +326,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case cpu_to_le16(IEEE80211_FCTL_TODS): if (unlikely(iftype != NL80211_IFTYPE_AP && - iftype != NL80211_IFTYPE_AP_VLAN)) + iftype != NL80211_IFTYPE_AP_VLAN && + iftype != NL80211_IFTYPE_P2P_GO)) return -1; break; case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): @@ -354,7 +355,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, break; case cpu_to_le16(IEEE80211_FCTL_FROMDS): if ((iftype != NL80211_IFTYPE_STATION && - iftype != NL80211_IFTYPE_MESH_POINT) || + iftype != NL80211_IFTYPE_P2P_CLIENT && + iftype != NL80211_IFTYPE_MESH_POINT) || (is_multicast_ether_addr(dst) && !compare_ether_addr(src, addr))) return -1; @@ -431,6 +433,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, switch (iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); @@ -439,6 +442,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, hdrlen = 24; break; case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: fc |= cpu_to_le16(IEEE80211_FCTL_TODS); /* BSSID SA DA */ memcpy(hdr.addr1, bssid, ETH_ALEN); @@ -778,7 +782,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, /* if it's part of a bridge, reject changing type to station/ibss */ if ((dev->priv_flags & IFF_BRIDGE_PORT) && - (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) + (ntype == NL80211_IFTYPE_ADHOC || + ntype == NL80211_IFTYPE_STATION || + ntype == NL80211_IFTYPE_P2P_CLIENT)) return -EBUSY; if (ntype != otype) { @@ -789,6 +795,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, cfg80211_leave_ibss(rdev, dev, false); break; case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, true); break; @@ -817,9 +824,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, if (dev->ieee80211_ptr->use_4addr) break; /* fall through */ + case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_ADHOC: dev->priv_flags |= IFF_DONT_BRIDGE; break; + case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: -- cgit v1.2.3 From a02cec2155fbea457eca8881870fd2de1a4c4c76 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 22 Sep 2010 20:43:57 +0000 Subject: net: return operator cleanup Change "return (EXPR);" to "return EXPR;" return is not a function, parentheses are not required. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/wireless/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/core.h b/net/wireless/core.h index 37580e090a3..5d89310b358 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -86,7 +86,7 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) static inline bool wiphy_idx_valid(int wiphy_idx) { - return (wiphy_idx >= 0); + return wiphy_idx >= 0; } -- cgit v1.2.3 From 92e44948b2b3b2db8f39f17033f98ae2356156a5 Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Fri, 24 Sep 2010 07:23:55 +0300 Subject: nl80211: Fix exit from nl80211_set_power_save If interface does not existk, when nl80211_set_power_save is called, (eg. module has been unloaded) it has been causing kernel panic. Added new goto target to avoid crash if get_rdev_dev_by_info_ifindex does not return dev and rdev pointers. Signed-off-by: Teemu Paasikivi Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f15b1af2c76..4ff827e8c36 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4990,7 +4990,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) - goto unlock_rdev; + goto unlock_rtnl; wdev = dev->ieee80211_ptr; @@ -5014,6 +5014,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) unlock_rdev: cfg80211_unlock_rdev(rdev); dev_put(dev); +unlock_rtnl: rtnl_unlock(); out: -- cgit v1.2.3 From 93b05238027420978d785569f8c1aa4a6867bc13 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 28 Sep 2010 12:53:14 +0200 Subject: cfg80211: always set IBSS basic rates IBSS started from wireless extensions is currently missing basic rate configuration, fix this by moving the code to generate the default to the common code that gets invoked for both nl80211 and wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/ibss.c | 19 +++++++++++++++++++ net/wireless/nl80211.c | 17 ----------------- 2 files changed, 19 insertions(+), 17 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27a8ce9343c..8cb6e08373b 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -88,6 +88,25 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, if (wdev->ssid_len) return -EALREADY; + if (!params->basic_rates) { + /* + * If no rates were explicitly configured, + * use the mandatory rate set for 11b or + * 11a for maximum compatibility. + */ + struct ieee80211_supported_band *sband = + rdev->wiphy.bands[params->channel->band]; + int j; + u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? + IEEE80211_RATE_MANDATORY_A : + IEEE80211_RATE_MANDATORY_B; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].flags & flag) + params->basic_rates |= BIT(j); + } + } + if (WARN_ON(wdev->connect_keys)) kfree(wdev->connect_keys); wdev->connect_keys = connkeys; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ff827e8c36..9c84825803c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4119,23 +4119,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) goto out; } } - } else { - /* - * If no rates were explicitly configured, - * use the mandatory rate set for 11b or - * 11a for maximum compatibility. - */ - struct ieee80211_supported_band *sband = - wiphy->bands[ibss.channel->band]; - int j; - u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? - IEEE80211_RATE_MANDATORY_A : - IEEE80211_RATE_MANDATORY_B; - - for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].flags & flag) - ibss.basic_rates |= BIT(j); - } } err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); -- cgit v1.2.3 From 5a254ffe3ffdfa84fe076009bd8e88da412180d2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 27 Sep 2010 09:07:26 -0700 Subject: wireless: Use first phyX name available when registering phy devices. Choose first available phyX name when creating phy devices. This means that reloading a wifi driver will not cause a change in the name of it's phy device. Also, allow users to rename a phy to any un-used name, including phy%d. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/wireless/core.c | 54 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c21ebf9780..1684ad91763 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -178,26 +178,10 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { struct cfg80211_registered_device *rdev2; - int wiphy_idx, taken = -1, result, digits; + int result; assert_cfg80211_lock(); - /* prohibit calling the thing phy%d when %d is not its number */ - sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); - if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { - /* count number of places needed to print wiphy_idx */ - digits = 1; - while (wiphy_idx /= 10) - digits++; - /* - * deny the name if it is phy where is printed - * without leading zeroes. taken == strlen(newname) here - */ - if (taken == strlen(PHY_NAME) + digits) - return -EINVAL; - } - - /* Ignore nop renames */ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) return 0; @@ -205,7 +189,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, /* Ensure another device does not already have this name. */ list_for_each_entry(rdev2, &cfg80211_rdev_list, list) if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) - return -EINVAL; + return -EEXIST; result = device_rename(&rdev->wiphy.dev, newname); if (result) @@ -320,9 +304,11 @@ static void cfg80211_event_work(struct work_struct *work) struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; - - struct cfg80211_registered_device *rdev; + int i; + struct cfg80211_registered_device *rdev, *rdev2; int alloc_size; + char nname[IFNAMSIZ + 1]; + bool found = false; WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); @@ -346,16 +332,36 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { wiphy_counter--; + goto too_many_devs; + } + + /* 64k wiphy devices is enough for anyone! */ + for (i = 0; i < 0xFFFF; i++) { + found = false; + snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); + nname[sizeof(nname)-1] = 0; + list_for_each_entry(rdev2, &cfg80211_rdev_list, list) + if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { + found = true; + break; + } + + if (!found) + break; + } + + if (unlikely(found)) { +too_many_devs: mutex_unlock(&cfg80211_mutex); - /* ugh, wrapped! */ + /* ugh, too many devices already! */ kfree(rdev); return NULL; } - mutex_unlock(&cfg80211_mutex); - /* give it a proper name */ - dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + dev_set_name(&rdev->wiphy.dev, "%s", nname); + + mutex_unlock(&cfg80211_mutex); mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); -- cgit v1.2.3 From 17e5a8082894a4b66cb69e7ec16074f0f01281e1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Sep 2010 17:15:30 +0200 Subject: nl80211: allow drivers to indicate whether the survey data channel is in use Some user space applications only want to display survey data for the operating channel, however there is no API to get that yet. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9c84825803c..0087c4323c5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3489,6 +3489,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, if (survey->filled & SURVEY_INFO_NOISE_DBM) NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, survey->noise); + if (survey->filled & SURVEY_INFO_IN_USE) + NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); nla_nest_end(msg, infoattr); -- cgit v1.2.3 From 663fcafd977f13e6483f7d4cf2ccdbc4fae81ed0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 21:06:09 +0200 Subject: cfg80211/mac80211: allow management frame TX in AP mode Enable management frame transmission and subscribing to management frames through nl80211 in both cfg80211 and mac80211. Also update a few places that I forgot to update for P2P-client mode previously, and fix a small bug with non-action frames in this API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/mlme.c | 54 ++++++++++++++++++++++++++++++++++++++++---------- net/wireless/nl80211.c | 10 ++++++++-- 2 files changed, 51 insertions(+), 13 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 46f37116089..caf11a42750 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -876,21 +876,53 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (ieee80211_is_action(mgmt->frame_control) && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { - /* Verify that we are associated with the destination AP */ + int err = 0; + wdev_lock(wdev); - if (!wdev->current_bss || - memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, - ETH_ALEN) != 0 || - ((wdev->iftype == NL80211_IFTYPE_STATION || - wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && - memcmp(wdev->current_bss->pub.bssid, mgmt->da, - ETH_ALEN) != 0)) { - wdev_unlock(wdev); - return -ENOTCONN; - } + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (!wdev->current_bss) { + err = -ENOTCONN; + break; + } + + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->bssid, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + + /* + * check for IBSS DA must be done by driver as + * cfg80211 doesn't track the stations + */ + if (wdev->iftype == NL80211_IFTYPE_ADHOC) + break; + /* for station, check that DA is the AP */ + if (memcmp(wdev->current_bss->pub.bssid, + mgmt->da, ETH_ALEN)) { + err = -ENOTCONN; + break; + } + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_AP_VLAN: + if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) + err = -EINVAL; + break; + default: + err = -EOPNOTSUPP; + break; + } wdev_unlock(wdev); + + if (err) + return err; } if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0087c4323c5..cbbbe9ab452 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4828,7 +4828,10 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } @@ -4881,7 +4884,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { err = -EOPNOTSUPP; goto out; } -- cgit v1.2.3 From 2234362c427e2ef667595b9b81c0125003ac5607 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 22:17:43 +0200 Subject: cfg80211: fix locking Add missing unlocking of the wiphy in set_channel, and don't try to unlock a non-existing wiphy in set_cqm. Cc: stable@kernel.org [2.6.35+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cbbbe9ab452..21061ccee55 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -821,11 +821,13 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); if (result) - goto unlock; + goto unlock_rtnl; result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); - unlock: + dev_put(netdev); + cfg80211_unlock_rdev(rdev); + unlock_rtnl: rtnl_unlock(); return result; @@ -5097,7 +5099,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) - goto unlock_rdev; + goto unlock_rtnl; wdev = dev->ieee80211_ptr; @@ -5115,9 +5117,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, threshold, hysteresis); -unlock_rdev: + unlock_rdev: cfg80211_unlock_rdev(rdev); dev_put(dev); + unlock_rtnl: rtnl_unlock(); return err; -- cgit v1.2.3 From e8347ebad2f1b15bddb6ed3ed5f767531eb52dc3 Mon Sep 17 00:00:00 2001 From: Bill Jordan Date: Fri, 1 Oct 2010 13:54:28 -0400 Subject: cfg80211: patches to allow setting the WDS peer Added a nl interface to set the peer bssid of a WDS interface. Signed-off-by: Bill Jordan Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 21061ccee55..fd92b6b7ff0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -603,6 +603,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); } CMD(set_channel, SET_CHANNEL); + CMD(set_wds_peer, SET_WDS_PEER); #undef CMD @@ -833,6 +834,53 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) return result; } +static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; + struct net_device *dev; + u8 *bssid; + int err; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + rtnl_lock(); + + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) + goto unlock_rtnl; + + wdev = dev->ieee80211_ptr; + + if (netif_running(dev)) { + err = -EBUSY; + goto out; + } + + if (!rdev->ops->set_wds_peer) { + err = -EOPNOTSUPP; + goto out; + } + + if (wdev->iftype != NL80211_IFTYPE_WDS) { + err = -EOPNOTSUPP; + goto out; + } + + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); + err = rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); + +out: + cfg80211_unlock_rdev(rdev); + dev_put(dev); +unlock_rtnl: + rtnl_unlock(); + + return err; +} + + static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; @@ -5473,6 +5521,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_WDS_PEER, + .doit = nl80211_set_wds_peer, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { -- cgit v1.2.3 From 4c476991062a0a59523c2bf193f09087f469686a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:36:35 +0200 Subject: nl80211: use the new genetlink pre/post_doit hooks This makes nl80211 use the new genetlink pre_doit/post_doit hooks for locking and checking the interface/wiphy index. This significantly reduces the code size and the likelihood of locking errors. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 1737 +++++++++++++++--------------------------------- 1 file changed, 533 insertions(+), 1204 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fd92b6b7ff0..a96da47d064 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -23,6 +23,11 @@ #include "nl80211.h" #include "reg.h" +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + /* the netlink family */ static struct genl_family nl80211_fam = { .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ @@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { .version = 1, /* no particular meaning now */ .maxattr = NL80211_ATTR_MAX, .netnsok = true, + .pre_doit = nl80211_pre_doit, + .post_doit = nl80211_post_doit, }; /* internal helper: get rdev and dev */ @@ -704,28 +711,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev; - - dev = cfg80211_get_dev_from_info(info); - if (IS_ERR(dev)) - return PTR_ERR(dev); + struct cfg80211_registered_device *dev = info->user_ptr[0]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out_err; - - if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) - goto out_free; + return -ENOMEM; - cfg80211_unlock_rdev(dev); + if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } return genlmsg_reply(msg, info); - - out_free: - nlmsg_free(msg); - out_err: - cfg80211_unlock_rdev(dev); - return -ENOBUFS; } static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { @@ -814,24 +811,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *netdev; - int result; - - rtnl_lock(); - - result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); - if (result) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; - result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); - - dev_put(netdev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); - - return result; + return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); } static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) @@ -893,8 +876,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) u32 frag_threshold = 0, rts_threshold = 0; u8 coverage_class = 0; - rtnl_lock(); - /* * Try to find the wiphy and netdev. Normally this * function shouldn't need the netdev, but this is @@ -921,8 +902,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev = __cfg80211_rdev_from_info(info); if (IS_ERR(rdev)) { mutex_unlock(&cfg80211_mutex); - result = PTR_ERR(rdev); - goto unlock; + return PTR_ERR(rdev); } wdev = NULL; netdev = NULL; @@ -1104,8 +1084,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) mutex_unlock(&rdev->mtx); if (netdev) dev_put(netdev); - unlock: - rtnl_unlock(); return result; } @@ -1185,33 +1163,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; - struct cfg80211_registered_device *dev; - struct net_device *netdev; - int err; - - err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev); - if (err) - return err; + struct cfg80211_registered_device *dev = info->user_ptr[0]; + struct net_device *netdev = info->user_ptr[1]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out_err; + return -ENOMEM; if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, - dev, netdev) < 0) - goto out_free; - - dev_put(netdev); - cfg80211_unlock_rdev(dev); + dev, netdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } return genlmsg_reply(msg, info); - - out_free: - nlmsg_free(msg); - out_err: - dev_put(netdev); - cfg80211_unlock_rdev(dev); - return -ENOBUFS; } static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { @@ -1271,39 +1236,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; int err; enum nl80211_iftype otype, ntype; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u32 _flags, *flags = NULL; bool change = false; memset(¶ms, 0, sizeof(params)); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - otype = ntype = dev->ieee80211_ptr->iftype; if (info->attrs[NL80211_ATTR_IFTYPE]) { ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); if (otype != ntype) change = true; - if (ntype > NL80211_IFTYPE_MAX) { - err = -EINVAL; - goto unlock; - } + if (ntype > NL80211_IFTYPE_MAX) + return -EINVAL; } if (info->attrs[NL80211_ATTR_MESH_ID]) { - if (ntype != NL80211_IFTYPE_MESH_POINT) { - err = -EINVAL; - goto unlock; - } + if (ntype != NL80211_IFTYPE_MESH_POINT) + return -EINVAL; params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); change = true; @@ -1314,20 +1269,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) change = true; err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); if (err) - goto unlock; + return err; } else { params.use_4addr = -1; } if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { - if (ntype != NL80211_IFTYPE_MONITOR) { - err = -EINVAL; - goto unlock; - } + if (ntype != NL80211_IFTYPE_MONITOR) + return -EINVAL; err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], &_flags); if (err) - goto unlock; + return err; flags = &_flags; change = true; @@ -1341,17 +1294,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) if (!err && params.use_4addr != -1) dev->ieee80211_ptr->use_4addr = params.use_4addr; - unlock: - dev_put(dev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; @@ -1368,19 +1316,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto unlock_rtnl; - } - if (!rdev->ops->add_virtual_intf || - !(rdev->wiphy.interface_modes & (1 << type))) { - err = -EOPNOTSUPP; - goto unlock; - } + !(rdev->wiphy.interface_modes & (1 << type))) + return -EOPNOTSUPP; if (type == NL80211_IFTYPE_MESH_POINT && info->attrs[NL80211_ATTR_MESH_ID]) { @@ -1392,7 +1330,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); if (err) - goto unlock; + return err; } err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? @@ -1402,38 +1340,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); - unlock: - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->del_virtual_intf) { - err = -EOPNOTSUPP; - goto out; - } + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); + if (!rdev->ops->del_virtual_intf) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; + return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); } struct get_key_cookie { @@ -1486,9 +1404,9 @@ static void get_key_callback(void *c, struct key_params *params) static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 key_idx = 0; u8 *mac_addr = NULL; struct get_key_cookie cookie = { @@ -1506,30 +1424,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->get_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_key) + return -EOPNOTSUPP; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_NEW_KEY); - - if (IS_ERR(hdr)) { - err = PTR_ERR(hdr); - goto free_msg; - } + if (IS_ERR(hdr)) + return PTR_ERR(hdr); cookie.msg = msg; cookie.idx = key_idx; @@ -1549,28 +1454,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) goto nla_put_failure; genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); nla_put_failure: err = -ENOBUFS; free_msg: nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct key_parse key; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; int (*func)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index); @@ -1585,21 +1483,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (!key.def && !key.defmgmt) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (key.def) func = rdev->ops->set_default_key; else func = rdev->ops->set_default_mgmt_key; - if (!func) { - err = -EOPNOTSUPP; - goto out; - } + if (!func) + return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1616,21 +1506,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) #endif wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct key_parse key; u8 *mac_addr = NULL; @@ -1644,21 +1527,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->add_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->add_key) + return -EOPNOTSUPP; - if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { - err = -EINVAL; - goto out; - } + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) + return -EINVAL; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1667,20 +1540,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) mac_addr, &key.p); wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 *mac_addr = NULL; struct key_parse key; @@ -1691,16 +1558,8 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->del_key) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->del_key) + return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); @@ -1717,13 +1576,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) #endif wdev_unlock(dev->ieee80211_ptr); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - - unlock_rtnl: - rtnl_unlock(); - return err; } @@ -1731,36 +1583,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) { int (*call)(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *info); - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct beacon_parameters params; int haveinfo = 0; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; 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]) { - err = -EINVAL; - goto out; - } + !info->attrs[NL80211_ATTR_BEACON_HEAD]) + return -EINVAL; call = rdev->ops->add_beacon; break; @@ -1769,14 +1610,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) break; default: WARN_ON(1); - err = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } - if (!call) { - err = -EOPNOTSUPP; - goto out; - } + if (!call) + return -EOPNOTSUPP; memset(¶ms, 0, sizeof(params)); @@ -1806,53 +1644,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) haveinfo = 1; } - if (!haveinfo) { - err = -EINVAL; - goto out; - } - - err = call(&rdev->wiphy, dev, ¶ms); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + if (!haveinfo) + return -EINVAL; - return err; + return call(&rdev->wiphy, dev, ¶ms); } static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - if (!rdev->ops->del_beacon) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->del_beacon) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } - err = rdev->ops->del_beacon(&rdev->wiphy, dev); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_beacon(&rdev->wiphy, dev); } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { @@ -2049,12 +1859,12 @@ static int nl80211_dump_station(struct sk_buff *skb, static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct station_info sinfo; struct sk_buff *msg; u8 *mac_addr = NULL; + int err; memset(&sinfo, 0, sizeof(sinfo)); @@ -2063,41 +1873,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); + if (!rdev->ops->get_station) + return -EOPNOTSUPP; - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); if (err) - goto out_rtnl; - - if (!rdev->ops->get_station) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo); - if (err) - goto out; + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out; + return -ENOMEM; if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, - dev, mac_addr, &sinfo) < 0) - goto out_free; - - err = genlmsg_reply(msg, info); - goto out; - - out_free: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev, mac_addr, &sinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } - return err; + return genlmsg_reply(msg, info); } /* @@ -2127,9 +1920,9 @@ static int get_vlan(struct genl_info *info, static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct station_parameters params; u8 *mac_addr = NULL; @@ -2167,12 +1960,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; @@ -2234,19 +2021,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); return err; } static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct station_parameters params; u8 *mac_addr = NULL; @@ -2283,18 +2066,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (parse_station_flags(info, ¶ms)) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - 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_P2P_GO) { - err = -EINVAL; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; err = get_vlan(info, rdev, ¶ms.vlan); if (err) @@ -2318,52 +2093,28 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) out: if (params.vlan) dev_put(params.vlan); - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - return err; } static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *mac_addr = NULL; if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - 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_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EINVAL; - goto out; - } - - if (!rdev->ops->del_station) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EINVAL; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev->ops->del_station) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr); } static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, @@ -2490,9 +2241,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb, static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct mpath_info pinfo; struct sk_buff *msg; u8 *dst = NULL; @@ -2505,53 +2256,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->get_mpath) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_mpath) + return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); if (err) - goto out; + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) - goto out; + return -ENOMEM; if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, - dev, dst, next_hop, &pinfo) < 0) - goto out_free; - - err = genlmsg_reply(msg, info); - goto out; - - out_free: - nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev, dst, next_hop, &pinfo) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } - return err; + return genlmsg_reply(msg, info); } static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; u8 *next_hop = NULL; @@ -2564,42 +2295,22 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->change_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!rdev->ops->change_mpath) + return -EOPNOTSUPP; - err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!netif_running(dev)) + return -ENETDOWN; - return err; + return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); } + static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; u8 *next_hop = NULL; @@ -2612,75 +2323,37 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->add_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!rdev->ops->add_mpath) + return -EOPNOTSUPP; - err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!netif_running(dev)) + return -ENETDOWN; - return err; + return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); } static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u8 *dst = NULL; if (info->attrs[NL80211_ATTR_MAC]) dst = nla_data(info->attrs[NL80211_ATTR_MAC]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->del_mpath) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev->ops->del_mpath) + return -EOPNOTSUPP; - return err; + return rdev->ops->del_mpath(&rdev->wiphy, dev, dst); } static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct bss_parameters params; memset(¶ms, 0, sizeof(params)); @@ -2708,32 +2381,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_AP_ISOLATE]) params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->change_bss) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->change_bss) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - return err; + return rdev->ops->change_bss(&rdev->wiphy, dev, ¶ms); } static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { @@ -2812,37 +2467,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_get_mesh_params(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct mesh_config cur_params; int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; void *hdr; struct nlattr *pinfoattr; struct sk_buff *msg; - rtnl_lock(); - - /* Look up our device */ - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->get_mesh_params) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->get_mesh_params) + return -EOPNOTSUPP; /* Get the mesh params */ err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); if (err) - goto out; + return err; /* Draw up a netlink message to send back */ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOBUFS; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_GET_MESH_PARAMS); if (!hdr) @@ -2881,22 +2525,13 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, cur_params.dot11MeshHWMPRootMode); nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); nla_put_failure: genlmsg_cancel(msg, hdr); nlmsg_free(msg); - err = -EMSGSIZE; - out: - /* Cleanup */ - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - - return err; -} + return -ENOBUFS; +} #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ do {\ @@ -2925,10 +2560,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) { - int err; u32 mask; - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct mesh_config cfg; struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; struct nlattr *parent_attr; @@ -2940,16 +2574,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) parent_attr, nl80211_meshconf_params_policy)) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - - if (!rdev->ops->set_mesh_params) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->set_mesh_params) + return -EOPNOTSUPP; /* This makes sure that there aren't more than 32 mesh config * parameters (otherwise our bitfield scheme would not work.) */ @@ -2995,16 +2621,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) nla_get_u8); /* Apply changes */ - err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); - - out: - /* cleanup */ - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); - - return err; + return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); } #undef FILL_IN_MESH_PARAM_IF_SET @@ -3187,8 +2804,8 @@ static int validate_scan_freqs(struct nlattr *freqs) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_scan_request *request; struct cfg80211_ssid *ssid; struct ieee80211_channel *channel; @@ -3201,36 +2818,22 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - wiphy = &rdev->wiphy; - if (!rdev->ops->scan) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->scan) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; - if (rdev->scan_req) { - err = -EBUSY; - goto out; - } + if (rdev->scan_req) + return -EBUSY; if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { n_channels = validate_scan_freqs( info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); - if (!n_channels) { - err = -EINVAL; - goto out; - } + if (!n_channels) + return -EINVAL; } else { n_channels = 0; @@ -3243,29 +2846,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) n_ssids++; - if (n_ssids > wiphy->max_scan_ssids) { - err = -EINVAL; - goto out; - } + if (n_ssids > wiphy->max_scan_ssids) + return -EINVAL; if (info->attrs[NL80211_ATTR_IE]) ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); else ie_len = 0; - if (ie_len > wiphy->max_scan_ie_len) { - err = -EINVAL; - goto out; - } + if (ie_len > wiphy->max_scan_ie_len) + return -EINVAL; request = kzalloc(sizeof(*request) + sizeof(*ssid) * n_ssids + sizeof(channel) * n_channels + ie_len, GFP_KERNEL); - if (!request) { - err = -ENOMEM; - goto out; - } + if (!request) + return -ENOMEM; if (n_ssids) request->ssids = (void *)&request->channels[n_channels]; @@ -3353,18 +2950,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!err) { nl80211_send_scan_start(rdev, dev); dev_hold(dev); - } - + } else { out_free: - if (err) { rdev->scan_req = NULL; kfree(request); } - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); return err; } @@ -3643,8 +3233,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; const u8 *bssid, *ssid, *ie = NULL; int err, ssid_len, ie_len = 0; @@ -3686,12 +3276,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) key.p.key = NULL; } - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (key.idx >= 0) { int i; bool ok = false; @@ -3701,35 +3285,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) break; } } - if (!ok) { - err = -EINVAL; - goto out; - } + if (!ok) + return -EINVAL; } - if (!rdev->ops->auth) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->auth) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { - err = -EINVAL; - goto out; - } + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); @@ -3740,24 +3314,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) } auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); - if (!nl80211_valid_auth_type(auth_type)) { - err = -EINVAL; - goto out; - } + if (!nl80211_valid_auth_type(auth_type)) + return -EINVAL; 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, - local_state_change); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, + ssid, ssid_len, ie, ie_len, + key.p.key, key.p.key_len, key.idx, + local_state_change); } static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, @@ -3841,8 +3406,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_crypto_settings crypto; struct ieee80211_channel *chan; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; @@ -3857,36 +3422,22 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->assoc) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->assoc) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); - if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { - err = -EINVAL; - goto out; - } + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) + return -EINVAL; ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); @@ -3901,10 +3452,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); if (mfp == NL80211_MFP_REQUIRED) use_mfp = true; - else if (mfp != NL80211_MFP_NO) { - err = -EINVAL; - goto out; - } + else if (mfp != NL80211_MFP_NO) + return -EINVAL; } if (info->attrs[NL80211_ATTR_PREV_BSSID]) @@ -3916,20 +3465,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) ssid, ssid_len, ie, ie_len, use_mfp, &crypto); -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; const u8 *ie = NULL, *bssid; - int err, ie_len = 0; + int ie_len = 0; u16 reason_code; bool local_state_change; @@ -3942,35 +3486,22 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_REASON_CODE]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->deauth) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->deauth) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); if (reason_code == 0) { /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; + return -EINVAL; } if (info->attrs[NL80211_ATTR_IE]) { @@ -3980,23 +3511,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) 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); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); } static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; const u8 *ie = NULL, *bssid; - int err, ie_len = 0; + int ie_len = 0; u16 reason_code; bool local_state_change; @@ -4009,35 +3533,22 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_REASON_CODE]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->disassoc) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->disassoc) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); if (reason_code == 0) { /* Reason Code 0 is reserved */ - err = -EINVAL; - goto out; + return -EINVAL; } if (info->attrs[NL80211_ATTR_IE]) { @@ -4047,21 +3558,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) 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); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, + local_state_change); } static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_ibss_params ibss; struct wiphy *wiphy; struct cfg80211_cached_keys *connkeys = NULL; @@ -4086,26 +3590,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->join_ibss) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->join_ibss) + return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { - err = -EOPNOTSUPP; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; wiphy = &rdev->wiphy; @@ -4123,24 +3615,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); if (!ibss.channel || ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || - ibss.channel->flags & IEEE80211_CHAN_DISABLED) { - err = -EINVAL; - goto out; - } + ibss.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; - if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { - connkeys = nl80211_parse_connkeys(rdev, - info->attrs[NL80211_ATTR_KEYS]); - if (IS_ERR(connkeys)) { - err = PTR_ERR(connkeys); - connkeys = NULL; - goto out; - } - } - if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); @@ -4150,10 +3630,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) wiphy->bands[ibss.channel->band]; int i, j; - if (n_rates == 0) { - err = -EINVAL; - goto out; - } + if (n_rates == 0) + return -EINVAL; for (i = 0; i < n_rates; i++) { int rate = (rates[i] & 0x7f) * 5; @@ -4166,60 +3644,39 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) break; } } - if (!found) { - err = -EINVAL; - goto out; - } + if (!found) + return -EINVAL; } } - err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); + if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { + connkeys = nl80211_parse_connkeys(rdev, + info->attrs[NL80211_ATTR_KEYS]); + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); + } -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); if (err) kfree(connkeys); - rtnl_unlock(); return err; } static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; - int err; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; - if (!rdev->ops->leave_ibss) { - err = -EOPNOTSUPP; - goto out; - } - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->leave_ibss) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) + return -EOPNOTSUPP; - err = cfg80211_leave_ibss(rdev, dev, false); + if (!netif_running(dev)) + return -ENETDOWN; -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_leave_ibss(rdev, dev, false); } #ifdef CONFIG_NL80211_TESTMODE @@ -4229,20 +3686,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int err; if (!info->attrs[NL80211_ATTR_TESTDATA]) return -EINVAL; - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto unlock_rtnl; - } - err = -EOPNOTSUPP; if (rdev->ops->testmode_cmd) { rdev->testmode_info = info; @@ -4252,10 +3701,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) rdev->testmode_info = NULL; } - cfg80211_unlock_rdev(rdev); - - unlock_rtnl: - rtnl_unlock(); return err; } @@ -4346,8 +3791,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_connect_params connect; struct wiphy *wiphy; struct cfg80211_cached_keys *connkeys = NULL; @@ -4376,22 +3821,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) NL80211_MAX_NR_CIPHER_SUITES); if (err) return err; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; wiphy = &rdev->wiphy; @@ -4410,39 +3846,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) ieee80211_get_channel(wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); if (!connect.channel || - connect.channel->flags & IEEE80211_CHAN_DISABLED) { - err = -EINVAL; - goto out; - } + connect.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; } if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { connkeys = nl80211_parse_connkeys(rdev, info->attrs[NL80211_ATTR_KEYS]); - if (IS_ERR(connkeys)) { - err = PTR_ERR(connkeys); - connkeys = NULL; - goto out; - } + if (IS_ERR(connkeys)) + return PTR_ERR(connkeys); } err = cfg80211_connect(rdev, dev, &connect, connkeys); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: if (err) kfree(connkeys); - rtnl_unlock(); return err; } static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; - int err; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u16 reason; if (!info->attrs[NL80211_ATTR_REASON_CODE]) @@ -4453,36 +3877,19 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) if (reason == 0) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - err = cfg80211_disconnect(rdev, dev, reason, true); + if (!netif_running(dev)) + return -ENETDOWN; -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - return err; + return cfg80211_disconnect(rdev, dev, reason, true); } static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net *net; int err; u32 pid; @@ -4492,43 +3899,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); - rtnl_lock(); - - rdev = cfg80211_get_dev_from_info(info); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto out_rtnl; - } - net = get_net_ns_by_pid(pid); - if (IS_ERR(net)) { - err = PTR_ERR(net); - goto out; - } + if (IS_ERR(net)) + return PTR_ERR(net); err = 0; /* check if anything to do */ - if (net_eq(wiphy_net(&rdev->wiphy), net)) - goto out_put_net; + if (!net_eq(wiphy_net(&rdev->wiphy), net)) + err = cfg80211_switch_netns(rdev, net); - err = cfg80211_switch_netns(rdev, net); - out_put_net: put_net(net); - out: - cfg80211_unlock_rdev(rdev); - out_rtnl: - rtnl_unlock(); return err; } static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa) = NULL; - int err; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct cfg80211_pmksa pmksa; memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); @@ -4539,20 +3929,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_PMKID]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; - pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; switch (info->genlhdr->cmd) { case NL80211_CMD_SET_PMKSA: @@ -4566,62 +3948,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) break; } - if (!rdev_ops) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev_ops(&rdev->wiphy, dev, &pmksa); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + if (!rdev_ops) + return -EOPNOTSUPP; - return err; + return rdev_ops(&rdev->wiphy, dev, &pmksa); } static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - int err; - struct net_device *dev; - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto out_rtnl; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto out; - } - - if (!rdev->ops->flush_pmksa) { - err = -EOPNOTSUPP; - goto out; - } - - err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - out_rtnl: - rtnl_unlock(); + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - return err; + if (!rdev->ops->flush_pmksa) + return -EOPNOTSUPP; + return rdev->ops->flush_pmksa(&rdev->wiphy, dev); } static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; struct sk_buff *msg; void *hdr; @@ -4643,21 +3995,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, if (!duration || !msecs_to_jiffies(duration) || duration > 5000) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->remain_on_channel) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->remain_on_channel) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( @@ -4665,24 +4007,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, if (channel_type != NL80211_CHAN_NO_HT && channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) { - err = -EINVAL; - goto out; - } + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) { - err = -EINVAL; - goto out; - } + if (chan == NULL) + return -EINVAL; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_REMAIN_ON_CHANNEL); @@ -4701,58 +4037,35 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + + return genlmsg_reply(msg, info); nla_put_failure: err = -ENOBUFS; free_msg: nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u64 cookie; - int err; if (!info->attrs[NL80211_ATTR_COOKIE]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->cancel_remain_on_channel) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->cancel_remain_on_channel) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); - - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); } static u32 rateset_to_mask(struct ieee80211_supported_band *sband, @@ -4788,26 +4101,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, struct genl_info *info) { struct nlattr *tb[NL80211_TXRATE_MAX + 1]; - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_bitrate_mask mask; - int err, rem, i; - struct net_device *dev; + int rem, i; + struct net_device *dev = info->user_ptr[1]; struct nlattr *tx_rates; struct ieee80211_supported_band *sband; if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->set_bitrate_mask) { - err = -EOPNOTSUPP; - goto unlock; - } + if (!rdev->ops->set_bitrate_mask) + return -EOPNOTSUPP; memset(&mask, 0, sizeof(mask)); /* Default to all rates enabled */ @@ -4824,15 +4129,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { enum ieee80211_band band = nla_type(tx_rates); - if (band < 0 || band >= IEEE80211_NUM_BANDS) { - err = -EINVAL; - goto unlock; - } + if (band < 0 || band >= IEEE80211_NUM_BANDS) + return -EINVAL; sband = rdev->wiphy.bands[band]; - if (sband == NULL) { - err = -EINVAL; - goto unlock; - } + if (sband == NULL) + return -EINVAL; nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), nla_len(tx_rates), nl80211_txattr_policy); if (tb[NL80211_TXRATE_LEGACY]) { @@ -4840,29 +4141,19 @@ 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) { - err = -EINVAL; - goto unlock; - } + if (mask.control[band].legacy == 0) + return -EINVAL; } } - err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); - - unlock: - dev_put(dev); - cfg80211_unlock_rdev(rdev); - unlock_rtnl: - rtnl_unlock(); - return err; + return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); } static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; - int err; if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) return -EINVAL; @@ -4870,44 +4161,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_FRAME_TYPE]) frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; /* not much point in registering if we can't reply */ - if (!rdev->ops->mgmt_tx) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; - err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, + return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, frame_type, nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); - return err; } static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; struct ieee80211_channel *chan; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; bool channel_type_valid = false; @@ -4921,31 +4196,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_WIPHY_FREQ]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - if (!rdev->ops->mgmt_tx) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->mgmt_tx) + return -EOPNOTSUPP; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { - err = -EOPNOTSUPP; - goto out; - } + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } + if (!netif_running(dev)) + return -ENETDOWN; if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( @@ -4953,25 +4216,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (channel_type != NL80211_CHAN_NO_HT && channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) { - err = -EINVAL; - goto out; - } + channel_type != NL80211_CHAN_HT40MINUS) + return -EINVAL; channel_type_valid = true; } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); chan = rdev_freq_to_chan(rdev, freq, channel_type); - if (chan == NULL) { - err = -EINVAL; - goto out; - } + if (chan == NULL) + return -EINVAL; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_FRAME); @@ -4991,110 +4248,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); nla_put_failure: err = -ENOBUFS; free_msg: nlmsg_free(msg); - out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); return err; } static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; u8 ps_state; bool state; int err; - if (!info->attrs[NL80211_ATTR_PS_STATE]) { - err = -EINVAL; - goto out; - } + if (!info->attrs[NL80211_ATTR_PS_STATE]) + return -EINVAL; ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); - if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { - err = -EINVAL; - goto out; - } - - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; + if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) + return -EINVAL; wdev = dev->ieee80211_ptr; - if (!rdev->ops->set_power_mgmt) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; state = (ps_state == NL80211_PS_ENABLED) ? true : false; if (state == wdev->ps) - goto unlock_rdev; - - wdev->ps = state; - - if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps, - wdev->ps_timeout)) - /* assume this means it's off */ - wdev->ps = false; - -unlock_rdev: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); + return 0; -out: + err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state, + wdev->ps_timeout); + if (!err) + wdev->ps = state; return err; } static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; enum nl80211_ps_state ps_state; struct wireless_dev *wdev; - struct net_device *dev; + struct net_device *dev = info->user_ptr[1]; struct sk_buff *msg; void *hdr; int err; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - wdev = dev->ieee80211_ptr; - if (!rdev->ops->set_power_mgmt) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->set_power_mgmt) + return -EOPNOTSUPP; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM; hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, NL80211_CMD_GET_POWER_SAVE); if (!hdr) { - err = -ENOMEM; + err = -ENOBUFS; goto free_msg; } @@ -5106,22 +4325,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); genlmsg_end(msg, hdr); - err = genlmsg_reply(msg, info); - goto out; + return genlmsg_reply(msg, info); -nla_put_failure: + nla_put_failure: err = -ENOBUFS; - -free_msg: + free_msg: nlmsg_free(msg); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - -unlock_rtnl: - rtnl_unlock(); - return err; } @@ -5135,43 +4344,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { static int nl80211_set_cqm_rssi(struct genl_info *info, s32 threshold, u32 hysteresis) { - struct cfg80211_registered_device *rdev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev; - struct net_device *dev; - int err; + struct net_device *dev = info->user_ptr[1]; if (threshold > 0) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - wdev = dev->ieee80211_ptr; - if (!rdev->ops->set_cqm_rssi_config) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } + if (!rdev->ops->set_cqm_rssi_config) + return -EOPNOTSUPP; if (wdev->iftype != NL80211_IFTYPE_STATION && - wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { - err = -EOPNOTSUPP; - goto unlock_rdev; - } - - err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, - threshold, hysteresis); - - unlock_rdev: - cfg80211_unlock_rdev(rdev); - dev_put(dev); - unlock_rtnl: - rtnl_unlock(); + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; - return err; + return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, + threshold, hysteresis); } static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) @@ -5205,6 +4395,54 @@ out: return err; } +#define NL80211_FLAG_NEED_WIPHY 0x01 +#define NL80211_FLAG_NEED_NETDEV 0x02 +#define NL80211_FLAG_NEED_RTNL 0x04 + +static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + struct net_device *dev; + int err; + bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; + + if (rtnl) + rtnl_lock(); + + if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { + rdev = cfg80211_get_dev_from_info(info); + if (IS_ERR(rdev)) { + if (rtnl) + rtnl_unlock(); + return PTR_ERR(rdev); + } + info->user_ptr[0] = rdev; + } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { + err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); + if (err) { + if (rtnl) + rtnl_unlock(); + return err; + } + info->user_ptr[0] = rdev; + info->user_ptr[1] = dev; + } + + return 0; +} + +static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + if (info->user_ptr[0]) + cfg80211_unlock_rdev(info->user_ptr[0]); + if (info->user_ptr[1]) + dev_put(info->user_ptr[1]); + if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) + rtnl_unlock(); +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -5212,12 +4450,14 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_wiphy, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_WIPHY, }, { .cmd = NL80211_CMD_SET_WIPHY, .doit = nl80211_set_wiphy, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_INTERFACE, @@ -5225,90 +4465,119 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_interface, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV, }, { .cmd = NL80211_CMD_SET_INTERFACE, .doit = nl80211_set_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_INTERFACE, .doit = nl80211_new_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_INTERFACE, .doit = nl80211_del_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_KEY, .doit = nl80211_get_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_KEY, .doit = nl80211_set_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_KEY, .doit = nl80211_new_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_KEY, .doit = nl80211_del_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_addset_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_BEACON, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_del_beacon, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_STATION, .doit = nl80211_get_station, .dumpit = nl80211_dump_station, .policy = nl80211_policy, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_STATION, .doit = nl80211_set_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_STATION, .doit = nl80211_new_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_STATION, .doit = nl80211_del_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_MPATH, @@ -5316,30 +4585,40 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_MPATH, .doit = nl80211_set_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_NEW_MPATH, .doit = nl80211_new_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_MPATH, .doit = nl80211_del_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_BSS, .doit = nl80211_set_bss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_REG, @@ -5364,18 +4643,24 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_get_mesh_params, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_MESH_PARAMS, .doit = nl80211_set_mesh_params, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_TRIGGER_SCAN, .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_SCAN, @@ -5387,36 +4672,48 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_authenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_ASSOCIATE, .doit = nl80211_associate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEAUTHENTICATE, .doit = nl80211_deauthenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DISASSOCIATE, .doit = nl80211_disassociate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_JOIN_IBSS, .doit = nl80211_join_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_LEAVE_IBSS, .doit = nl80211_leave_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, #ifdef CONFIG_NL80211_TESTMODE { @@ -5424,6 +4721,8 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_testmode_do, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, #endif { @@ -5431,18 +4730,24 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_connect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DISCONNECT, .doit = nl80211_disconnect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_WIPHY_NETNS, .doit = nl80211_wiphy_netns, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_SURVEY, @@ -5454,72 +4759,96 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_DEL_PMKSA, .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_FLUSH_PMKSA, .doit = nl80211_flush_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_REMAIN_ON_CHANNEL, .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, .doit = nl80211_set_tx_bitrate_mask, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_REGISTER_FRAME, .doit = nl80211_register_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_FRAME, .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_POWER_SAVE, .doit = nl80211_set_power_save, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_GET_POWER_SAVE, .doit = nl80211_get_power_save, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_CQM, .doit = nl80211_set_cqm, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_CHANNEL, .doit = nl80211_set_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, { .cmd = NL80211_CMD_SET_WDS_PEER, -- cgit v1.2.3 From 41265714810e20d91ddd7aaca30043b0f12190ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:14:05 +0200 Subject: nl80211: use generic check for netif_running Use a new flag that requires the netdev to be UP and use it to check instead of coding the check into all functions that require it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 97 +++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 69 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a96da47d064..ca8d04cb172 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -411,9 +411,6 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) { ASSERT_WDEV_LOCK(wdev); - if (!netif_running(wdev->netdev)) - return -ENETDOWN; - switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: @@ -2083,11 +2080,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) goto out; } - if (!netif_running(dev)) { - err = -ENETDOWN; - goto out; - } - err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); out: @@ -2301,9 +2293,6 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop); } @@ -2329,9 +2318,6 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop); } @@ -2823,9 +2809,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->scan) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (rdev->scan_req) return -EBUSY; @@ -3296,9 +3279,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); @@ -3429,9 +3409,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); chan = ieee80211_get_channel(&rdev->wiphy, @@ -3493,9 +3470,6 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); @@ -3540,9 +3514,6 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); @@ -3596,9 +3567,6 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_MAC]) @@ -3673,9 +3641,6 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return cfg80211_leave_ibss(rdev, dev, false); } @@ -3826,9 +3791,6 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_MAC]) @@ -3881,9 +3843,6 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - return cfg80211_disconnect(rdev, dev, reason, true); } @@ -3998,9 +3957,6 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, if (!rdev->ops->remain_on_channel) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); @@ -4060,9 +4016,6 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, if (!rdev->ops->cancel_remain_on_channel) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); @@ -4207,9 +4160,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!netif_running(dev)) - return -ENETDOWN; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { channel_type = nla_get_u32( info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); @@ -4398,6 +4348,9 @@ out: #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 +#define NL80211_FLAG_CHECK_NETDEV_UP 0x08 +#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ + NL80211_FLAG_CHECK_NETDEV_UP) static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) @@ -4425,6 +4378,12 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, rtnl_unlock(); return err; } + if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } info->user_ptr[0] = rdev; info->user_ptr[1] = dev; } @@ -4504,7 +4463,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4512,7 +4471,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4520,7 +4479,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4568,7 +4527,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4585,7 +4544,7 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4593,7 +4552,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4601,7 +4560,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_new_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4659,7 +4618,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4672,7 +4631,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_authenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4680,7 +4639,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_associate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4688,7 +4647,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_deauthenticate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4696,7 +4655,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_disassociate, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4704,7 +4663,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_join_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4712,7 +4671,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_leave_ibss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, #ifdef CONFIG_NL80211_TESTMODE @@ -4730,7 +4689,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_connect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4738,7 +4697,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_disconnect, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4783,7 +4742,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4791,7 +4750,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -4815,7 +4774,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { -- cgit v1.2.3 From 6774889314ba507483e63c014fcb81adfc127202 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Oct 2010 21:14:06 +0200 Subject: nl80211: reduce dumping boilerplate Consolidate boilerplate code needed for .dumpit calls operating on netdevs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 151 +++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 92 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ca8d04cb172..0c9497170f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -198,6 +198,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) return res; } +static int nl80211_prepare_netdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, + struct net_device **dev) +{ + int ifidx = cb->args[0]; + int err; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + + cb->args[0] = ifidx; + + rtnl_lock(); + + *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!*dev) { + err = -ENODEV; + goto out_rtnl; + } + + *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_rtnl; + } + + return 0; + out_rtnl: + rtnl_unlock(); + return err; +} + +static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) +{ + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + /* IE validation */ static bool is_valid_ie_attr(const struct nlattr *attr) { @@ -1796,28 +1837,12 @@ static int nl80211_dump_station(struct sk_buff *skb, struct cfg80211_registered_device *dev; struct net_device *netdev; u8 mac_addr[ETH_ALEN]; - int ifidx = cb->args[0]; int sta_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_station) { err = -EOPNOTSUPP; @@ -1847,9 +1872,7 @@ static int nl80211_dump_station(struct sk_buff *skb, cb->args[1] = sta_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); + nl80211_finish_netdev_dump(dev); return err; } @@ -2169,28 +2192,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, struct net_device *netdev; u8 dst[ETH_ALEN]; u8 next_hop[ETH_ALEN]; - int ifidx = cb->args[0]; int path_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_mpath) { err = -EOPNOTSUPP; @@ -2224,10 +2231,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, cb->args[1] = path_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return err; } @@ -3034,25 +3038,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct net_device *dev; struct cfg80211_internal_bss *scan; struct wireless_dev *wdev; - int ifidx = cb->args[0]; int start = cb->args[1], idx = 0; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - dev = dev_get_by_index(sock_net(skb->sk), ifidx); - if (!dev) - return -ENODEV; - - rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto out_put_netdev; - } + err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); + if (err) + return err; wdev = dev->ieee80211_ptr; @@ -3068,21 +3059,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->nlh->nlmsg_seq, NLM_F_MULTI, rdev, wdev, scan) < 0) { idx--; - goto out; + break; } } - out: spin_unlock_bh(&rdev->bss_lock); wdev_unlock(wdev); cb->args[1] = idx; - err = skb->len; - cfg80211_unlock_rdev(rdev); - out_put_netdev: - dev_put(dev); + nl80211_finish_netdev_dump(rdev); - return err; + return skb->len; } static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, @@ -3130,29 +3117,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct survey_info survey; struct cfg80211_registered_device *dev; struct net_device *netdev; - int ifidx = cb->args[0]; int survey_idx = cb->args[1]; int res; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - res = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - res = PTR_ERR(dev); - goto out_rtnl; - } + res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (res) + return res; if (!dev->ops->dump_survey) { res = -EOPNOTSUPP; @@ -3180,10 +3150,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, cb->args[1] = survey_idx; res = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return res; } -- cgit v1.2.3 From e31b82136d1adc7a599b6e99d3321e5831841f5a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 19:39:30 +0200 Subject: cfg80211/mac80211: allow per-station GTKs This adds API to allow adding per-station GTKs, updates mac80211 to support it, and also allows drivers to remove a key from hwaccel again when this may be necessary due to multiple GTKs. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 2 +- net/wireless/ibss.c | 2 +- net/wireless/nl80211.c | 87 +++++++++++++++++++++++++++++++++++++++++----- net/wireless/sme.c | 2 +- net/wireless/util.c | 12 +++++-- net/wireless/wext-compat.c | 38 +++++++++++++------- 6 files changed, 116 insertions(+), 27 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.h b/net/wireless/core.h index 37580e090a3..2d1d4c70113 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); /* internal helpers */ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, - const u8 *mac_addr); + bool pairwise, const u8 *mac_addr); void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, size_t ie_len, u16 reason, bool from_ap); void cfg80211_sme_scan_done(struct net_device *dev); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8cb6e08373b..f33fbb79437 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, NULL); + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0c9497170f1..8826888cc14 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -93,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, + [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, @@ -168,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, }; -/* policy for the attributes */ +/* policy for the key attributes */ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, [NL80211_KEY_IDX] = { .type = NLA_U8 }, @@ -176,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, + [NL80211_KEY_TYPE] = { .type = NLA_U32 }, }; /* ifidx get helper */ @@ -306,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct key_parse { struct key_params p; int idx; + int type; bool def, defmgmt; }; @@ -336,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) if (tb[NL80211_KEY_CIPHER]) k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); + if (tb[NL80211_KEY_TYPE]) { + k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + return 0; } @@ -360,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) + return -EINVAL; + } + return 0; } @@ -369,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) memset(k, 0, sizeof(*k)); k->idx = -1; + k->type = -1; if (info->attrs[NL80211_ATTR_KEY]) err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); @@ -433,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, } else if (parse.defmgmt) goto error; err = cfg80211_validate_key_settings(rdev, &parse.p, - parse.idx, NULL); + parse.idx, false, NULL); if (err) goto error; result->params[parse.idx].cipher = parse.p.cipher; @@ -516,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, dev->wiphy.max_scan_ie_len); + if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); + NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, sizeof(u32) * dev->wiphy.n_cipher_suites, dev->wiphy.cipher_suites); @@ -1446,7 +1465,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) int err; struct net_device *dev = info->user_ptr[1]; u8 key_idx = 0; - u8 *mac_addr = NULL; + const u8 *mac_addr = NULL; + bool pairwise; struct get_key_cookie cookie = { .error = 0, }; @@ -1462,6 +1482,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + pairwise = !!mac_addr; + if (info->attrs[NL80211_ATTR_KEY_TYPE]) { + u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); + if (kt >= NUM_NL80211_KEYTYPES) + return -EINVAL; + if (kt != NL80211_KEYTYPE_GROUP && + kt != NL80211_KEYTYPE_PAIRWISE) + return -EINVAL; + pairwise = kt == NL80211_KEYTYPE_PAIRWISE; + } + if (!rdev->ops->get_key) return -EOPNOTSUPP; @@ -1482,8 +1513,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) if (mac_addr) NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, - &cookie, get_key_callback); + if (pairwise && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -ENOENT; + + err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, + mac_addr, &cookie, get_key_callback); if (err) goto free_msg; @@ -1553,7 +1588,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) int err; struct net_device *dev = info->user_ptr[1]; struct key_parse key; - u8 *mac_addr = NULL; + const u8 *mac_addr = NULL; err = nl80211_parse_key(info, &key); if (err) @@ -1565,16 +1600,31 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + if (!rdev->ops->add_key) return -EOPNOTSUPP; - if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) + if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr)) return -EINVAL; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); if (!err) err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, mac_addr, &key.p); wdev_unlock(dev->ieee80211_ptr); @@ -1596,13 +1646,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_MAC]) mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + if (key.type == -1) { + if (mac_addr) + key.type = NL80211_KEYTYPE_PAIRWISE; + else + key.type = NL80211_KEYTYPE_GROUP; + } + + /* for now */ + if (key.type != NL80211_KEYTYPE_PAIRWISE && + key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; + if (!rdev->ops->del_key) return -EOPNOTSUPP; wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr); + + if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + if (!err) - err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); + err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, + key.type == NL80211_KEYTYPE_PAIRWISE, + mac_addr); #ifdef CONFIG_CFG80211_WEXT if (!err) { @@ -3212,6 +3281,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return err; if (key.idx >= 0) { + if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) + return -EINVAL; if (!key.p.key || !key.p.key_len) return -EINVAL; if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f161b984454..e17b0bee6bd 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, */ if (rdev->ops->del_key) for (i = 0; i < 6; i++) - rdev->ops->del_key(wdev->wiphy, dev, i, NULL); + rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); #ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); diff --git a/net/wireless/util.c b/net/wireless/util.c index fb5448f7d55..76120aeda57 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, - const u8 *mac_addr) + bool pairwise, const u8 *mac_addr) { int i; if (key_idx > 5) return -EINVAL; + if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + return -EINVAL; + + if (pairwise && !mac_addr) + return -EINVAL; + /* * Disallow pairwise keys with non-zero index unless it's WEP * (because current deployments use pairwise WEP keys with * non-zero indizes but 802.11i clearly specifies to use zero) */ - if (mac_addr && key_idx && + if (pairwise && key_idx && params->cipher != WLAN_CIPHER_SUITE_WEP40 && params->cipher != WLAN_CIPHER_SUITE_WEP104) return -EINVAL; @@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) for (i = 0; i < 6; i++) { if (!wdev->connect_keys->params[i].cipher) continue; - if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, + if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, &wdev->connect_keys->params[i])) { printk(KERN_ERR "%s: failed to set key %d\n", dev->name, i); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f81..6002265289c 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *addr, - bool remove, bool tx_key, int idx, - struct key_params *params) + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err, i; bool rejoin = false; + if (pairwise && !addr) + return -EINVAL; + if (!wdev->wext.keys) { wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), GFP_KERNEL); @@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, __cfg80211_leave_ibss(rdev, wdev->netdev, true); rejoin = true; } - err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); + + if (!pairwise && addr && + !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) + err = -ENOENT; + else + err = rdev->ops->del_key(&rdev->wiphy, dev, idx, + pairwise, addr); } wdev->wext.connect.privacy = false; /* @@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (addr) tx_key = false; - if (cfg80211_validate_key_settings(rdev, params, idx, addr)) + if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) return -EINVAL; err = 0; if (wdev->current_bss) - err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); + err = rdev->ops->add_key(&rdev->wiphy, dev, idx, + pairwise, addr, params); if (err) return err; @@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, } static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *addr, - bool remove, bool tx_key, int idx, - struct key_params *params) + struct net_device *dev, bool pairwise, + const u8 *addr, bool remove, bool tx_key, + int idx, struct key_params *params) { int err; /* devlist mutex needed for possible IBSS re-join */ mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); - err = __cfg80211_set_encryption(rdev, dev, addr, remove, - tx_key, idx, params); + err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, + remove, tx_key, idx, params); wdev_unlock(dev->ieee80211_ptr); mutex_unlock(&rdev->devlist_mtx); @@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, else if (!remove) return -EINVAL; - return cfg80211_set_encryption(rdev, dev, NULL, remove, + return cfg80211_set_encryption(rdev, dev, false, NULL, remove, wdev->wext.default_key == -1, idx, ¶ms); } @@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, } return cfg80211_set_encryption( - rdev, dev, addr, remove, + rdev, dev, + !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), + addr, remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, idx, ¶ms); } -- cgit v1.2.3 From d537f5fdfcc9c57c1e3b9fb316a4bed2bf7597e7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 21:34:11 +0200 Subject: nl80211: fix error in generic netif_running check Yikes! The error return keeps a netdev reference and the rdev mutex locked, fix that! Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8826888cc14..9942f0b061f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4418,6 +4418,8 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, } if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && !netif_running(dev)) { + cfg80211_unlock_rdev(rdev); + dev_put(dev); if (rtnl) rtnl_unlock(); return -ENETDOWN; -- cgit v1.2.3 From b206b4ef062d83c0875a085672ed50e8c8b01521 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 6 Oct 2010 18:34:12 +0900 Subject: nl80211/mac80211: Add retry and failed transmission count to station info This information is already available in mac80211, we just need to export it via cfg80211 and nl80211. Signed-off-by: Bruno Randolf Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9942f0b061f..524f5540283 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1890,6 +1890,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_PACKETS) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, sinfo->tx_packets); + if (sinfo->filled & STATION_INFO_TX_RETRIES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES, + sinfo->tx_retries); + if (sinfo->filled & STATION_INFO_TX_FAILED) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, + sinfo->tx_failed); nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); -- cgit v1.2.3 From 3207390a8b58bfc1335750f91cf6783c48ca19ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Oct 2010 21:18:04 +0200 Subject: cfg80211: fix BSS double-unlinking When multiple interfaces are actively trying to associate with the same BSS, they may both find that the BSS isn't there and then try to unlink it. This can cause errors since the unlinking code can't currently deal with items that have already been unlinked. Normally this doesn't happen as most people don't try to use multiple station interfaces that associate at the same time too. Fix this by using the list entry as a flag to see if the item is still on a list. Cc: stable@kernel.org Reported-by: Ben Greear Tested-by: Hun-Kyi Wynn Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/scan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c718014..503ebb86ba1 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) bss = container_of(pub, struct cfg80211_internal_bss, pub); spin_lock_bh(&dev->bss_lock); + if (!list_empty(&bss->list)) { + list_del_init(&bss->list); + dev->bss_generation++; + rb_erase(&bss->rbn, &dev->bss_tree); - list_del(&bss->list); - dev->bss_generation++; - rb_erase(&bss->rbn, &dev->bss_tree); - + kref_put(&bss->ref, bss_release); + } spin_unlock_bh(&dev->bss_lock); - - kref_put(&bss->ref, bss_release); } EXPORT_SYMBOL(cfg80211_unlink_bss); -- cgit v1.2.3 From 43b19952de54b0fccfcdc5968891ebe550367fe8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 13:10:30 +0200 Subject: nl80211: use new genl helpers for WDS Bill Jordan's patch to allow setting the WDS peer crossed with my patch removing all the boilerplate code in nl80211, and consequently he didn't make use of it yet. Fix that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 45 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 524f5540283..4fed1663aba 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -876,48 +876,25 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) { - struct cfg80211_registered_device *rdev; - struct wireless_dev *wdev; - struct net_device *dev; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; u8 *bssid; - int err; if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; - rtnl_lock(); - - err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); - if (err) - goto unlock_rtnl; - - wdev = dev->ieee80211_ptr; - - if (netif_running(dev)) { - err = -EBUSY; - goto out; - } + if (netif_running(dev)) + return -EBUSY; - if (!rdev->ops->set_wds_peer) { - err = -EOPNOTSUPP; - goto out; - } + if (!rdev->ops->set_wds_peer) + return -EOPNOTSUPP; - if (wdev->iftype != NL80211_IFTYPE_WDS) { - err = -EOPNOTSUPP; - goto out; - } + if (wdev->iftype != NL80211_IFTYPE_WDS) + return -EOPNOTSUPP; bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); - err = rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); - -out: - cfg80211_unlock_rdev(rdev); - dev_put(dev); -unlock_rtnl: - rtnl_unlock(); - - return err; + return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid); } @@ -4860,6 +4837,8 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_wds_peer, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, }, }; -- cgit v1.2.3 From 388ac775be95e510c2095ed6cd59422a5183a9fb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Oct 2010 13:11:09 +0200 Subject: cfg80211: constify WDS address There's no need for the WDS peer address to not be const, so make it const. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4fed1663aba..882dc921103 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -879,7 +879,7 @@ static int nl80211_set_wds_peer(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; - u8 *bssid; + const u8 *bssid; if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; -- cgit v1.2.3 From 7623225f905263424c7254dc6a07bff083a498dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 11 Oct 2010 14:46:52 -0400 Subject: Revert "wireless: Use first phyX name available when registering phy devices." This reverts commit 5a254ffe3ffdfa84fe076009bd8e88da412180d2. The commit failed to take into account that allocated wireless devices (wiphys) are not added into the device list upon allocation, but only when they are registered. Therefore, it opened up a race between allocating and registering a name, so that if two processes allocate and register concurrently ("alloc, alloc, register, register" rather than "alloc, register, alloc, register") the code will attempt to use the same name twice. Signed-off-by: Johannes Berg --- net/wireless/core.c | 54 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 30 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/core.c b/net/wireless/core.c index 1684ad91763..9c21ebf9780 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -178,10 +178,26 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { struct cfg80211_registered_device *rdev2; - int result; + int wiphy_idx, taken = -1, result, digits; assert_cfg80211_lock(); + /* prohibit calling the thing phy%d when %d is not its number */ + sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); + if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { + /* count number of places needed to print wiphy_idx */ + digits = 1; + while (wiphy_idx /= 10) + digits++; + /* + * deny the name if it is phy where is printed + * without leading zeroes. taken == strlen(newname) here + */ + if (taken == strlen(PHY_NAME) + digits) + return -EINVAL; + } + + /* Ignore nop renames */ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) return 0; @@ -189,7 +205,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, /* Ensure another device does not already have this name. */ list_for_each_entry(rdev2, &cfg80211_rdev_list, list) if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) - return -EEXIST; + return -EINVAL; result = device_rename(&rdev->wiphy.dev, newname); if (result) @@ -304,11 +320,9 @@ static void cfg80211_event_work(struct work_struct *work) struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { static int wiphy_counter; - int i; - struct cfg80211_registered_device *rdev, *rdev2; + + struct cfg80211_registered_device *rdev; int alloc_size; - char nname[IFNAMSIZ + 1]; - bool found = false; WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key)); WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc)); @@ -332,37 +346,17 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) if (unlikely(!wiphy_idx_valid(rdev->wiphy_idx))) { wiphy_counter--; - goto too_many_devs; - } - - /* 64k wiphy devices is enough for anyone! */ - for (i = 0; i < 0xFFFF; i++) { - found = false; - snprintf(nname, sizeof(nname)-1, PHY_NAME "%d", i); - nname[sizeof(nname)-1] = 0; - list_for_each_entry(rdev2, &cfg80211_rdev_list, list) - if (strcmp(nname, dev_name(&rdev2->wiphy.dev)) == 0) { - found = true; - break; - } - - if (!found) - break; - } - - if (unlikely(found)) { -too_many_devs: mutex_unlock(&cfg80211_mutex); - /* ugh, too many devices already! */ + /* ugh, wrapped! */ kfree(rdev); return NULL; } - /* give it a proper name */ - dev_set_name(&rdev->wiphy.dev, "%s", nname); - mutex_unlock(&cfg80211_mutex); + /* give it a proper name */ + dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); + mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); INIT_LIST_HEAD(&rdev->netdev_list); -- cgit v1.2.3 From 5a5c731aa59cc2c44ca20f45b1a577cd4f5435e2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 7 Oct 2010 16:39:20 -0700 Subject: wireless: Set some stats used by /proc/net/wireless (wext) Some stats for /proc/net/wireless (and wext in general) are not being set. This patch addresses a few of those with values easily obtained from mac80211 core. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/wireless/wext-compat.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6002265289c..12222ee6ebf 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1366,6 +1366,10 @@ struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) } wstats.qual.updated |= IW_QUAL_NOISE_INVALID; + if (sinfo.filled & STATION_INFO_RX_DROP_MISC) + wstats.discard.misc = sinfo.rx_dropped_misc; + if (sinfo.filled & STATION_INFO_TX_FAILED) + wstats.discard.retries = sinfo.tx_failed; return &wstats; } -- cgit v1.2.3 From 8610c29a2c9f273886b1c31ae4d92c69d4326262 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Oct 2010 02:39:29 +0200 Subject: cfg80211: add channel utilization stats to the survey command Using these, user space can calculate a relative channel utilization with arbitrary intervals by regularly taking snapshots of the survey results. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 882dc921103..c506241f863 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3153,6 +3153,21 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, survey->noise); if (survey->filled & SURVEY_INFO_IN_USE) NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, + survey->channel_time); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + survey->channel_time_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, + survey->channel_time_ext_busy); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, + survey->channel_time_rx); + if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) + NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + survey->channel_time_tx); nla_nest_end(msg, infoattr); -- cgit v1.2.3 From cfd8e12f42746df396ecbdf7a1d8e92e8e4dbb97 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 11 Oct 2010 10:28:59 -0700 Subject: wireless: Print wiphy name in sysfs. The index cannot be used to reliably reconstruct a phy name, so explicitly add the phy name to sysfs so that scripts can figure out the parent phy device for a particular wireless interface. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- net/wireless/sysfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net/wireless') diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 74a9e3cce45..4294fa22bb2 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -35,6 +35,14 @@ SHOW_FMT(index, "%d", wiphy_idx); SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; + return sprintf(buf, "%s\n", dev_name(&wiphy->dev)); +} + + static ssize_t addresses_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -57,6 +65,7 @@ static struct device_attribute ieee80211_dev_attrs[] = { __ATTR_RO(macaddress), __ATTR_RO(address_mask), __ATTR_RO(addresses), + __ATTR_RO(name), {} }; -- cgit v1.2.3 From 271733cf844a2f5f186ef3b40c26d6397b71039a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Oct 2010 12:06:23 +0200 Subject: cfg80211: notify drivers about frame registrations Drivers may need to adjust their filters according to frame registrations, so notify them about them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/mlme.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index caf11a42750..26838d903b9 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -764,6 +764,8 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, u16 frame_type, const u8 *match_data, int match_len) { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg, *nreg; int err = 0; u16 mgmt_type; @@ -810,22 +812,37 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, nreg->frame_type = cpu_to_le16(frame_type); list_add(&nreg->list, &wdev->mgmt_registrations); + if (rdev->ops->mgmt_frame_register) + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, true); + out: spin_unlock_bh(&wdev->mgmt_registrations_lock); + return err; } void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg, *tmp; spin_lock_bh(&wdev->mgmt_registrations_lock); list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { - if (reg->nlpid == nlpid) { - list_del(®->list); - kfree(reg); + if (reg->nlpid != nlpid) + continue; + + if (rdev->ops->mgmt_frame_register) { + u16 frame_type = le16_to_cpu(reg->frame_type); + + rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + frame_type, false); } + + list_del(®->list); + kfree(reg); } spin_unlock_bh(&wdev->mgmt_registrations_lock); -- cgit v1.2.3 From 9ebad4ab87f2ffa6eca825327721e647c7457264 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Oct 2010 13:41:35 +0200 Subject: radiotap: fix vendor namespace parsing There's a bug with radiotap vendor namespace parsing if you don't register for the given namespace extensions. Fix this by passing only the unknown vendor namespaces and the registered data to frontends, but not both. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/radiotap.c | 58 +++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index c774bc0f155..dbe35e138e9 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c @@ -201,7 +201,7 @@ int ieee80211_radiotap_iterator_next( { while (1) { int hit = 0; - int pad, align, size, subns, vnslen; + int pad, align, size, subns; uint32_t oui; /* if no more EXT bits, that's it */ @@ -261,6 +261,27 @@ int ieee80211_radiotap_iterator_next( if (pad) iterator->_arg += align - pad; + if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { + int vnslen; + + if ((unsigned long)iterator->_arg + size - + (unsigned long)iterator->_rtheader > + (unsigned long)iterator->_max_length) + return -EINVAL; + + oui = (*iterator->_arg << 16) | + (*(iterator->_arg + 1) << 8) | + *(iterator->_arg + 2); + subns = *(iterator->_arg + 3); + + find_ns(iterator, oui, subns); + + vnslen = get_unaligned_le16(iterator->_arg + 4); + iterator->_next_ns_data = iterator->_arg + size + vnslen; + if (!iterator->current_namespace) + size += vnslen; + } + /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test @@ -287,40 +308,25 @@ int ieee80211_radiotap_iterator_next( /* these special ones are valid in each bitmap word */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - iterator->_reset_on_ext = 1; - vnslen = get_unaligned_le16(iterator->this_arg + 4); - iterator->_next_ns_data = iterator->_arg + vnslen; - oui = (*iterator->this_arg << 16) | - (*(iterator->this_arg + 1) << 8) | - *(iterator->this_arg + 2); - subns = *(iterator->this_arg + 3); - - find_ns(iterator, oui, subns); - iterator->is_radiotap_ns = 0; - /* allow parsers to show this information */ + /* + * If parser didn't register this vendor + * namespace with us, allow it to show it + * as 'raw. Do do that, set argument index + * to vendor namespace. + */ iterator->this_arg_index = IEEE80211_RADIOTAP_VENDOR_NAMESPACE; - iterator->this_arg_size += vnslen; - if ((unsigned long)iterator->this_arg + - iterator->this_arg_size - - (unsigned long)iterator->_rtheader > - (unsigned long)(unsigned long)iterator->_max_length) - return -EINVAL; - hit = 1; - break; + if (!iterator->current_namespace) + hit = 1; + goto next_entry; case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: - iterator->_bitmap_shifter >>= 1; - iterator->_arg_index++; - iterator->_reset_on_ext = 1; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; - break; + goto next_entry; case IEEE80211_RADIOTAP_EXT: /* * bit 31 was set, there is more -- cgit v1.2.3