Re: [PATCH v6 2/3] mac80211: Define new driver callback replace_key
Hi Alexander, Just minor nitpicks: + * @replace_key: Replace an exiting in use key with a new one while guaranteeing + * to not leak clear text packets. Implementing this callback will enable + * mac80211 to announce NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE. + * Packets already queued must not be send out encrypted with the new key send out -> sent out + * and packets decoded with the old key must not be handed over to mac80211 + * when the driver is not checking IV/ICV itself once the callback has been + * completed. + * Mac80211 will log an error when asked to use replace a PTK key + * without replace_key but will still perform the then potentially + * insecure action via set_key for backward compatibility for now. + * Not sure this part really belongs in the driver method description? * @update_tkip_key: See the section "Hardware crypto acceleration" *This callback will be called in the context of Rx. Called for drivers *which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4fb2709cb527..84cc8005c19a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -572,9 +572,14 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); } + if (ops->replace_key) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE); + if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + Stray whitespace? if (ops->wake_tx_queue) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); Regards, -Denis
Re: [PATCH v6 1/3] nl80211: Add ATOMIC_KEY_REPLACE API
Hi Alexander, On 08/14/2018 05:42 AM, Alexander Wetzel wrote: Drivers able to correctly replace a in-use key should set NL80211_EXT_FEATURE_ATOMIC_KEY_REPLACE to allow the userspace (e.g. hostapd or wpa_supplicant) to rekey PTK keys. The userspace must detect a PTK rekey attempt and only go ahead with the rekey when the driver has set this flag. If the driver is not supporting the feature the userspace either must not replace the PTK key or perform a full re-association. Ignoring this flag and continuing to rekey the connection can still work but has to be considered insecure and broken. It can leak cleartext packets or freeze the connection and is only supported to allow the userspace to be updated. Signed-off-by: Alexander Wetzel --- include/uapi/linux/nl80211.h | 6 ++ 1 file changed, 6 insertions(+) This looks good to me from a userspace perspective. I will try to implement support for this in iwd soon to give you a prototype to play with. Reviewed-by: Denis Kenzior Regards, -Denis
Re: [PATCH v2] mac80211: Fix wlan freezes under load at rekey
Hi Alexander, On 07/11/2018 12:08 PM, Alexander Wetzel wrote: Hi Denis, Hi Alexander, hostapd or wpa_supplicant are "ordering" mac80211 to install a new key and are implementing the state machine and are in a good position to handle the fallout... at least theoretically. Ideally it would even know beforehand that we don't want to handle the PTK rekeying, and then could reconnect instead of going through the handshake. Don't see how we could do that in the kernel, all the relevant information is handled in the state machine. I guess an API extension telling hostap/supplicant if we can handle rekeys or not would tbe he only way to avoid that. Can the kernel / driver provide some sort of hint to user space that PTK rekey isn’t supported? We could then have user space deauthenticate with a big warning about what/why this is happening and try to re-connect to the last used BSS. Sure. In fact the latest patch is already doing that by returning an error when set_key is called for PTK and it's not an initial call. Tests with wpa_supplicant shows that this is is then handled like the initial key set is failing. Networkmanager prompts for the password and wpa_supplicant running without seems to blacklist a reconnect for 15s. Ideally we shouldn't even get this far. We really need some kind of capability bit on the phy telling userspace whether PTK rekey is supported or not. Then userspace can take proper action based on this information. E.g. if PTK rekey isn't safe, then we can simply issue a CMD_DISCONNECT and re-connect to the last BSS. The kernel doesn't need to play any 'tricks'. The fact that current userspace implementations are broken is regrettable and needs to be fixed. I kind of liked that solution, but with existing implematations out this is indeed awkward to find a "correct" solution. The main problem for me currently is to find a correct and still acceptable solution. This turned from "let's fix this nasty wlan connection freezes" to a projet spanning the complete wlan stack: From hardware up to and including the userspace... Right. The problem is that this PTK rekey likely 'works' (for some definition thereof) in a vast majority of cases, e.g. the link isn't broken, so the user doesn't notice. So, if the kernel starts to unilaterally issue disconnects, you will have a lot of grumbling users. Just to clarify, I'm not arguing against this necessarily. I can see why issuing a disconnect is a good idea for many reasons (e.g. security, etc.) But, I would expect a lot of user backlash if this is done, and given that this has been an issue for many years, I wonder if its the right way of handling this? It's fun to learn how that interacts (if not very fast), I'm stuggling finding the best way forward here. Whatever we do has undesired consequences. Maybe I'm missing something, but here the high level options we have in my opinion: 1) Keep it as it is and solve that in a indefinite future when we and the world implement the ieee802.11 2012 addition, to use key 0+1 for PTK and 2+3 for GTK - rekey has a extrem high probability of freezing connections and leaking a few clear text packets for years (decades?) to come + The issue is fixed at the core It would seem to me that 0+1 rekey is a separate issue that needs to be supported in both kernel and userspace anyway. 2) Make it worse, like some (most) Windows systems/cards seem to handle it by encrypting EAPOL #4 with the NEW key, breaking the handshake and forcing a reconnect. - break something more to fix a problem sounds like a insane approach + This seems to be quite common and therefore well "tested" (based on my very limited data on that) This seems awful. And then if you're unlucky someone will come in and tell you that the kernel has to maintain this 'legacy' behavior forever. So things can't ever be fixed. Plus, as I already mentioned above, some users 'think' that PTK rekey already works just fine. 3) Fix what we can in mac80211 but keep the API stable - Without driver actions still many drivers will be "undefined" and even if they are not freezing leak packets + This will reduce the problems to a fraction of what is is today with only a mac80211 update 4) Redesign the mac80211 rekey handling and interaction with drivers to only rekey if it is save and decline when not. + We only have to touch the kernel - any supplicant (whatever runs the wpa state machine) may get errors where the programmes did not expect them, leading to unexpected side effects. 5) The full-stack solution: Update the API for the userpace + We do not have to "trick" the wpa state machine to disconnect, the programmers of it have to code it. - Well, it must be suppurted from the wpa state machine. If not we still have to handle the rekey somehow or we accept freezes/cleartext leaks... The last two solutions will also need some "fallback" when a secure rekey is not possible and/or the user is runing an old
Re: [PATCH v2] mac80211: Fix wlan freezes under load at rekey
Hi Alexander, hostapd or wpa_supplicant are "ordering" mac80211 to install a new key and are implementing the state machine and are in a good position to handle the fallout... at least theoretically. Ideally it would even know beforehand that we don't want to handle the PTK rekeying, and then could reconnect instead of going through the handshake. Don't see how we could do that in the kernel, all the relevant information is handled in the state machine. I guess an API extension telling hostap/supplicant if we can handle rekeys or not would tbe he only way to avoid that. Can the kernel / driver provide some sort of hint to user space that PTK rekey isn’t supported? We could then have user space deauthenticate with a big warning about what/why this is happening and try to re-connect to the last used BSS. So I think we're probably better off accepting the set_key but not actually using it, and instead disconnecting... even if that's awkward and should come with a big comment :-) Instead of returning an error I'll change the code to accept the rekey but do nothing with it. (Basically delete the new key and keep the old active). And of course calling ieee80211_set_disassoc() prior to return "success". Let's see how the supplicant will react on a disassoc while doing a rekey... This sounds pretty awful actually. Now that wpa_s is not the only game in town, can we stop resorting to these tactics? Regards, -Denis
Re: Proper SET_KEY usage?
Hi Johannes, On 07/06/2018 07:17 AM, Johannes Berg wrote: Hi, Yeah. This stuff grew out of WEXT mostly, and what things wpa_s did at the time... Right. My main intent with this was to see if I could understand things enough to actually start fixing some of the docs, see if we need to deprecate some things and/or maybe fix bits inside nl80211. :-) That'd be very welcome! So it sounds like SET_KEY is completely unnecessary for a unicast key in an RSN/WPA association for an STA. Should we update mac80211 (and possibly nl80211, though likely it doesn't have enough info) to issue a warning when someone tries to use set_key on such a key? I'm not sure I see much point, since we'll have to deal with older wpa_s basically forever? Do we though? I can understand not breaking userspace APIs, but it seems like this API had only a single user (up until recently) and it 'should' be acceptable to break ancient versions of it. Whether we can or not is a question for the wider community though... What about AP/IBSS? Aren't unicast keys also per-station in this case? It sounds like SET_KEY isn't useful in this context either, right? Yes, same situation really. What about WEP? WEP is a special case, you typically use the same key for all traffic, and may switch around between them. In theory though, and I think this API allows you to do it, you can have multiple WEP keys and use different ones for unicast/multicast TX. Or the same. Or switch them around as you like. Put another way, should we deprecate the whole NL80211_KEY_DEFAULT_TYPE_UNICAST attribute? Perhaps. I'm not sure I see much point in it. The WEP case above is pretty fringe, and wext didn't support it, so ... probably not needed? Should we at least take this out of the driver API then and have it ignored by nl80211? And maybe mark this deprecated in the docs? And since you went off on a tangent (maybe this needs a separate discussion?) but... Can you elaborate about PTK rekeying with a non-zero key index? Are you saying that in IBSS/AP mode we can't support PTK rekey? We can't properly support PTK rekeying in any mode, see Alexander Wetzel's patch and the whole discussion on the different versions I had with him. I'll merge his patch soon I think, but it doesn't really work properly. I think we had this conversation before. Up to 802.11-2012, PTK Rekey was not really explicitly mentioned as possible. There were hints and stuff, but no explicit language. I think in 802.11-2016 they finally explicitly say that this is possible. However, we seem to have networks that perform PTK Rekey and even full 802.1X re-auth every hour (eduroam for example). How is this working? Or is it a case of it not always working? Some time relatively recently (802.11-2016 I think) the spec has introduced a method to indicate that you support what was previously not allowed at all: using non-zero key index for a PTK. This way, you can do transparent PTK rekeying like you do with GTK now, by switching to a new key index when you rekey. And keep the old one for whatever packets are in process, right? That makes more sense. We don't - currently - support this in mac80211 or even wpa_supplicant, and I expect many devices would have issues with this with hardware offload. I'm also not aware of any certification program for it, but I also haven't followed the WPA3 efforts (but I don't think they're focused here, they're focused on algorithms and higher layers IIRC.) Does the recent PMK handshake offload support proposal take into consideration PTK rekeying? (The difference between them is that in IBSS you will have per-station GTKs, but that's also irrelevant because those are only used for RX - your own GTK on the netdev/wdev/sdata/vif level is used for TX.) Okay, so for GTKs we would have a per-station RX GTK and a 'default' TX GTK. So in this case a SET_KEY would be needed only on the 'default' TX GTK index. Okay, maybe a tangent, but this brings up a question: Why do we have separate steps for this operation? Can't we just issue a NEW_KEY and have the kernel figure this out? I think the only case would be WEP? So can we expect all drivers to operate this way? Or should we maybe also have nl80211 call set_key operation on a key with no associated STA implicitly? Well, that's what I was pointing out earlier, the whole Multicast attribute is ignored and should not be sent in the first place: >> Key Default Types: len 4 >> Multicast: true The proof :) follows: :) So while nl80211_new_key actually parses this information (stored in struct key_parse) it never forwards any of it to the driver. The group key vs pairwise key determination seems to be predicated on presence of NL80211_ATTR_KEY_TYPE and the following fallback: if (key.type == -1) { if (mac_addr) key.type = NL80211_KEYTYPE_PAIRWISE; else
[PATCH v2] nl80211/mac80211: allow non-linear skb in rx_control_port
The current implementation of cfg80211_rx_control_port assumed that the caller could provide a contiguous region of memory for the control port frame to be sent up to userspace. Unfortunately, many drivers produce non-linear skbs, especially for data frames. This resulted in userspace getting notified of control port frames with correct metadata (from address, port, etc) yet garbage / nonsense contents, resulting in bad handshakes, disconnections, etc. mac80211 linearizes skbs containing management frames. But it didn't seem worthwhile to do this for control port frames. Thus the signature of cfg80211_rx_control_port was changed to take the skb directly. nl80211 then takes care of obtaining control port frame data directly from the (linear | non-linear) skb. The caller is still responsible for freeing the skb, cfg80211_rx_control_port does not take ownership of it. Signed-off-by: Denis Kenzior --- v2 changes: - Reword commit header - Rework tracing slightly per Arend's feedback - Added blurb about skb->protocol in include/net/cfg80211.h include/net/cfg80211.h | 12 ++-- net/mac80211/rx.c | 5 + net/wireless/nl80211.c | 24 +++- net/wireless/trace.h | 18 ++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9ba1f289c439..beed5b2a3933 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5937,10 +5937,11 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** * cfg80211_rx_control_port - notification about a received control port frame * @dev: The device the frame matched to - * @buf: control port frame - * @len: length of the frame data - * @addr: The peer from which the frame was received - * @proto: frame protocol, typically PAE or Pre-authentication + * @skb: The skbuf with the control port frame. It is assumed that the skbuf + * is 802.3 formatted (with 802.3 header). The skb can be non-linear. This + * function does not take ownership of the skb, so the caller is responsible + * for any cleanup. The caller must also ensure that skb->protocol is set + * appropriately. * @unencrypted: Whether the frame was received unencrypted * * This function is used to inform userspace about a received control port @@ -5953,8 +5954,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, * Return: %true if the frame was passed to userspace */ bool cfg80211_rx_control_port(struct net_device *dev, - const u8 *buf, size_t len, - const u8 *addr, u16 proto, bool unencrypted); + struct sk_buff *skb, bool unencrypted); /** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a16ba568e2a3..64742f2765c4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2370,11 +2370,8 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, sdata->control_port_over_nl80211)) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); bool noencrypt = status->flag & RX_FLAG_DECRYPTED; - struct ethhdr *ehdr = eth_hdr(skb); - cfg80211_rx_control_port(dev, skb->data, skb->len, -ehdr->h_source, -be16_to_cpu(skb->protocol), noencrypt); + cfg80211_rx_control_port(dev, skb, noencrypt); dev_kfree_skb(skb); } else { /* deliver to local stack */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8db59129c095..b75a0144c0a5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15036,20 +15036,24 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, EXPORT_SYMBOL(cfg80211_mgmt_tx_status); static int __nl80211_rx_control_port(struct net_device *dev, -const u8 *buf, size_t len, -const u8 *addr, u16 proto, +struct sk_buff *skb, bool unencrypted, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct ethhdr *ehdr = eth_hdr(skb); + const u8 *addr = ehdr->h_source; + u16 proto = be16_to_cpu(skb->protocol); struct sk_buff *msg; void *hdr; + struct nlattr *frame; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); if (!nlportid) return -ENOENT; - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + skb->len, gfp); if (!msg) return -ENOMEM; @@ -15063,13 +15067,17 @@ static int __n
Re: [PATCH] nl80211/mac80211: Fix cfg80211_rx_control_port
Hi Arend, On 07/03/2018 02:18 PM, Arend van Spriel wrote: Hi Denis, I prefer the subject summarizes the issue, eg. "allow non-linear skb data passed to cfg80211_rx_control_port". Right, I'll fix this in the next version. On 7/3/2018 8:26 PM, Denis Kenzior wrote: The current implementation of cfg80211_rx_control_port assumed that the caller could provide a contiguous region of memory for the control port frame to be sent up to userspace. Unfortunately, many drivers produce non-linear skbs, especially for data frames. This resulted in userspace getting notified of control port frames with correct metadata (from address, port, etc) yet garbage / nonsense contents, resulting in bad handshakes, disconnections, etc. [snip] diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9ba1f289c439..94842c2a2f73 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5937,10 +5937,10 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** * cfg80211_rx_control_port - notification about a received control port frame * @dev: The device the frame matched to - * @buf: control port frame - * @len: length of the frame data - * @addr: The peer from which the frame was received - * @proto: frame protocol, typically PAE or Pre-authentication + * @skb: The skbuf with the control port frame. It is assumed that the skbuf + * is 802.3 formatted (with 802.3 header). The skb can be non-linear. This + * function does not take ownership of the skb, so the caller is responsible + * for any cleanup. * @unencrypted: Whether the frame was received unencrypted * * This function is used to inform userspace about a received control port @@ -5953,8 +5953,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, * Return: %true if the frame was passed to userspace */ bool cfg80211_rx_control_port(struct net_device *dev, - const u8 *buf, size_t len, - const u8 *addr, u16 proto, bool unencrypted); + struct sk_buff *skb, bool unencrypted); If we are changing the signature, could we change the return type to int. I don't see much value in the int-2-bool conversion. I was mostly following the pattern in other cfg80211_rx_ functions here. They all return bool or void. I'm fine either way. /** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event [snip] diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8db59129c095..b75a0144c0a5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15036,20 +15036,24 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, EXPORT_SYMBOL(cfg80211_mgmt_tx_status); static int __nl80211_rx_control_port(struct net_device *dev, - const u8 *buf, size_t len, - const u8 *addr, u16 proto, + struct sk_buff *skb, bool unencrypted, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct ethhdr *ehdr = eth_hdr(skb); + const u8 *addr = ehdr->h_source; + u16 proto = be16_to_cpu(skb->protocol); So this means skb->protocol has to be set by driver (using eth_type_trans() helper). Guess mac80211 does it for sure, but better make it a clear requirement for cfg80211-based drivers. Right, mac80211 uses skb->protocol to do the filtering, so this is already done. We could make protocol and addr explicit arguments, but it seemed strange to not extract these from the skb. I guess we could also extract the proto from the eth_hdr or call eth_type_trans inside nl80211. I have no strong feelings here. It would be great if another driver or two tried to implement this and gave us feedback as to which works better... struct sk_buff *msg; void *hdr; + struct nlattr *frame; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); if (!nlportid) return -ENOENT; - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + skb->len, gfp); if (!msg) return -ENOMEM; @@ -15063,13 +15067,17 @@ static int __nl80211_rx_control_port(struct net_device *dev, nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), NL80211_ATTR_PAD) || - nla_put(msg, NL80211_ATTR_FRAME, len, buf) || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) || (unencrypted && nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) goto nla_put_failure; + frame = nla_reserve(msg, NL80211_ATTR_FRAME, skb->len); + if (!frame) + goto nla_put_failure; + + skb_copy_bits(skb, 0, nla_da
[PATCH] nl80211/mac80211: Fix cfg80211_rx_control_port
The current implementation of cfg80211_rx_control_port assumed that the caller could provide a contiguous region of memory for the control port frame to be sent up to userspace. Unfortunately, many drivers produce non-linear skbs, especially for data frames. This resulted in userspace getting notified of control port frames with correct metadata (from address, port, etc) yet garbage / nonsense contents, resulting in bad handshakes, disconnections, etc. mac80211 linearizes skbs containing management frames. But it didn't seem worthwhile to do this for control port frames. Thus the signature of cfg80211_rx_control_port was changed to take the skb directly. nl80211 then takes care of obtaining control port frame data directly from the (linear | non-linear) skb. The caller is still responsible for freeing the skb, cfg80211_rx_control_port does not take ownership of it. Signed-off-by: Denis Kenzior --- include/net/cfg80211.h | 11 +-- net/mac80211/rx.c | 5 + net/wireless/nl80211.c | 24 +++- net/wireless/trace.h | 26 +- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9ba1f289c439..94842c2a2f73 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5937,10 +5937,10 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** * cfg80211_rx_control_port - notification about a received control port frame * @dev: The device the frame matched to - * @buf: control port frame - * @len: length of the frame data - * @addr: The peer from which the frame was received - * @proto: frame protocol, typically PAE or Pre-authentication + * @skb: The skbuf with the control port frame. It is assumed that the skbuf + * is 802.3 formatted (with 802.3 header). The skb can be non-linear. This + * function does not take ownership of the skb, so the caller is responsible + * for any cleanup. * @unencrypted: Whether the frame was received unencrypted * * This function is used to inform userspace about a received control port @@ -5953,8 +5953,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, * Return: %true if the frame was passed to userspace */ bool cfg80211_rx_control_port(struct net_device *dev, - const u8 *buf, size_t len, - const u8 *addr, u16 proto, bool unencrypted); + struct sk_buff *skb, bool unencrypted); /** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a16ba568e2a3..64742f2765c4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2370,11 +2370,8 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, sdata->control_port_over_nl80211)) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); bool noencrypt = status->flag & RX_FLAG_DECRYPTED; - struct ethhdr *ehdr = eth_hdr(skb); - cfg80211_rx_control_port(dev, skb->data, skb->len, -ehdr->h_source, -be16_to_cpu(skb->protocol), noencrypt); + cfg80211_rx_control_port(dev, skb, noencrypt); dev_kfree_skb(skb); } else { /* deliver to local stack */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8db59129c095..b75a0144c0a5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15036,20 +15036,24 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, EXPORT_SYMBOL(cfg80211_mgmt_tx_status); static int __nl80211_rx_control_port(struct net_device *dev, -const u8 *buf, size_t len, -const u8 *addr, u16 proto, +struct sk_buff *skb, bool unencrypted, gfp_t gfp) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct ethhdr *ehdr = eth_hdr(skb); + const u8 *addr = ehdr->h_source; + u16 proto = be16_to_cpu(skb->protocol); struct sk_buff *msg; void *hdr; + struct nlattr *frame; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); if (!nlportid) return -ENOENT; - msg = nlmsg_new(100 + len, gfp); + msg = nlmsg_new(100 + skb->len, gfp); if (!msg) return -ENOMEM; @@ -15063,13 +15067,17 @@ static int __nl80211_rx_control_port(struct net_device *dev, nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), N
Re: Proper SET_KEY usage?
Hi Johannes, On 06/29/2018 05:01 AM, Johannes Berg wrote: Hi Denis, Hope you don't mind me adding the list to the explanations, so they're recorded. Your questions are completely reasonable, after all :-) Absolutely do not mind. So I've been poking around a bit more in nl80211/mac80211 stuff and I was curious how exactly NEW_KEY/SET_KEY are supposed to be used. The documentation is lets say... less than stellar. Yeah. This stuff grew out of WEXT mostly, and what things wpa_s did at the time... Right. My main intent with this was to see if I could understand things enough to actually start fixing some of the docs, see if we need to deprecate some things and/or maybe fix bits inside nl80211. So here's a excerpts from a capture of wpa_supplicant 2.6 connecting to a PSK (CCMP + MFP-enabled) BSS. So first thing it does is creates the pairwise key via CMD_NEW_KEY: < Request: New Key (0x0b) len 68 [ack] Interface Index: 3 (0x0003) Key Data: len 16 [...] Key Cipher: CCMP (00:0f:ac) suite 04 Key Sequence: len 6 00 00 00 00 00 00 MAC Address [...] Key Index: 0 (0x00) > Response: New Key (0x0b) len 4 [0x100] Status: Success (0) So far so good. Yeah, that seems reasonable :-) The next thing it does is: < Request: Set Key (0x0a) len 28 [ack] Interface Index: 3 (0x0003) Key Index: 0 (0x00) Key Default: true Key Default Types: len 4 Unicast: true > Response: Set Key (0x0a) len 4 [0x100] Status: Success (0) This part is a bit bizarre. Yeah. Maybe Jouni can chime in why this happens. I suspect the reason is some legacy with wext or ancient drivers. First it seems to be a complete no-op on mac80211 because mac80211 puts the key into sta->ptk, while ieee80211_set_default_key is fully ignorant of the sta and only operates on struct ieee80211_sub_if_data. Indeed. PTKs are also immediately selected for TX. Is this really intended to be used this way? Is SET_KEY useful / necessary in an STA context? What is the intended usage here? Even if we implement, in the future, PTK rekeying properly with non-zero key index, I think we could still set the key for TX immediately, and keep the other for RX, so it shouldn't be necessary in any way for a PTK (or actually for a per-station key, which differs slightly) context. So it sounds like SET_KEY is completely unnecessary for a unicast key in an RSN/WPA association for an STA. Should we update mac80211 (and possibly nl80211, though likely it doesn't have enough info) to issue a warning when someone tries to use set_key on such a key? What about AP/IBSS? Aren't unicast keys also per-station in this case? It sounds like SET_KEY isn't useful in this context either, right? What about WEP? Put another way, should we deprecate the whole NL80211_KEY_DEFAULT_TYPE_UNICAST attribute? And since you went off on a tangent (maybe this needs a separate discussion?) but... Can you elaborate about PTK rekeying with a non-zero key index? Are you saying that in IBSS/AP mode we can't support PTK rekey? (The difference between them is that in IBSS you will have per-station GTKs, but that's also irrelevant because those are only used for RX - your own GTK on the netdev/wdev/sdata/vif level is used for TX.) Okay, so for GTKs we would have a per-station RX GTK and a 'default' TX GTK. So in this case a SET_KEY would be needed only on the 'default' TX GTK index. Okay, maybe a tangent, but this brings up a question: Why do we have separate steps for this operation? Can't we just issue a NEW_KEY and have the kernel figure this out? Okay, then wpa_s sets the Group key: < Request: New Key (0x0b) len 64 [ack] Interface Index: 3 (0x0003) Key Data: len 16 [...] Key Cipher: CCMP (00:0f:ac) suite 04 Key Sequence: len 6 c8 08 00 00 00 00 Key Default Types: len 4 Multicast: true Key Index: 1 (0x01) > Response: New Key (0x0b) len 4 [0x100] Status: Success (0) wpa_s doesn't use CMD_SET_KEY at all for the key created above. Notice the completely superfluous 'Key Default Types' attribute. This will be ignored by nl80211 when invoking the add_key driver method. CMD_SET_KEY is only used in contexts where you might transmit with the key, this isn't true for the GTK in client-mode. The key types is an artifact of the IBSS I described I think, in this case you don't have a station MAC address for the key, but for GTK in IBSS you will have a MAC address (because the GTK for RX is per station) but you still need to tag it as being a GTK and not PTK. Well, that's what I was pointing out earlier, the whole Multicast attribute is ignored and should not be sent in the first place: >> Key Default Types: len 4 >> Multicast: true The proof :) follows: add_key has the following signature: int (*add_key)(struct wiphy *wiphy, struct
Re: [BUG] mac80211: Using smp_processor_id() in preemptible code: iwd
Hi Johannes, > On Jun 15, 2018, at 7:30 AM, Johannes Berg wrote: > > On Fri, 2018-06-15 at 11:09 +, McGinn, Dan wrote: >> Hi, I'm newly trying out Intel iwd daemon but I experience regular kernel >> errors in 4.17, although WPA2-PSK connection remains stable. These errors >> don't seem to be experienced with wpa_supplicant. The errors reliably >> appear around the following events: >> netdev_unicast_notify() >> netdev_control_port_frame_event() >> netdev_set_rekey_offload() >> netdev_set_gtk() >> >> @Denkenz in IRC helpfully suggests Johannes could follow the finger of >> suspicion to this commit: >> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=911806491425d79107cadddbde11b42bbdfe38c8 > > It's his code ;-) Right, but you’re much more aware of all the locking issues than I am. > > Clearly this comes from cfg80211 without any locking other than rtnl, so > you don't have preemption disabled. That's the minimum needed to get rid > of the warning you found. In my defense, I did ask you whether there are any potential locking issues in the RFC and you didn’t think there were any. I posted a fix for this. Could you please review? Regards, -Denis
[PATCH] mac80211: Fix oops in ieee80211_tx_control_port
On pre-emption enabled kernels the following oops was being seen due to missing local_bh_disable/local_bh_enable calls. mac80211 assumes that pre-emption is disabled in the data path. [ 5365.229756] Call Trace: [ 5365.229762] dump_stack+0x5c/0x80 [ 5365.229766] check_preemption_disabled.cold.0+0x46/0x51 [ 5365.229779] __ieee80211_subif_start_xmit+0x144/0x210 [mac80211] [ 5365.229790] ieee80211_tx_control_port+0x116/0x140 [mac80211] [ 5365.229806] nl80211_tx_control_port+0x13c/0x270 [cfg80211] [ 5365.229810] genl_family_rcv_msg+0x1c4/0x3a0 [ 5365.229814] ? nlmon_xmit+0x3c/0x50 [nlmon] [ 5365.229816] ? dev_hard_start_xmit+0xa5/0x240 [ 5365.229817] genl_rcv_msg+0x47/0x90 [ 5365.229818] ? genl_family_rcv_msg+0x3a0/0x3a0 [ 5365.229820] netlink_rcv_skb+0x4c/0x120 [ 5365.229821] genl_rcv+0x24/0x40 [ 5365.229822] netlink_unicast+0x196/0x240 [ 5365.229824] netlink_sendmsg+0x1fd/0x3c0 [ 5365.229826] sock_sendmsg+0x33/0x40 [ 5365.229827] __sys_sendto+0xee/0x160 [ 5365.229830] ? __se_sys_epoll_ctl+0x34d/0xe80 [ 5365.229831] ? do_epoll_wait+0xb0/0xd0 [ 5365.229832] __x64_sys_sendto+0x24/0x30 [ 5365.229835] do_syscall_64+0x5b/0x170 [ 5365.229836] entry_SYSCALL_64_after_hwframe+0x44/0xa9 Signed-off-by: Denis Kenzior --- net/mac80211/tx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5b93bde248fd..6a79d564de35 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4850,7 +4850,9 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, skb_reset_network_header(skb); skb_reset_mac_header(skb); + local_bh_disable(); __ieee80211_subif_start_xmit(skb, skb->dev, flags); + local_bh_enable(); return 0; } -- 2.13.5
Kernel Oops in ieee80211_subif_start_xmit
Hi Johannes, Some Arch Linux users are reporting a kernel oops when using iwd on 4.17 inside the control port bits. It seems to be pre-emption related since I've never seen this in all my testing. Any pointers as to what might be causing this? [ 5069.567760] Call Trace: [ 5069.567765] dump_stack+0x5c/0x80 [ 5069.567769] check_preemption_disabled.cold.0+0x46/0x51 [ 5069.567778] __ieee80211_subif_start_xmit+0x144/0x210 [mac80211] [ 5069.567786] ieee80211_tx_control_port+0x116/0x140 [mac80211] [ 5069.567806] nl80211_tx_control_port+0x13c/0x270 [cfg80211] [ 5069.567809] genl_family_rcv_msg+0x1c4/0x3a0 [ 5069.567811] genl_rcv_msg+0x47/0x90 [ 5069.567814] ? __kmalloc_node_track_caller+0x210/0x2b0 [ 5069.567815] ? genl_family_rcv_msg+0x3a0/0x3a0 [ 5069.567816] netlink_rcv_skb+0x4c/0x120 [ 5069.567818] genl_rcv+0x24/0x40 [ 5069.567819] netlink_unicast+0x196/0x240 [ 5069.567821] netlink_sendmsg+0x1fd/0x3c0 [ 5069.567823] sock_sendmsg+0x33/0x40 [ 5069.567825] __sys_sendto+0xee/0x160 [ 5069.567826] ? __sys_recvmsg+0x54/0xa0 [ 5069.567829] ? do_epoll_wait+0xb0/0xd0 [ 5069.567830] __x64_sys_sendto+0x24/0x30 [ 5069.567832] do_syscall_64+0x5b/0x170 [ 5069.567834] entry_SYSCALL_64_after_hwframe+0x44/0xa9
Re: [PATCH] cfg80211: Fix support for flushing old scan results
On 05/22/2018 04:28 PM, Johannes Berg wrote: On Tue, 2018-05-22 at 16:25 -0500, Denis Kenzior wrote: Hi Johannes, But in theory, I think you could've received the beacon with hidden SSID *before* the scan, yet it might be present in the scan results if the new scan caused the probe response to be associated with that scan. Right, your explanation was helpful, thanks. It still seems completely weird and redundant that we get two separate entries though. The second entry with the probe response data still carries the beacon info (as you point out). Should the pure-beacon one be filtered? I'm not sure. It still indicates that a hidden SSID was found, and in general even a real SSID on the same BSSID doesn't indicate that this was the only hidden SSID ... Right, but you still get that info conveyed through the Beacon IEs elements on the second/third/etc entry. So it still seems redundant to include the pure beacon one? Also, given that you have to ask for the SSID you want specifically, what practical purpose does it serve to know that this wasn't the only hidden SSID? I mean you can see that hidden SSIDs are out there, run an active scan for the ones you can use. If none are there, you can just ignore that bssid... Right, so thinking out loud here. Would it be useful to tell GET SCAN to only return entries with actual probe response data? Combined with the flush flag it seems like a much better fit for the cases you point out. I don't really see much point in doing filtering in the kernel. It wouldn't doesn't hurt, but just trades off more kernel code for less transferred data - and that's mostly in this particular corner case, so not really an efficiency problem? Fair enough. It was more motivated by 'make the API a bit more readable / accessible / user friendly'. And if it wasn't a hidden SSID, then you probably do want to know about the non-hidden SSIDs that you picked up along the way. In fact, this will become crucial with OCE, since that results in cases where you don't even send a probe request if you've picked up certain things during the scan passively. Right. In our case we only scan passively unless we detect a hidden ssid and have provisioned hidden ssids. Then we issue an active scan for just those... Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, But in theory, I think you could've received the beacon with hidden SSID *before* the scan, yet it might be present in the scan results if the new scan caused the probe response to be associated with that scan. Right, your explanation was helpful, thanks. It still seems completely weird and redundant that we get two separate entries though. The second entry with the probe response data still carries the beacon info (as you point out). Should the pure-beacon one be filtered? I’m just curious what other potential uses this flag might have. Well, basically, ensure that your scan data is up-to-date? I think mostly it's because there are scenarios where the AP is expected to vary the probe response data, so you need to know if you * have a new probe response, or * didn't receive a new probe response, or * the AP erroneously didn't change the new probe response. Right, so thinking out loud here. Would it be useful to tell GET SCAN to only return entries with actual probe response data? Combined with the flush flag it seems like a much better fit for the cases you point out. Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, > On May 22, 2018, at 3:52 PM, Johannes Berg <johan...@sipsolutions.net> wrote: > > On Tue, 2018-05-22 at 15:49 -0500, Denis Kenzior wrote: > >> Okay, so we need to use NL80211_BSS_PRESP_DATA if we want to filter out >> scan results that are coming from beacons, right? > > You could do that, yes. In non-hidden cases you get the beacon/probe > response data combined, in hidden cases you may get the beacon data > separately and the (second, third, ...) entry with probe response data > will come with beacon data too. > > I'm not really sure what value that would have though. In general, you > might want to not display hidden SSIDs as such or at all in the UI. Right. The intent here is to handle auto-connect to hidden networks. So if we have provisioned a network that is hidden, and we see hidden networks via beacons, we want to scan for our provisioned hidden SSIDs and only get the probe response results. > >> So what's the practical use of the flush flag? Or is that something >> that was meant to be 'for-testing-only'? > > I think you misunderstand? The value is that it ensures that nothing is > present in the list that was received *before* the scan. > We misunderstood how it was supposed to work, but no, I get how things work now. I’m just curious what other potential uses this flag might have. Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, On 05/22/2018 03:40 PM, Johannes Berg wrote: Hi, So I need to absorb all of this some more, but I'm still wondering why we are seeing two separate scan entries (with hidden & plain ssid) when we requested a flush? Is there a way to force the kernel to only show us the probe responses. Oh. I didn't even think about this part, but that's just a consequence of having a hidden SSID. We need one entry to track the beacon, and then we add another entry for each hidden SSID it may have. Some APs implement multiple SSIDs that way (old Cisco equipment, IIRC, though then with zero-length SSID instead of zero-bytes), so you can't lump them together into a single BSS entry. It would seem that even with the flush flag set, there could still be spurious beacons getting in causing these results to appear in the scan result set, right? In general anything can, there's no filtering. So you might do a flush scan for a specific SSID and still get 20 (different) results, if 20 beacons happened to be received while you were scanning. Okay, so we need to use NL80211_BSS_PRESP_DATA if we want to filter out scan results that are coming from beacons, right? So what's the practical use of the flush flag? Or is that something that was meant to be 'for-testing-only'? Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, I think I finally figured out what's going on. It's a mix between strange 'iw' behaviour, and strange backward-compatibility behaviour in cfg80211. If you do this again and give the scan dump command explicitly with -b added, like sudo iw dev wlp2s0 scan passive iw dev wlp2s0 scan dump -b then you'll likely see BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 274.815s [boottime] freq: 5765 beacon interval: 100 TUs signal: -35.00 dBm last seen: 349 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 [... ht/vht ...] Information elements from Beacon frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 [... ht/vht ...] So there are two things going on: 1) In iw, we limit the amount of information printed, but in that case still print "Information elements from Probe Response frame", if beacon IEs are also present in the BSS information. 2) Originally, the kernel didn't distinguish between probe response and beacon IE attributes, but only had "IEs" in general. When we later did want to distinguish, we changed nl80211 to unconditionally put some IEs into the "IEs", if received from beacon put them into "beacon IEs", but to avoid further duplication didn't introduce a separate "probe response IEs" attribute. You can see this in nl80211_send_bss(): /* this pointer prefers to be pointed to probe response data * but is always valid */ ies = rcu_dereference(res->ies); if (ies) { if (nla_put_u64_64bit(msg, NL80211_BSS_TSF, ies->tsf, NL80211_BSS_PAD)) goto fail_unlock_rcu; if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS, ies->len, ies->data)) goto fail_unlock_rcu; } /* and this pointer is always (unless driver didn't know) beacon data */ ies = rcu_dereference(res->beacon_ies); if (ies && ies->from_beacon) { if (nla_put_u64_64bit(msg, NL80211_BSS_BEACON_TSF, ies->tsf, NL80211_BSS_PAD)) goto fail_unlock_rcu; if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES, ies->len, ies->data)) goto fail_unlock_rcu; } Ultimately, this is also lossy - so later I added NL80211_BSS_PRESP_DATA that indicates "these were *really* received by probe response. I guess I should change iw in the following way: https://p.sipsolutions.net/6958d16d00f955c7.txt which will mean it will not print "probe response IEs" in a false positive way. Obviously on kernels that don't set NL80211_BSS_PRESP_DATA it won't print it out even if the beacon/probe response were both received with different content, but it can't know if the kernel doesn't tell it. So I need to absorb all of this some more, but I'm still wondering why we are seeing two separate scan entries (with hidden & plain ssid) when we requested a flush? Is there a way to force the kernel to only show us the probe responses. It would seem that even with the flush flag set, there could still be spurious beacons getting in causing these results to appear in the scan result set, right? Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, On 05/22/2018 09:51 AM, Johannes Berg wrote: On Tue, 2018-05-22 at 16:50 +0200, Johannes Berg wrote: On Tue, 2018-05-22 at 09:48 -0500, Denis Kenzior wrote: Hi Arend, Are you saying the first result is from the Beacon and the other is from the Probe Response? Then why are the 'Information elements from Probe Response frame' the way they are? Nope. I am not saying that. I am saying that there are two probe requests being sent. One with broadcast ssid, ie. ssid_len == 0, and with ssid 'myssid'. But it is speculation without a sniffer capture. Ah I see what you mean now. No, we traced this down to hostapd itself and it was receiving a single Probe Request with the ssid set and replying to it per spec. So I'm pretty confident this scenario isn't what is happening. Let me try to get some actual packet captures... Was "myssid" the real SSID, or did you hide that from us and it was really 9 characters long in the original? See the other sub-thread. It was 9 characters long, I hand-edited it to protect the innocent. If it was really 9 characters long I could imagine that there's a different bug with a beacon with all-zero-bytes having been received (and getting stuck into the probe response buffer for some reason), and then you *should* see both entries. Or perhaps there's a bug with how we link the results between hidden/non-hidden, but it seems to me that hostapd would never have responded with a probe response with zeroed bytes. We suspect it is likely a bug in cfg80211_bss_update logic somewhere. Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, On 05/22/2018 03:12 AM, Johannes Berg wrote: Hi Denis, Just FYI, there's definitely something funny with the scanning code: denkenz@iwd-test ~ $ sudo iw dev wlp2s0 scan flush BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 274.815s [boottime] freq: 5765 beacon interval: 100 TUs signal: -35.00 dBm last seen: 349 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 This is already rather strange to start with. Can you provide a sniffer capture of this situation? Will do Thing is - the all-zero-bytes there points to using hidden SSID with a length of 9 characters, BUT * "myssid" is just 6 characters long - or did you edit that? Good eyes! Yes this was edited to protect the innocent neighbors ;) * normally the zeroed-out SSID isn't transmitted in a *probe response* but only in beacons Exactly. That's what makes this really weird. Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Arend, Are you saying the first result is from the Beacon and the other is from the Probe Response? Then why are the 'Information elements from Probe Response frame' the way they are? Nope. I am not saying that. I am saying that there are two probe requests being sent. One with broadcast ssid, ie. ssid_len == 0, and with ssid 'myssid'. But it is speculation without a sniffer capture. Ah I see what you mean now. No, we traced this down to hostapd itself and it was receiving a single Probe Request with the ssid set and replying to it per spec. So I'm pretty confident this scenario isn't what is happening. Let me try to get some actual packet captures... Regards -Denis
Re: [PATCH] nl80211: Reject disconnect commands except from conn_owner
Hi Arend, On 05/22/2018 05:39 AM, Arend van Spriel wrote: On 5/8/2018 5:05 PM, Denis Kenzior wrote: Hi Arend, Sure. I guess we all have been there kicking of wpa_s and discovering there is already one running in the background. I am just a bit squeamish to change the behavior like this. H. Is wpa_s already using SOCKET_OWNER. If so, I might create a patch to opt-out for that so people can knowingly choose chaos ;-) wpa_s is using SOCKET_OWNER these days. However, with the introduction of Control Port over NL80211, just getting rid of SOCKET_OWNER might not be that easy. I have a regression test script employing py80211 which listens for connect event. Right now I am using an older wpa_s, but the above will screw it up. So it is still early in the morning for me and you might have to talk slower. But let me take a stab anyway :) What will screw up? The connect event is always multicast, so you should still receive it regardless of SOCKET_OWNER / Control Port over NL80211. If I recall correctly the mlme notification needed to be unicast, because multicast was not 100% reliable, right? Would it be acceptable to send unicast to the socket owner and still do the multicast or are we already doing that? If not, that would fix my imminent issue. Control Port events are only unicast to the application that is the SOCKET_OWNER. E.g. either wpa_s or iwd. They are never multicast as nobody else could make sense of them anyway due to lack of passphrase / nonces. The other 'regular' events like Disconnect, Connect, etc are still multicast. What this patch does is prevents some app from rudely coming in and sending a Disconnect on an interface which is being managed by another process, e.g. iwd or wpa_s, that has set the SOCKET_OWNER flag. Regards, -Denis
[PATCH] nl80211: Fix compilation
Commit 7ea3e110f2f8ba23f330c2f702f556acd539bcb8 seems to have introduced: net/wireless/nl80211.c: In function ‘nl80211_get_station’: net/wireless/nl80211.c:4802:34: error: incompatible type for argument 1 of ‘cfg80211_sinfo_release_content’ cfg80211_sinfo_release_content(sinfo); ^ In file included from net/wireless/nl80211.c:24:0: ./include/net/cfg80211.h:5721:20: note: expected ‘struct station_info *’ but argument is of type ‘struct station_info’ static inline void cfg80211_sinfo_release_content(struct station_info *sinfo) ^~ Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fd2b1646e81a..376cb66d164c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4799,7 +4799,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { - cfg80211_sinfo_release_content(sinfo); + cfg80211_sinfo_release_content(); return -ENOMEM; } -- 2.13.5
[PATCH] nl80211: Optimize cfg80211_bss_expire invocations
Only invoke cfg80211_bss_expire on the first nl80211_dump_scan invocation to avoid (likely) redundant processing. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/nl80211.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ff28f8feeb09..7458cbcf00b2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7930,7 +7930,15 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) wdev_lock(wdev); spin_lock_bh(>bss_lock); - cfg80211_bss_expire(rdev); + + /* +* dump_scan will be called multiple times to break up the scan results +* into multiple messages. It is unlikely that any more bss-es will be +* expired after the first call, so only call only call this on the +* first dump_scan invocation. +*/ + if (start == 0) + cfg80211_bss_expire(rdev); cb->seq = rdev->bss_generation; -- 2.13.5
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Arend, On 05/18/2018 01:54 PM, Arend van Spriel wrote: On 5/18/2018 6:47 PM, Denis Kenzior wrote: Hi Johannes, On 05/18/2018 03:13 AM, Johannes Berg wrote: On Fri, 2018-05-11 at 09:48 -0700, Tim Kourt wrote: __cfg80211_bss_expire function was incorrectly used to flush the BSS entries from the previous scan results, causing NL80211_SCAN_FLAG_FLUSH flag to have no effect. Hmm. I guess I'm not convinced - what's the bug? We flush anything that's older than our start, so that should work just fine? Just FYI, there's definitely something funny with the scanning code: denkenz@iwd-test ~ $ sudo iw dev wlp2s0 scan flush BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 274.815s [boottime] freq: 5765 beacon interval: 100 TUs signal: -35.00 dBm last seen: 349 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 Then if I try: denkenz@iwd-test ~ $ sudo iw dev wlp2s0 scan flush ssid myssid BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 319.667s [boottime] freq: 5765 beacon interval: 100 TUs signal: -42.00 dBm last seen: 350 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 319.662s [boottime] freq: 5765 beacon interval: 100 TUs signal: -37.00 dBm last seen: 355 ms ago Information elements from Probe Response frame: SSID: myssid Shouldn't the second scan give a single result from that one BSS? Looking at the 'last seen' values it does look ok. Both results have the same BSSID, but the first one shows the broadcast ssid (or so it seems). Are you saying the first result is from the Beacon and the other is from the Probe Response? Then why are the 'Information elements from Probe Response frame' the way they are? Neither iw nor nl80211 on the kernel side add the broadcast ssid. So question is what device are you using and does it use mac80211 software Intel 7260. We're seeing the same results with hwsim as well though. This was just a quick test to illustrate. scanning or hardware scanning. I did not dive into mac80211 to see if the broadcast ssid is added there. By the way, if you're interested. The same tests with a Broadcom based device wouldn't even find the hidden network. It would always come back with a single 'x00' SSID regardless of whether I added 'ssid myssid' at the end. Regards, -Denis
Re: [PATCH] cfg80211: Fix support for flushing old scan results
Hi Johannes, On 05/18/2018 03:13 AM, Johannes Berg wrote: On Fri, 2018-05-11 at 09:48 -0700, Tim Kourt wrote: __cfg80211_bss_expire function was incorrectly used to flush the BSS entries from the previous scan results, causing NL80211_SCAN_FLAG_FLUSH flag to have no effect. Hmm. I guess I'm not convinced - what's the bug? We flush anything that's older than our start, so that should work just fine? Just FYI, there's definitely something funny with the scanning code: denkenz@iwd-test ~ $ sudo iw dev wlp2s0 scan flush BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 274.815s [boottime] freq: 5765 beacon interval: 100 TUs signal: -35.00 dBm last seen: 349 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 Then if I try: denkenz@iwd-test ~ $ sudo iw dev wlp2s0 scan flush ssid myssid BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 319.667s [boottime] freq: 5765 beacon interval: 100 TUs signal: -42.00 dBm last seen: 350 ms ago Information elements from Probe Response frame: SSID: \x00\x00\x00\x00\x00\x00\x00\x00\x00 BSS 10:c3:7b:54:74:d4(on wlp2s0) last seen: 319.662s [boottime] freq: 5765 beacon interval: 100 TUs signal: -37.00 dBm last seen: 355 ms ago Information elements from Probe Response frame: SSID: myssid Shouldn't the second scan give a single result from that one BSS? Regards, -Denis
Re: [PATCH v7 00/11] EAPoL over NL80211
Hi Arend, On 03/27/2018 03:03 AM, Arend van Spriel wrote: On 3/26/2018 7:52 PM, Denis Kenzior wrote: The proposed patchset has been tested in a mac80211_hwsim based environment with hostapd and iwd. Hi Denis, Looking pretty good. Do you also have hostapd and iwd patches available somewhere. I would like to see if I can get brcmfmac using it. There are some very raw iwd patches I have. They're sitting in my private tree. I can send these to you privately or maybe setup a wiki page somewhere for you to grab them. They do not take the NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211 feature bit into account, so I still need to work on these. Was holding off until Johannes merges at least the high level API bits. I never modified hostapd. iwd has a very rudimentary AP mode support. Not fully useable but enough to run a 4-way handshake. So with that in mind I concentrated on two scenarios while testing: 1. modified iwd (STA) utiling EAPoL over NL80211 connecting to stock hostapd. In effect this was testing both the legacy and the new behavior. 2. modified iwd (STA) utilizing EAPoL over NL80211 connecting to stock hostapd. Then disconnecting and connecting to modified iwd (AP). iwd doesn't (yet) have support for P2P, IBSS or Mesh. So the bits touching these features should be considered untested. Regards, -Denis
[PATCH v7 05/11] nl80211: Add SOCKET_OWNER support to JOIN_IBSS
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ibss.c | 1 + net/wireless/nl80211.c | 6 ++ 3 files changed, 9 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1cdac3d732c1..877fab2836ec 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1985,6 +1985,8 @@ enum nl80211_commands { * multicast group. * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the * station will deauthenticate when the socket is closed. + * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically + * torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a1d10993d08a..d5d26fc5b853 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -224,6 +224,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (err) return err; + wdev->conn_owner_nlportid = 0; __cfg80211_clear_ibss(dev, nowext); return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 234f6a41aa03..2f630ee3240b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8704,6 +8704,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_join_ibss(rdev, dev, , connkeys); if (err) kzfree(connkeys); + else if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + return err; } -- 2.13.5
[PATCH v7 03/11] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 14 +- net/wireless/nl80211.c | 26 ++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 76b6783f35f6..2e7f30c66913 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 77675ae3e475..1cdac3d732c1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1488,6 +1489,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2641,6 +2651,8 @@ enum nl80211_attrs { NL80211_ATTR_NSS, NL80211_ATTR_ACK_SIGNAL, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aadc1f090b65..234f6a41aa03 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -287,6 +287,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -8204,6 +8205,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return err; } +static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev, +struct genl_info *info) +{ + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set"); + return -EINVAL; + } + + if (!rdev->ops->tx_control_port || + !wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + return 0; +} + static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_crypto_settings *settings, @@ -8227,6 +8244,15 @@ static int nl
[PATCH v7 10/11] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/tx.c | 46 ++ 3 files changed, 50 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fd68f6fb02d7..9294acb495ee 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3786,4 +3786,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae9c33cd8ada..a52bd2a61a27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1734,6 +1734,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7643178ef132..6ae8fe121500 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4749,3 +4749,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(ETH_P_PREAUTH)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[PATCH v7 08/11] nl80211: Add control_port_over_nl80211 for ibss
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 9 + 2 files changed, 12 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2e7f30c66913..2a28f446648e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2033,6 +2033,8 @@ struct cfg80211_disassoc_request { * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is * required to assume that the port is unauthorized until authorized by * user space. Otherwise, port is marked authorized by default. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @userspace_handles_dfs: whether user space controls DFS operation, i.e. * changes the channel when a radar is detected. This is required * to operate on DFS channels. @@ -2056,6 +2058,7 @@ struct cfg80211_ibss_params { bool channel_fixed; bool privacy; bool control_port; + bool control_port_over_nl80211; bool userspace_handles_dfs; int mcast_rate[NUM_NL80211_BANDS]; struct ieee80211_ht_cap ht_capa; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 34e8435f0c43..774f5d6ba8e4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8702,6 +8702,15 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.control_port = nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + int r = validate_pae_over_nl80211(rdev, info); + + if (r < 0) + return r; + + ibss.control_port_over_nl80211 = true; + } + ibss.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); -- 2.13.5
[PATCH v7 02/11] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. A new EXT_FEATURE flag is introduced so that nl80211 code can check whether a given wiphy has capability to pass EAPoL frames over NL80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 ++ include/uapi/linux/nl80211.h | 3 ++ net/wireless/nl80211.c | 71 +++- net/wireless/rdev-ops.h | 15 ++ net/wireless/trace.h | 26 5 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6dee630ee66d..76b6783f35f6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2960,6 +2960,9 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3255,6 +3258,12 @@ struct cfg80211_ops { const u8 *aa); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const __be16 proto, + const bool noencrypt); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1334f810f7b4..77675ae3e475 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5012,6 +5012,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5042,6 +5044,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_LOW_SPAN_SCAN, NL80211_EXT_FEATURE_LOW_POWER_SCAN, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d7dcc2d05025..aadc1f090b65 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12517,6 +12517,68 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ); } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { + GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing"); + return -EINVAL; + } + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_d
[PATCH v7 04/11] cfg80211: Support all iftypes in autodisconnect_wk
Currently autodisconnect_wk assumes that only interface types of P2P_CLIENT and STATION use conn_owner_nlportid. Change this so all interface types are supported. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/sme.c | 43 --- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 701cfd7acc1b..5df6b33db786 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1239,17 +1239,38 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) wdev_lock(wdev); if (wdev->conn_owner_nlportid) { - /* -* Use disconnect_bssid if still connecting and ops->disconnect -* not implemented. Otherwise we can use cfg80211_disconnect. -*/ - if (rdev->ops->disconnect || wdev->current_bss) - cfg80211_disconnect(rdev, wdev->netdev, - WLAN_REASON_DEAUTH_LEAVING, true); - else - cfg80211_mlme_deauth(rdev, wdev->netdev, -wdev->disconnect_bssid, NULL, 0, -WLAN_REASON_DEAUTH_LEAVING, false); + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + cfg80211_stop_ap(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_MESH_POINT: + cfg80211_leave_mesh(rdev, wdev->netdev); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + /* +* Use disconnect_bssid if still connecting and +* ops->disconnect not implemented. Otherwise we can +* use cfg80211_disconnect. +*/ + if (rdev->ops->disconnect || wdev->current_bss) + cfg80211_disconnect(rdev, wdev->netdev, + WLAN_REASON_DEAUTH_LEAVING, + true); + else + cfg80211_mlme_deauth(rdev, wdev->netdev, +wdev->disconnect_bssid, +NULL, 0, +WLAN_REASON_DEAUTH_LEAVING, +false); + break; + default: + break; + } } wdev_unlock(wdev); -- 2.13.5
[PATCH v7 00/11] EAPoL over NL80211
T_OVER_NL80211 flag. This is a capability flag used by the drivers, e.g. that the driver supports control port over nl80211 capability. This capability is now checked when CONTROL_PORT_OVER_NL80211 is requested. - mac80211 rx path now forwards Pre-Authentication frames over NL80211 as well, if requested. Tweaked the signature of cfg80211_rx_control_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (11): nl80211: Add CMD_CONTROL_PORT_FRAME API nl80211: Implement TX of control port frames nl80211: Add CONTROL_PORT_OVER_NL80211 attribute cfg80211: Support all iftypes in autodisconnect_wk nl80211: Add SOCKET_OWNER support to JOIN_IBSS nl80211: Add SOCKET_OWNER support to JOIN_MESH nl80211: Add SOCKET_OWNER support to START_AP nl80211: Add control_port_over_nl80211 for ibss nl80211: Add control_port_over_nl80211 to mesh_setup mac80211: Add support for tx_control_port mac80211: Send control port frames over nl80211 include/net/cfg80211.h | 40 + include/uapi/linux/nl80211.h | 36 +++- net/mac80211/cfg.c | 7 ++ net/mac80211/ibss.c | 1 + net/mac80211/ieee80211_i.h | 4 + net/mac80211/iface.c | 2 + net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c| 33 ++-- net/mac80211/tx.c| 46 +++ net/wireless/ap.c| 1 + net/wireless/ibss.c | 1 + net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 193 ++- net/wireless/rdev-ops.h | 15 net/wireless/sme.c | 43 +++--- net/wireless/trace.h | 47 +++ 17 files changed, 455 insertions(+), 19 deletions(-) -- 2.13.5
[PATCH v7 01/11] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT, NL80211_CMD_ASSOCIATE or NL80211_CMD_START_AP Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 22 + include/uapi/linux/nl80211.h | 13 ++ net/wireless/nl80211.c | 58 net/wireless/trace.h | 21 4 files changed, 114 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fc40843baed3..6dee630ee66d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5694,6 +5694,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - notification about a received control port frame + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * This function is used to inform userspace about a received control port + * frame. It should only be used if userspace indicated it wants to receive + * control port frames over NL80211. + * + * The frame is the data portion of the 802.3 or 802.11 data frame with all + * network layer headers removed (e.g. the raw EAPoL frame). + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c13c84304be3..1334f810f7b4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -990,6 +990,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host @@ -1228,6 +1239,8 @@ enum nl80211_commands { NL80211_CMD_STA_OPMODE_CHANGED, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a910150f8169..d7dcc2d05025 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14535,6 +14535,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_rx_control_port(struct net_device *dev, +const u8 *buf, size_t len, +const u8 *addr, u16 proto, +bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), + NL80211_ATTR_PAD) || + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + nla_put(
[PATCH v7 06/11] nl80211: Add SOCKET_OWNER support to JOIN_MESH
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 10 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 877fab2836ec..e3329bc4644b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1987,6 +1987,8 @@ enum nl80211_commands { * station will deauthenticate when the socket is closed. * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically * torn down when the socket is closed. + * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be + * automatically torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index b12da6ef3c12..e91a5078615b 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -286,6 +286,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, err = rdev_leave_mesh(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->mesh_id_len = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2f630ee3240b..05b903958894 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10153,7 +10153,15 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) setup.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); - return cfg80211_join_mesh(rdev, dev, , ); + err = cfg80211_join_mesh(rdev, dev, , ); + + if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + + return err; } static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) -- 2.13.5
[PATCH v7 07/11] nl80211: Add SOCKET_OWNER support to START_AP
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ap.c| 1 + net/wireless/nl80211.c | 4 3 files changed, 7 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e3329bc4644b..9b4fd4bca141 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1989,6 +1989,8 @@ enum nl80211_commands { * torn down when the socket is closed. * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be * automatically torn down when the socket is closed. + * If set during %NL80211_CMD_START_AP the AP will be automatically + * disabled when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 63682176c96c..882d97bdc6bf 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -27,6 +27,7 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, err = rdev_stop_ap(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); wdev->ssid_len = 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 05b903958894..34e8435f0c43 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4135,6 +4135,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) wdev->chandef = params.chandef; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); + + if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) + wdev->conn_owner_nlportid = info->snd_portid; + } wdev_unlock(wdev); -- 2.13.5
[PATCH v7 09/11] nl80211: Add control_port_over_nl80211 to mesh_setup
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 9 + 2 files changed, 12 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2a28f446648e..bdb1a3c2661e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1453,6 +1453,8 @@ struct mesh_config { * @userspace_handles_dfs: whether user space controls DFS operation, i.e. * changes the channel when a radar is detected. This is required * to operate on DFS channels. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * * These parameters are fixed when the mesh is created. */ @@ -1475,6 +1477,7 @@ struct mesh_setup { u32 basic_rates; struct cfg80211_bitrate_mask beacon_rate; bool userspace_handles_dfs; + bool control_port_over_nl80211; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 774f5d6ba8e4..3947ec7bc3a0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10166,6 +10166,15 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) setup.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + int r = validate_pae_over_nl80211(rdev, info); + + if (r < 0) + return r; + + setup.control_port_over_nl80211 = true; + } + err = cfg80211_join_mesh(rdev, dev, , ); if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { -- 2.13.5
[PATCH v7 11/11] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 6 ++ net/mac80211/ibss.c| 1 + net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 2 ++ net/mac80211/main.c| 2 ++ net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 33 - 7 files changed, 42 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9294acb495ee..49112378e503 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +936,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, @@ -2019,6 +2023,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, if (err) return err; + sdata->control_port_over_nl80211 = setup.control_port_over_nl80211; + /* can mesh use other SMPS modes? */ sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = sdata->local->rx_chains; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index db07e0de9a03..05ddc9291ec5 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1844,6 +1844,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = local->rx_chains; + sdata->control_port_over_nl80211 = params->control_port_over_nl80211; ieee80211_queue_work(>hw, >work); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a52bd2a61a27..00dbc6a1b79d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d13ba064951f..555e389b7dfa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -519,6 +519,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) master->control_port_protocol; sdata->control_port_no_encrypt = master->control_port_no_encrypt; + sdata->control_port_over_nl80211 = + master->control_port_over_nl80211; sdata->vif.cab_queue = master->vif.cab_queue; memcpy(sdata->vif.hw_queue, master->vif.hw_queue, sizeof(sdata->vif.hw_queue)); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..e5a51267c75d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0024eff9bb84..b3665b857883 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4844,6 +4844,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.cont
[RFC v6 06/11] nl80211: Add SOCKET_OWNER support to JOIN_MESH
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 10 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 877fab2836ec..e3329bc4644b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1987,6 +1987,8 @@ enum nl80211_commands { * station will deauthenticate when the socket is closed. * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically * torn down when the socket is closed. + * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be + * automatically torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index b12da6ef3c12..e91a5078615b 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -286,6 +286,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, err = rdev_leave_mesh(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->mesh_id_len = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2f630ee3240b..05b903958894 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10153,7 +10153,15 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) setup.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); - return cfg80211_join_mesh(rdev, dev, , ); + err = cfg80211_join_mesh(rdev, dev, , ); + + if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + + return err; } static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) -- 2.13.5
[RFC v6 00/11] EAPoL over NL80211
lity flag used by the drivers, e.g. that the driver supports control port over nl80211 capability. This capability is now checked when CONTROL_PORT_OVER_NL80211 is requested. - mac80211 rx path now forwards Pre-Authentication frames over NL80211 as well, if requested. Tweaked the signature of cfg80211_rx_control_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (11): nl80211: Add CMD_CONTROL_PORT_FRAME API nl80211: Implement TX of control port frames nl80211: Add CONTROL_PORT_OVER_NL80211 attribute cfg80211: Support all iftypes in autodisconnect_wk nl80211: Add SOCKET_OWNER support to JOIN_IBSS nl80211: Add SOCKET_OWNER support to JOIN_MESH nl80211: Add SOCKET_OWNER support to START_AP nl80211: Add control_port_over_nl80211 for ibss nl80211: Add control_port_over_nl80211 to mesh_setup mac80211: Add support for tx_control_port mac80211: Send control port frames over nl80211 include/net/cfg80211.h | 40 + include/uapi/linux/nl80211.h | 36 +++- net/mac80211/cfg.c | 7 ++ net/mac80211/ibss.c | 1 + net/mac80211/ieee80211_i.h | 4 + net/mac80211/iface.c | 2 + net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c| 33 ++-- net/mac80211/tx.c| 46 +++ net/wireless/ap.c| 1 + net/wireless/ibss.c | 1 + net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 193 ++- net/wireless/rdev-ops.h | 15 net/wireless/sme.c | 43 +++--- net/wireless/trace.h | 47 +++ 17 files changed, 455 insertions(+), 19 deletions(-) -- 2.13.5
[RFC v6 02/11] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. A new EXT_FEATURE flag is introduced so that nl80211 code can check whether a given wiphy has capability to pass EAPoL frames over NL80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 ++ include/uapi/linux/nl80211.h | 3 ++ net/wireless/nl80211.c | 71 +++- net/wireless/rdev-ops.h | 15 ++ net/wireless/trace.h | 26 5 files changed, 123 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6dee630ee66d..76b6783f35f6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2960,6 +2960,9 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3255,6 +3258,12 @@ struct cfg80211_ops { const u8 *aa); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const __be16 proto, + const bool noencrypt); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1334f810f7b4..77675ae3e475 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5012,6 +5012,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5042,6 +5044,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_LOW_SPAN_SCAN, NL80211_EXT_FEATURE_LOW_POWER_SCAN, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d7dcc2d05025..aadc1f090b65 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12517,6 +12517,68 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ); } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) { + GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing"); + return -EINVAL; + } + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_d
[RFC v6 11/11] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 6 ++ net/mac80211/ibss.c| 1 + net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 2 ++ net/mac80211/main.c| 2 ++ net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 33 - 7 files changed, 42 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9294acb495ee..49112378e503 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +936,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, @@ -2019,6 +2023,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, if (err) return err; + sdata->control_port_over_nl80211 = setup.control_port_over_nl80211; + /* can mesh use other SMPS modes? */ sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = sdata->local->rx_chains; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index db07e0de9a03..05ddc9291ec5 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1844,6 +1844,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->smps_mode = IEEE80211_SMPS_OFF; sdata->needed_rx_chains = local->rx_chains; + sdata->control_port_over_nl80211 = params->control_port_over_nl80211; ieee80211_queue_work(>hw, >work); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a52bd2a61a27..00dbc6a1b79d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d13ba064951f..555e389b7dfa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -519,6 +519,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) master->control_port_protocol; sdata->control_port_no_encrypt = master->control_port_no_encrypt; + sdata->control_port_over_nl80211 = + master->control_port_over_nl80211; sdata->vif.cab_queue = master->vif.cab_queue; memcpy(sdata->vif.hw_queue, master->vif.hw_queue, sizeof(sdata->vif.hw_queue)); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..e5a51267c75d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0024eff9bb84..b3665b857883 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4844,6 +4844,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.cont
[RFC v6 09/11] nl80211: Add control_port_over_nl80211 to mesh_setup
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 9 + 2 files changed, 12 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2a28f446648e..bdb1a3c2661e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1453,6 +1453,8 @@ struct mesh_config { * @userspace_handles_dfs: whether user space controls DFS operation, i.e. * changes the channel when a radar is detected. This is required * to operate on DFS channels. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * * These parameters are fixed when the mesh is created. */ @@ -1475,6 +1477,7 @@ struct mesh_setup { u32 basic_rates; struct cfg80211_bitrate_mask beacon_rate; bool userspace_handles_dfs; + bool control_port_over_nl80211; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 774f5d6ba8e4..3947ec7bc3a0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10166,6 +10166,15 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) setup.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + int r = validate_pae_over_nl80211(rdev, info); + + if (r < 0) + return r; + + setup.control_port_over_nl80211 = true; + } + err = cfg80211_join_mesh(rdev, dev, , ); if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { -- 2.13.5
[RFC v6 03/11] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 14 +- net/wireless/nl80211.c | 26 ++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 76b6783f35f6..2e7f30c66913 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 77675ae3e475..1cdac3d732c1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1488,6 +1489,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2641,6 +2651,8 @@ enum nl80211_attrs { NL80211_ATTR_NSS, NL80211_ATTR_ACK_SIGNAL, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aadc1f090b65..234f6a41aa03 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -287,6 +287,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -8204,6 +8205,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) return err; } +static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev, +struct genl_info *info) +{ + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set"); + return -EINVAL; + } + + if (!rdev->ops->tx_control_port || + !wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + return 0; +} + static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct genl_info *info, struct cfg80211_crypto_settings *settings, @@ -8227,6 +8244,15 @@ static int nl
[RFC v6 10/11] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/tx.c | 46 ++ 3 files changed, 50 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fd68f6fb02d7..9294acb495ee 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3786,4 +3786,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae9c33cd8ada..a52bd2a61a27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1734,6 +1734,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7643178ef132..6ae8fe121500 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4749,3 +4749,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(ETH_P_PREAUTH)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[RFC v6 08/11] nl80211: Add control_port_over_nl80211 for ibss
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ net/wireless/nl80211.c | 9 + 2 files changed, 12 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2e7f30c66913..2a28f446648e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2033,6 +2033,8 @@ struct cfg80211_disassoc_request { * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is * required to assume that the port is unauthorized until authorized by * user space. Otherwise, port is marked authorized by default. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @userspace_handles_dfs: whether user space controls DFS operation, i.e. * changes the channel when a radar is detected. This is required * to operate on DFS channels. @@ -2056,6 +2058,7 @@ struct cfg80211_ibss_params { bool channel_fixed; bool privacy; bool control_port; + bool control_port_over_nl80211; bool userspace_handles_dfs; int mcast_rate[NUM_NL80211_BANDS]; struct ieee80211_ht_cap ht_capa; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 34e8435f0c43..774f5d6ba8e4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8702,6 +8702,15 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.control_port = nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + int r = validate_pae_over_nl80211(rdev, info); + + if (r < 0) + return r; + + ibss.control_port_over_nl80211 = true; + } + ibss.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); -- 2.13.5
[RFC v6 07/11] nl80211: Add SOCKET_OWNER support to START_AP
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ap.c| 1 + net/wireless/nl80211.c | 4 3 files changed, 7 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e3329bc4644b..9b4fd4bca141 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1989,6 +1989,8 @@ enum nl80211_commands { * torn down when the socket is closed. * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be * automatically torn down when the socket is closed. + * If set during %NL80211_CMD_START_AP the AP will be automatically + * disabled when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 63682176c96c..882d97bdc6bf 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -27,6 +27,7 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, err = rdev_stop_ap(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); wdev->ssid_len = 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 05b903958894..34e8435f0c43 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4135,6 +4135,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) wdev->chandef = params.chandef; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); + + if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) + wdev->conn_owner_nlportid = info->snd_portid; + } wdev_unlock(wdev); -- 2.13.5
[RFC v6 04/11] cfg80211: Support all iftypes in autodisconnect_wk
Currently autodisconnect_wk assumes that only interface types of P2P_CLIENT and STATION use conn_owner_nlportid. Change this so all interface types are supported. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/sme.c | 43 --- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 701cfd7acc1b..5df6b33db786 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1239,17 +1239,38 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) wdev_lock(wdev); if (wdev->conn_owner_nlportid) { - /* -* Use disconnect_bssid if still connecting and ops->disconnect -* not implemented. Otherwise we can use cfg80211_disconnect. -*/ - if (rdev->ops->disconnect || wdev->current_bss) - cfg80211_disconnect(rdev, wdev->netdev, - WLAN_REASON_DEAUTH_LEAVING, true); - else - cfg80211_mlme_deauth(rdev, wdev->netdev, -wdev->disconnect_bssid, NULL, 0, -WLAN_REASON_DEAUTH_LEAVING, false); + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + cfg80211_stop_ap(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_MESH_POINT: + cfg80211_leave_mesh(rdev, wdev->netdev); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + /* +* Use disconnect_bssid if still connecting and +* ops->disconnect not implemented. Otherwise we can +* use cfg80211_disconnect. +*/ + if (rdev->ops->disconnect || wdev->current_bss) + cfg80211_disconnect(rdev, wdev->netdev, + WLAN_REASON_DEAUTH_LEAVING, + true); + else + cfg80211_mlme_deauth(rdev, wdev->netdev, +wdev->disconnect_bssid, +NULL, 0, +WLAN_REASON_DEAUTH_LEAVING, +false); + break; + default: + break; + } } wdev_unlock(wdev); -- 2.13.5
[RFC v6 05/11] nl80211: Add SOCKET_OWNER support to JOIN_IBSS
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ibss.c | 1 + net/wireless/nl80211.c | 6 ++ 3 files changed, 9 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1cdac3d732c1..877fab2836ec 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1985,6 +1985,8 @@ enum nl80211_commands { * multicast group. * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the * station will deauthenticate when the socket is closed. + * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically + * torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a1d10993d08a..d5d26fc5b853 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -224,6 +224,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (err) return err; + wdev->conn_owner_nlportid = 0; __cfg80211_clear_ibss(dev, nowext); return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 234f6a41aa03..2f630ee3240b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8704,6 +8704,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_join_ibss(rdev, dev, , connkeys); if (err) kzfree(connkeys); + else if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + return err; } -- 2.13.5
[RFC v6 01/11] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT, NL80211_CMD_ASSOCIATE or NL80211_CMD_START_AP Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 22 + include/uapi/linux/nl80211.h | 13 ++ net/wireless/nl80211.c | 58 net/wireless/trace.h | 21 4 files changed, 114 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fc40843baed3..6dee630ee66d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5694,6 +5694,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - notification about a received control port frame + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * This function is used to inform userspace about a received control port + * frame. It should only be used if userspace indicated it wants to receive + * control port frames over NL80211. + * + * The frame is the data portion of the 802.3 or 802.11 data frame with all + * network layer headers removed (e.g. the raw EAPoL frame). + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c13c84304be3..1334f810f7b4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -990,6 +990,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host @@ -1228,6 +1239,8 @@ enum nl80211_commands { NL80211_CMD_STA_OPMODE_CHANGED, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a910150f8169..d7dcc2d05025 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14535,6 +14535,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_rx_control_port(struct net_device *dev, +const u8 *buf, size_t len, +const u8 *addr, u16 proto, +bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), + NL80211_ATTR_PAD) || + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + nla_put(
Re: [RFC v5 0/9] EAPoL over NL80211
Hi Johannes, However, it doesn't actually matter at all - we shouldn't get there with VLAN interface. EAPOL frames are always sent out to the corresponding AP interface, see ieee80211_rx_h_data: if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && unlikely(port_control) && sdata->bss) { sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); dev = sdata->dev; rx->sdata = sdata; } Okay, that makes things easier. However, it does bring up a question. Should we be symmetric and remove AP_VLAN as a valid target of control port frames? E.g. drop NL80211_IFTYPE_AP_VLAN case in patch 2 of the series. In effect we'd require all control port frame traffic to go over the master interface. - JOIN_IBSS & JOIN_MESH don't seem to support control_port_ethertype or control_port_no_encrypt. Should struct cfg80211_crypto_settings parsed inside nl80211_crypto_settings be added to ibss_params or mesh_config/mesh_setup? I don't think it matters - they just don't support this now and don't really need to. Except that the eapol over nl80211 flag is being sent in security settings. This covers STA/AP/P2P_GO/P2P_CLIENT. We need some way of passing this information for mesh & ibss. Not sure I understand what you're saying. Can't we just say the flag isn't permitted in those modes? I'm the one confused now. You wanted me to add IFTYPE_IBSS in nl80211_tx_control_port in your earlier feedback :) Let me try to restate what I said earlier in a different way and see if it makes things a bit clearer: So in patch 9, we set sdata->control_port_over_nl80211 based on parameters passed into start_ap or mgd_assoc. The control_port_over_nl80211 flag is passed in cfg80211_crypto_settings structure that is part of the relevant parameters structure. If sdata->control_port_over_nl80211 is true, then we actually redirect the control port frames to nl80211. So my question is, if we want to support IBSS/MESH, should we: 1. add the whole cfg80211_crypto_settings to the IBSS/MESH parameters, 2. add the control_port_over_nl80211 flag directly to IBSS/MESH parameters 3. Pass the flag some other way? 4. Or drop IBSS/MESH from patch 2 (nl80211_tx_control_port) completely? Regards, -Denis
Re: [RFC v5 4/9] cfg80211: Support all iftypes in autodisconnect_wk
Hi Johannes, On 03/21/2018 02:46 AM, Johannes Berg wrote: On Tue, 2018-03-13 at 16:59 -0500, Denis Kenzior wrote: Currently autodisconnect_wk assumes that only interface types of P2P_CLIENT and STATION use conn_owner_nlportid. Change this so all interface types are supported. Hmm. This sort of duplicates cfg80211_leave() for the most part, apart from the special case with cfg80211_mlme_deauth(). I wonder why we need that, and if we could use cfg80211_leave()? cfg80211_leave also messes with scans and autodisconnect_wk didn't. So I played it safe as I didn't want to introduce any silent semantic changes. Also, cfg80211_leave uses stop_ap/leave_ibss with notify argument being true, while I thought it made more sense to use false (as there's arguably nobody left to pay attention to it) and to be consistent with nl80211_stop_ap and nl80211_leave_ibss which also use false. I don't see an issue with using cfg80211_leave though. Just tell me which way you prefer. Regards, -Denis
Re: [RFC v5 0/9] EAPoL over NL80211
Hi Johannes, On 03/21/2018 10:13 AM, Johannes Berg wrote: TODO: That was well-hidden :) Sorry. I assumed people read the change log :) - It is unclear to me how AP_VLAN and AP interfaces should synchronize on conn_owner_nlportid. This is required for tx_control_port to work. I'm not really sure what you mean? Technically I guess an AP_VLAN could have a different owner from an AP, but if the AP goes down all the AP_VLANs go down with it already anyway. So the issue is that when mac80211 calls cfg80211_rx_control_port and subsequently __nl80211_rx_control_port, we grab the nlportid from the wdev. So if that isn't synchronized, then AP_VLAN devices won't be sending the EAPoL frames to the right place. - JOIN_IBSS & JOIN_MESH don't seem to support control_port_ethertype or control_port_no_encrypt. Should struct cfg80211_crypto_settings parsed inside nl80211_crypto_settings be added to ibss_params or mesh_config/mesh_setup? I don't think it matters - they just don't support this now and don't really need to. Except that the eapol over nl80211 flag is being sent in security settings. This covers STA/AP/P2P_GO/P2P_CLIENT. We need some way of passing this information for mesh & ibss. Regards, -Denis
Re: [RFC v5 3/9] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Hi Johannes, On 03/21/2018 02:47 AM, Johannes Berg wrote: On Tue, 2018-03-13 at 16:59 -0500, Denis Kenzior wrote: + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) + return -EINVAL; There might be value in adding GENL_SET_ERR_MSG() calls to new instances of -EINVAL, but if you don't want to do that now I won't insist (and perhaps add some when I apply the patches). Sure, that sounds easy enough. Did you see the TODO comments I added in RFC v5 0/9 message? I need your help figuring out how you want to handle those. Those are pretty esoteric though and would require more surgery. Any chance that we can merge the non-controversial bits of this RFC so that we can get some wider testing and start encouraging non-mac80211 based drivers to support these mechanisms? Regards, -Denis
[RFC v5 4/9] cfg80211: Support all iftypes in autodisconnect_wk
Currently autodisconnect_wk assumes that only interface types of P2P_CLIENT and STATION use conn_owner_nlportid. Change this so all interface types are supported. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/sme.c | 43 --- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 701cfd7acc1b..5df6b33db786 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1239,17 +1239,38 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) wdev_lock(wdev); if (wdev->conn_owner_nlportid) { - /* -* Use disconnect_bssid if still connecting and ops->disconnect -* not implemented. Otherwise we can use cfg80211_disconnect. -*/ - if (rdev->ops->disconnect || wdev->current_bss) - cfg80211_disconnect(rdev, wdev->netdev, - WLAN_REASON_DEAUTH_LEAVING, true); - else - cfg80211_mlme_deauth(rdev, wdev->netdev, -wdev->disconnect_bssid, NULL, 0, -WLAN_REASON_DEAUTH_LEAVING, false); + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + cfg80211_leave_ibss(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + cfg80211_stop_ap(rdev, wdev->netdev, false); + break; + case NL80211_IFTYPE_MESH_POINT: + cfg80211_leave_mesh(rdev, wdev->netdev); + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + /* +* Use disconnect_bssid if still connecting and +* ops->disconnect not implemented. Otherwise we can +* use cfg80211_disconnect. +*/ + if (rdev->ops->disconnect || wdev->current_bss) + cfg80211_disconnect(rdev, wdev->netdev, + WLAN_REASON_DEAUTH_LEAVING, + true); + else + cfg80211_mlme_deauth(rdev, wdev->netdev, +wdev->disconnect_bssid, +NULL, 0, +WLAN_REASON_DEAUTH_LEAVING, +false); + break; + default: + break; + } } wdev_unlock(wdev); -- 2.13.5
[RFC v5 3/9] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 14 +- net/wireless/nl80211.c | 13 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 76b6783f35f6..2e7f30c66913 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 77675ae3e475..1cdac3d732c1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1488,6 +1489,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2641,6 +2651,8 @@ enum nl80211_attrs { NL80211_ATTR_NSS, NL80211_ATTR_ACK_SIGNAL, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3c4dbfa0ca71..24b1bd940fca 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -287,6 +287,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -8227,6 +8228,18 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, } else settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) + return -EINVAL; + + if (!rdev->ops->tx_control_port || + !wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + settings->control_port_over_nl80211 = true; + } + if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { void *data; int len, i; -- 2.13.5
[RFC v5 5/9] nl80211: Add SOCKET_OWNER support to JOIN_IBSS
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ibss.c | 1 + net/wireless/nl80211.c | 6 ++ 3 files changed, 9 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1cdac3d732c1..877fab2836ec 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1985,6 +1985,8 @@ enum nl80211_commands { * multicast group. * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the * station will deauthenticate when the socket is closed. + * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically + * torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index a1d10993d08a..d5d26fc5b853 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -224,6 +224,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, if (err) return err; + wdev->conn_owner_nlportid = 0; __cfg80211_clear_ibss(dev, nowext); return 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 24b1bd940fca..e678dc510f3a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8691,6 +8691,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_join_ibss(rdev, dev, , connkeys); if (err) kzfree(connkeys); + else if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + return err; } -- 2.13.5
[RFC v5 6/9] nl80211: Add SOCKET_OWNER support to JOIN_MESH
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 10 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 877fab2836ec..e3329bc4644b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1987,6 +1987,8 @@ enum nl80211_commands { * station will deauthenticate when the socket is closed. * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically * torn down when the socket is closed. + * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be + * automatically torn down when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index b12da6ef3c12..e91a5078615b 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -286,6 +286,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, err = rdev_leave_mesh(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->mesh_id_len = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e678dc510f3a..e38d55cf34f7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10140,7 +10140,15 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) setup.userspace_handles_dfs = nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); - return cfg80211_join_mesh(rdev, dev, , ); + err = cfg80211_join_mesh(rdev, dev, , ); + + if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) { + wdev_lock(dev->ieee80211_ptr); + dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid; + wdev_unlock(dev->ieee80211_ptr); + } + + return err; } static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) -- 2.13.5
[RFC v5 8/9] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/tx.c | 46 ++ 3 files changed, 50 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fd68f6fb02d7..9294acb495ee 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3786,4 +3786,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ae9c33cd8ada..a52bd2a61a27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1734,6 +1734,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7643178ef132..6ae8fe121500 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4749,3 +4749,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(ETH_P_PREAUTH)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[RFC v5 9/9] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 4 net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 2 ++ net/mac80211/main.c| 2 ++ net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 33 - 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9294acb495ee..180653fcdb94 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +936,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = + params->crypto.control_port_over_nl80211; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a52bd2a61a27..00dbc6a1b79d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d13ba064951f..555e389b7dfa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -519,6 +519,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) master->control_port_protocol; sdata->control_port_no_encrypt = master->control_port_no_encrypt; + sdata->control_port_over_nl80211 = + master->control_port_over_nl80211; sdata->vif.cab_queue = master->vif.cab_queue; memcpy(sdata->vif.hw_queue, master->vif.hw_queue, sizeof(sdata->vif.hw_queue)); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..e5a51267c75d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0024eff9bb84..b3665b857883 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4844,6 +4844,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + req->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(local, >crypto, sdata->vif.type); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de7d10732fd5..bbb8bc6cac2a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2245,6 +2245,32 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) return true; } +static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, +struct ieee80211_rx_data *rx) +{ + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; + +
[RFC v5 2/9] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. A new EXT_FEATURE flag is introduced so that nl80211 code can check whether a given wiphy has capability to pass EAPoL frames over NL80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 ++ include/uapi/linux/nl80211.h | 3 ++ net/wireless/nl80211.c | 70 +++- net/wireless/rdev-ops.h | 15 ++ net/wireless/trace.h | 26 5 files changed, 122 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6dee630ee66d..76b6783f35f6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2960,6 +2960,9 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3255,6 +3258,12 @@ struct cfg80211_ops { const u8 *aa); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const __be16 proto, + const bool noencrypt); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 1334f810f7b4..77675ae3e475 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5012,6 +5012,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5042,6 +5044,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_LOW_SPAN_SCAN, NL80211_EXT_FEATURE_LOW_POWER_SCAN, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d7dcc2d05025..3c4dbfa0ca71 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12517,6 +12517,67 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ); } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) + return -EINVAL; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + le
[RFC v5 7/9] nl80211: Add SOCKET_OWNER support to START_AP
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/ap.c| 1 + net/wireless/nl80211.c | 4 3 files changed, 7 insertions(+) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e3329bc4644b..9b4fd4bca141 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1989,6 +1989,8 @@ enum nl80211_commands { * torn down when the socket is closed. * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be * automatically torn down when the socket is closed. + * If set during %NL80211_CMD_START_AP the AP will be automatically + * disabled when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 63682176c96c..882d97bdc6bf 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -27,6 +27,7 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, err = rdev_stop_ap(rdev, dev); if (!err) { + wdev->conn_owner_nlportid = 0; wdev->beacon_interval = 0; memset(>chandef, 0, sizeof(wdev->chandef)); wdev->ssid_len = 0; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e38d55cf34f7..bbdcc61a738c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4135,6 +4135,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) wdev->chandef = params.chandef; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); + + if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) + wdev->conn_owner_nlportid = info->snd_portid; + } wdev_unlock(wdev); -- 2.13.5
[RFC v5 0/9] EAPoL over NL80211
ontrol_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (9): nl80211: Add CMD_CONTROL_PORT_FRAME API nl80211: Implement TX of control port frames nl80211: Add CONTROL_PORT_OVER_NL80211 attribute cfg80211: Support all iftypes in autodisconnect_wk nl80211: Add SOCKET_OWNER support to JOIN_IBSS nl80211: Add SOCKET_OWNER support to JOIN_MESH nl80211: Add SOCKET_OWNER support to START_AP mac80211: Add support for tx_control_port mac80211: Send control port frames over nl80211 include/net/cfg80211.h | 34 + include/uapi/linux/nl80211.h | 36 +- net/mac80211/cfg.c | 5 ++ net/mac80211/ieee80211_i.h | 4 ++ net/mac80211/iface.c | 2 + net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c| 33 +++-- net/mac80211/tx.c| 46 + net/wireless/ap.c| 1 + net/wireless/ibss.c | 1 + net/wireless/mesh.c | 1 + net/wireless/nl80211.c | 161 ++- net/wireless/rdev-ops.h | 15 net/wireless/sme.c | 43 +--- net/wireless/trace.h | 47 + 16 files changed, 414 insertions(+), 19 deletions(-) -- 2.13.5
[RFC v5 1/9] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT, NL80211_CMD_ASSOCIATE or NL80211_CMD_START_AP Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 22 + include/uapi/linux/nl80211.h | 13 ++ net/wireless/nl80211.c | 58 net/wireless/trace.h | 21 4 files changed, 114 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fc40843baed3..6dee630ee66d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5694,6 +5694,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - notification about a received control port frame + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * This function is used to inform userspace about a received control port + * frame. It should only be used if userspace indicated it wants to receive + * control port frames over NL80211. + * + * The frame is the data portion of the 802.3 or 802.11 data frame with all + * network layer headers removed (e.g. the raw EAPoL frame). + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c13c84304be3..1334f810f7b4 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -990,6 +990,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host @@ -1228,6 +1239,8 @@ enum nl80211_commands { NL80211_CMD_STA_OPMODE_CHANGED, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a910150f8169..d7dcc2d05025 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14535,6 +14535,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_rx_control_port(struct net_device *dev, +const u8 *buf, size_t len, +const u8 *addr, u16 proto, +bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), + NL80211_ATTR_PAD) || + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + nla_put(
Re: [RFC v4 3/6] nl80211: Implement TX of control port frames
Hi Johannes, On 02/19/2018 06:44 AM, Johannes Berg wrote: On Wed, 2018-01-31 at 19:04 -0600, Denis Kenzior wrote: + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } Why restrict this to client mode? At the very least, P2P_CLIENT really should be listed there, but I'm not sure why not also support it in IBSS, and AP/P2P_GO/AP_VLAN modes? We could do this in a separate patch, but then we have to define different flags for the modes which seems somewhat pointless. I've no means of testing the other modes at this time. So I'm not sure what to tell you. I can respin with IFTYPE_P2P_CLIENT in the switch/case (or you can amend and do so). Regards, -Denis
Re: [RFC v3 0/6] EAPoL over NL80211
Hi Johannes, On 01/31/2018 04:00 PM, Johannes Berg wrote: Looks pretty good! Some comments over in separate emails. Maybe you should consider reordering: [1/6] keep [2/6] keep [3/6] introduce TX (now patch 5) [4/6] introduce RX (now patch 3) modify this to require TX from the driver in order to be able to set the new flag [5/6] add TX to mac80211 [6/6] add RX to mac80211 and set the flag Ok, you don't really have to do that, since you only set the flag in the last patch anyway, but that'd make it better to add the check that requires TX, so you don't have to do that in the TX patch and modify the RX portion again. Err, Johannes Berg presents: Fun with Flags ;) So I re-read this about half a dozen times and I think I figured out what you wanted. It seems you mean different flags in 4/6 and 6/6. I reordered V4 with my interpretation. Doesn't quite look like the above, but hopefully I groked what you wanted correctly. I didn't put in the extra owner check on the tx operation since it wasn't clear whether you wanted that or not. Thanks for the review. Regards, -Denis
[RFC v4 6/6] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/main.c| 2 ++ net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 33 - 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fb3cf38d674f..71cb45e517b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = false; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +935,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = false; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c78f30555b6d..c71d2eded1f2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..e5a51267c75d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39b660b9a908..fc71a906939b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4830,6 +4830,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + req->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(local, >crypto, sdata->vif.type); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e755f93ad735..c152fc318c11 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2243,6 +2243,32 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) return true; } +static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, +struct ieee80211_rx_data *rx) +{ + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; + + if (unlikely((skb->protocol == sdata->control_port_protocol || + skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) && +sdata->control_port_over_nl80211)) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + bool noencrypt = status->flag & RX_FLAG_DECRYPTED; + struct ethhdr *ehdr = eth_hdr(skb); + + cfg80211_rx_control_port(dev, skb->data, skb->len, +ehdr->h_source, +be16_to_cpu(skb->protocol), noencrypt); + dev_kfree_skb(skb); + } else { + /* deliver to local stack */ + if (rx->napi) + napi_gro_receive(rx->napi, skb); + else + netif_receive_skb(skb); + } +} +
[RFC v4 3/6] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. A new EXT_FEATURE flag is introduced so that nl80211 code can check whether a given wiphy has capability to pass EAPoL frames over NL80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 +++ include/uapi/linux/nl80211.h | 3 +++ net/wireless/nl80211.c | 63 +++- net/wireless/rdev-ops.h | 15 +++ net/wireless/trace.h | 26 ++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f3102c6745fd..e1686421fdd7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2958,6 +2958,9 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3253,6 +3256,12 @@ struct cfg80211_ops { const u8 *aa); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const __be16 proto, + const bool noencrypt); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 31fc88cb0a2c..5842b3954cfd 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5009,6 +5009,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5039,6 +5041,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_LOW_SPAN_SCAN, NL80211_EXT_FEATURE_LOW_POWER_SCAN, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bffbd2cd2fc3..645c072cc4a3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12515,6 +12515,60 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ); } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) + return -EINVAL; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + dest = nla_data(info->attrs[NL80211_ATTR_MAC]); + proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + noencrypt = + nla_get_fl
[RFC v4 4/6] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 14 +- net/wireless/nl80211.c | 13 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e1686421fdd7..ccc501cc6ffc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5842b3954cfd..d6016afbfdd7 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1488,6 +1489,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2640,6 +2650,8 @@ enum nl80211_attrs { NL80211_ATTR_NSS, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 645c072cc4a3..fbc6c3ddb5f9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -286,6 +286,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -8225,6 +8226,18 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, } else settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE); + if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) { + if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) + return -EINVAL; + + if (!rdev->ops->tx_control_port || + !wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + settings->control_port_over_nl80211 = true; + } + if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { void *data; int len, i; -- 2.13.5
[RFC v4 1/6] uapi: Add 802.11 Preauthentication to if_ether
This adds 0x88c7 protocol type to if_ether. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index f8cb5760ea4f..54585906e50a 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -89,6 +89,7 @@ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet*/ #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ +#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ #define ETH_P_TIPC 0x88CA /* TIPC */ #define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ -- 2.13.5
[RFC v4 5/6] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/tx.c | 46 ++ 3 files changed, 50 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 46028e12e216..fb3cf38d674f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3785,4 +3785,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26900025de2f..c78f30555b6d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1734,6 +1734,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 25904af38839..99934bc3cd83 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4754,3 +4754,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(ETH_P_PREAUTH)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[RFC v4 2/6] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT or NL80211_CMD_ASSOCIATE Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 22 + include/uapi/linux/nl80211.h | 13 ++ net/wireless/nl80211.c | 58 net/wireless/trace.h | 21 4 files changed, 114 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7d49cd0cf92d..f3102c6745fd 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5690,6 +5690,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - notification about a received control port frame + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * This function is used to inform userspace about a received control port + * frame. It should only be used if userspace indicated it wants to receive + * control port frames over NL80211. + * + * The frame is the data portion of the 802.3 or 802.11 data frame with all + * network layer headers removed (e.g. the raw EAPoL frame). + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ca3d5a613fc0..31fc88cb0a2c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -990,6 +990,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host @@ -1228,6 +1239,8 @@ enum nl80211_commands { NL80211_CMD_STA_OPMODE_CHANGED, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cc6ec5bab676..bffbd2cd2fc3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14549,6 +14549,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_rx_control_port(struct net_device *dev, +const u8 *buf, size_t len, +const u8 *addr, u16 proto, +bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), + NL80211_ATTR_PAD) || + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + nla_put(msg, NL80211_ATT
[RFC v4 0/6] EAPoL over NL80211
This patchset adds support for running 802.11 authentication mechanisms (e.g. 802.1X, 4-Way Handshake, etc) over NL80211 instead of putting them onto the network device. This has the advantage of fixing several long-standing race conditions that result from userspace operating on multiple transports in order to manage a 802.11 connection (e.g. NL80211 and wireless netdev, wlan0, etc). For example, userspace would sometimes see 4-Way handshake packets before NL80211 signaled that the connection has been established. Leading to ugly hacks or having the STA wait for retransmissions from the AP. This also provides a way to mitigate a particularly nasty race condition where the encryption key could be set prior to the 4-way handshake packet 4/4 being sent. This would result in the packet being sent encrypted and discarded by the peer. The mitigation strategy for this race is for userspace to explicitly tell the kernel that a particular EAPoL packet should not be encrypted. To make this possible this patchset introduces a new NL80211 command and several new attributes. A userspace that is capable of processing EAPoL packets over NL80211 includes a new NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute in its NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT requests being sent to the kernel. The previously added NL80211_ATTR_SOCKET_OWNER attribute must also be included. The latter is used by the kernel to send NL80211_CMD_CONTROL_PORT_FRAME notifications back to userspace via a netlink unicast. If the NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute is not specified, then legacy behavior is kept and control port packets continue to flow over the network interface. If control port over nl80211 transport is requested, then control port packets are intercepted just prior to being handed to the network device and sent over netlink via the NL80211_CMD_CONTROL_PORT_FRAME notification. NL80211_ATTR_CONTROL_PORT_ETHERTYPE and NL80211_ATTR_MAC are included to specify the control port frame protocol and source address respectively. If the control port frame was received unencrypted then NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag is also included. NL80211_ATTR_FRAME attribute contains the raw control port frame with all transport layer headers stripped (e.g. this would be the raw EAPoL frame). Userspace can reply to control port frames either via legacy methods (by sending frames to the network device) or via NL80211_CMD_CONTROL_PORT_FRAME request. Userspace would included NL80211_ATTR_FRAME with the raw control port frame as well as NL80211_Attr_MAC and NL80211_ATTR_CONTROL_PORT_ETHERTYPE attributes to specify the destination address and protocol respectively. This allows Pre-Authentication (protocol 0x88c7) frames to be sent via this mechanism as well. Finally, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag can be included to tell the driver to send the frame unencrypted, e.g. for 4-Way handshake 4/4 frames. The proposed patchset has been tested in a mac80211_hwsim based environment with hostapd and iwd. ChangeLog v4 - Reordered the patches to make sure that: when CONTROL_PORT_OVER_NL80211 is provided by userspace, nl80211 checks that both EXT_FEATURE bit is set and the tx_control_port is present in rdev ops. - Fixed up various issues Johannes found in his review v3 - Added ETH_P_PREAUTH to if_ether.h - Moved NL80211 feature bit from wiphy features to ext features - Addressed various comments from Johannes v2 - Added WIPHY_FLAG_CONTROL_PORT_OVER_NL80211 flag. This is a capability flag used by the drivers, e.g. that the driver supports control port over nl80211 capability. This capability is now checked when CONTROL_PORT_OVER_NL80211 is requested. - mac80211 rx path now forwards Pre-Authentication frames over NL80211 as well, if requested. Tweaked the signature of cfg80211_rx_control_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (6): uapi: Add 802.11 Preauthentication to if_ether nl80211: Add CMD_CONTROL_PORT_FRAME API nl80211: Implement TX of control port frames nl80211: Add CONTROL_PORT_OVER_NL80211 attribute mac80211: Add support for tx_control_port mac80211: Send control port frames over nl80211 include/net/cfg80211.h| 34 +++ include/uapi/linux/if_ether.h | 1 + include/uapi/linux/nl80211.h | 30 +- net/mac80211/cfg.c| 3 + net/mac80211/ieee80211_i.h| 4 ++ net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c | 33 +-- net/mac80211/tx.c | 46 +++ net/wireless/nl80211.c| 134 +- net/wireless/rdev-ops.h | 15 + net/wireless/trace.h | 47 +++ 12 files changed, 344 insertions(+), 7 deletions(-) -- 2.13.5
Re: [PATCH 3/6] nl80211: Add CMD_CONTROL_PORT_FRAME API
Hi Johannes, + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. Never mind, so it's without Ethernet header. Is that really desirable though? I mean, it could be that the Ethernet address even matters (not sure) and it'd probably be easier to handle in (existing) userspace where Ethernet frames are expected now? I also include the from address inside the NL80211 message as ATTR_MAC. The protocol as well. I wrote the docs first and never updated the little details afterwards. Will fix. + nla_put_failure: + genlmsg_cancel(msg, hdr); nit: there's no point in cancelling if you free it (immediately). Just following some existing code, but will fix. +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted) +{ + bool ret; + + trace_cfg80211_rx_control_port(dev, buf, len, addr, proto, unencrypted); + ret = __nl80211_rx_control_port(dev, buf, len, addr, proto, + unencrypted, GFP_ATOMIC); + trace_cfg80211_return_bool(ret); this seems wrong - you return -ERROR from __nl80211_rx_control_port() so you need either to pass that on as an integer to the caller, or put an == 0 here or something? "Return: %true if the frame was passed to userspace" Yep, will fix. Regards, -Denis
Re: [PATCH 5/6] nl80211: Implement TX of control port frames
Hi Johannes, On 01/31/2018 03:53 PM, Johannes Berg wrote: +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; I wonder if maybe we should accept this command only from the socket owner? Is there a use case for something else? Yes I thought about adding such a check as I think it wouldn't make sense to accept control port frames from any other application besides the socket owner. However the socket owner stuff was a bit controversial, so I left it out. I would support adding this check... Actually, then again, that's awkward because doing events and commands on the same socket doesn't mix all _that_ well. Perhaps we just need to fix that problem in libnl or something and be done with it ... There are no issues on our side.. Regards, -Denis
[PATCH 5/6] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 +++ net/wireless/nl80211.c | 63 - net/wireless/rdev-ops.h | 15 net/wireless/trace.h| 25 4 files changed, 111 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 60a38543b830..dc6d37b40574 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2961,6 +2961,9 @@ struct cfg80211_external_auth_params { * * @external_auth: indicates result of offloaded authentication processing from * user space + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3256,6 +3259,12 @@ struct cfg80211_ops { const u8 *aa); int (*external_auth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_external_auth_params *params); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const u16 proto, + const bool noencrypt); }; /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 840dada2cca3..ed5752a99951 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12527,6 +12527,60 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) return rdev_external_auth(rdev, dev, ); } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!wiphy_ext_feature_isset(>wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + return -EOPNOTSUPP; + + if (!rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) + return -EINVAL; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + dest = nla_data(info->attrs[NL80211_ATTR_MAC]); + proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + noencrypt = + nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); + + return rdev_tx_control_port(rdev, dev, buf, len, + dest, cpu_to_be16(proto), noencrypt); + + out: + wdev_unlock(wdev); + return err; +} + #define NL80211_FLAG_NEED_WIPHY0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -13430,7 +13484,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, - + { + .cmd = NL80211_CMD_CONTROL_PORT_FRAME, + .doit = nl80211_tx_control_port, + .policy = nl80211_policy, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_family nl80211_fam __ro_after_init = { diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 84f23ae015fc..ced82e2350f4 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -714,6 +714,21 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, return re
[PATCH 4/6] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 34 +- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 46028e12e216..f53bfb27295f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = false; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +935,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = false; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26900025de2f..6f91aea6a4cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39b660b9a908..fc71a906939b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4830,6 +4830,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + req->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(local, >crypto, sdata->vif.type); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e755f93ad735..c3abf9e44079 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2243,6 +2243,33 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) return true; } +static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb, +struct ieee80211_rx_data *rx) +{ + struct ieee80211_sub_if_data *sdata = rx->sdata; + struct net_device *dev = sdata->dev; + + if (unlikely((skb->protocol == sdata->control_port_protocol || + skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) && +sdata->control_port_over_nl80211)) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + bool noencrypt = status->flag & RX_FLAG_DECRYPTED; + struct ethhdr *ehdr = eth_hdr(skb); + + if (!cfg80211_rx_control_port(dev, skb->data, skb->len, + ehdr->h_source, + be16_to_cpu(skb->protocol), + noencrypt)) + dev_kfree_skb(skb); + } else { + /* deliver to local stack */ + if (rx->napi) + napi_gro_receive(rx->napi, skb); + else + netif_receive_skb(skb); + } +} + /* * requires that rx->skb is a frame with ethernet header */ @@ -2327,13 +2354,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) #endif if (skb) { - /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); - if (rx->napi) - napi_gro_receive(rx->napi, skb); - else - netif_receive_skb(skb); + + ieee80211_deliver_skb_to_local_stack(skb, rx); } if (xmit_skb) { -- 2.13.5
[PATCH 3/6] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT or NL80211_CMD_ASSOCIATE Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 17 + include/uapi/linux/nl80211.h | 15 +++ net/wireless/nl80211.c | 59 net/wireless/trace.h | 21 4 files changed, 112 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fb369947aefb..60a38543b830 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5693,6 +5693,23 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - inform userspace about a received control port + * frame, e.g. EAPoL. This is used if userspace has specified it wants to + * receive control port frames over NL80211. + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 20b35ba6721f..3a9d4364d383 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -991,6 +991,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host @@ -1229,6 +1240,8 @@ enum nl80211_commands { NL80211_CMD_STA_OPMODE_CHANGED, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1476,6 +1489,8 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * When included in %NL80211_CMD_CONTROL_PORT_FRAME it means that the + * control port frame was received unencrypted. * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) * will be sent directly to the network interface or sent via the NL80211 diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0c389044a4d3..840dada2cca3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14561,6 +14561,65 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_rx_control_port(struct net_device *dev, +const u8 *buf, size_t len, +const u8 *addr, u16 proto, +bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); +
[PATCH 2/6] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 17 - net/wireless/nl80211.c | 12 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7d49cd0cf92d..fb369947aefb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ca3d5a613fc0..20b35ba6721f 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1475,6 +1476,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2627,6 +2637,8 @@ enum nl80211_attrs { NL80211_ATTR_NSS, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4996,6 +5008,8 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan. * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan. * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan. + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -5026,6 +5040,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_LOW_SPAN_SCAN, NL80211_EXT_FEATURE_LOW_POWER_SCAN, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cc6ec5bab676..0c389044a4d3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -286,6 +286,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -8225,6 +8226,17 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device
[PATCH 6/6] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/main.c| 2 ++ net/mac80211/tx.c | 46 ++ 4 files changed, 52 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f53bfb27295f..71cb45e517b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3787,4 +3787,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f91aea6a4cb..be444305ef06 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1735,6 +1735,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, u16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..e5a51267c75d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); if (!ops->hw_scan) wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 25904af38839..031b27fa752c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4754,3 +4754,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, u16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(ETH_P_PREAUTH)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[PATCH 1/6] uapi: Add 802.11 Preauthentication to if_ether
This adds 0x88c7 protocol type to if_ether. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/uapi/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index f8cb5760ea4f..54585906e50a 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -89,6 +89,7 @@ #define ETH_P_AOE 0x88A2 /* ATA over Ethernet*/ #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ +#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ #define ETH_P_TIPC 0x88CA /* TIPC */ #define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ -- 2.13.5
[RFC v3 0/6] EAPoL over NL80211
This patchset adds support for running 802.11 authentication mechanisms (e.g. 802.1X, 4-Way Handshake, etc) over NL80211 instead of putting them onto the network device. This has the advantage of fixing several long-standing race conditions that result from userspace operating on multiple transports in order to manage a 802.11 connection (e.g. NL80211 and wireless netdev, wlan0, etc). For example, userspace would sometimes see 4-Way handshake packets before NL80211 signaled that the connection has been established. Leading to ugly hacks or having the STA wait for retransmissions from the AP. This also provides a way to mitigate a particularly nasty race condition where the encryption key could be set prior to the 4-way handshake packet 4/4 being sent. This would result in the packet being sent encrypted and discarded by the peer. The mitigation strategy for this race is for userspace to explicitly tell the kernel that a particular EAPoL packet should not be encrypted. To make this possible this patchset introduces a new NL80211 command and several new attributes. A userspace that is capable of processing EAPoL packets over NL80211 includes a new NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute in its NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT requests being sent to the kernel. The previously added NL80211_ATTR_SOCKET_OWNER attribute must also be included. The latter is used by the kernel to send NL80211_CMD_CONTROL_PORT_FRAME notifications back to userspace via a netlink unicast. If the NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute is not specified, then legacy behavior is kept and control port packets continue to flow over the network interface. If control port over nl80211 transport is requested, then control port packets are intercepted just prior to being handed to the network device and sent over netlink via the NL80211_CMD_CONTROL_PORT_FRAME notification. NL80211_ATTR_CONTROL_PORT_ETHERTYPE and NL80211_ATTR_MAC are included to specify the control port frame protocol and source address respectively. If the control port frame was received unencrypted then NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag is also included. NL80211_ATTR_FRAME attribute contains the raw control port frame with all transport layer headers stripped (e.g. this would be the raw EAPoL frame). Userspace can reply to control port frames either via legacy methods (by sending frames to the network device) or via NL80211_CMD_CONTROL_PORT_FRAME request. Userspace would included NL80211_ATTR_FRAME with the raw control port frame as well as NL80211_Attr_MAC and NL80211_ATTR_CONTROL_PORT_ETHERTYPE attributes to specify the destination address and protocol respectively. This allows Pre-Authentication (protocol 0x88c7) frames to be sent via this mechanism as well. Finally, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag can be included to tell the driver to send the frame unencrypted, e.g. for 4-Way handshake 4/4 frames. The proposed patchset has been tested in a mac80211_hwsim based environment with hostapd and iwd. ChangeLog v3 - Added ETH_P_PREAUTH to if_ether.h - Moved NL80211 feature bit from wiphy features to ext features - Addressed various comments from Johannes v2 - Added WIPHY_FLAG_CONTROL_PORT_OVER_NL80211 flag. This is a capability flag used by the drivers, e.g. that the driver supports control port over nl80211 capability. This capability is now checked when CONTROL_PORT_OVER_NL80211 is requested. - mac80211 rx path now forwards Pre-Authentication frames over NL80211 as well, if requested. Tweaked the signature of cfg80211_rx_control_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (6): uapi: Add 802.11 Preauthentication to if_ether nl80211: Add CONTROL_PORT_OVER_NL80211 attribute nl80211: Add CMD_CONTROL_PORT_FRAME API mac80211: Send control port frames over nl80211 nl80211: Implement TX of control port frames mac80211: Add support for tx_control_port include/net/cfg80211.h| 29 + include/uapi/linux/if_ether.h | 1 + include/uapi/linux/nl80211.h | 32 +- net/mac80211/cfg.c| 3 + net/mac80211/ieee80211_i.h| 4 ++ net/mac80211/main.c | 2 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c | 34 +-- net/mac80211/tx.c | 46 +++ net/wireless/nl80211.c| 134 +- net/wireless/rdev-ops.h | 15 + net/wireless/trace.h | 46 +++ 12 files changed, 341 insertions(+), 7 deletions(-) -- 2.13.5
Re: [RFC v2 4/5] nl80211: Implement TX of control port frames
Hi Johannes, On 01/15/2018 07:14 AM, Johannes Berg wrote: Ok this is the interesting part :-) + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const u16 proto, + const bool noencrypt); (indentation seems off in both patchwork and my email, but whatever) Yes, that was my fault. + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) err, !current_bss? Seems fine to me? There's a break after that if statement. + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + dest = nla_data(info->attrs[NL80211_ATTR_MAC]); + proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + noencrypt = + nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); So this is the data we support here. Jouni and I were talking about this and were thinking we might need "use old key" or something like that. That's rather difficult to do though, I'm not even sure we keep the old key around? Jouni? Do you see how this could work? The other thing we thought about was that maybe we should have "open port after this frame", but since it's an in-band mechanism now you could do that also just before the frame. FWIW, I'm checking with our guy on what other specialities we might want to add into this mix as far as workarounds are concerned. Sure, I'll hold off on re-spinning these until I get more feedback. Regards, -Denis
Re: [RFC v2 3/5] mac80211: Send control port frames over nl80211
Hi Johannes, On 01/15/2018 07:09 AM, Johannes Berg wrote: On Wed, 2018-01-10 at 11:09 -0600, Denis Kenzior wrote: Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Interesting - maybe userspace should be able to configure a(n) (list of) ethertype(s)? I'm not so sure. Preauthentication is different from EAPoL frames and most of the special-case checks for control_port_ethertype inside mac80211 do not apply to it. I think it might be safer to carry it as a special case to the special case :P Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 31 --- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 46028e12e216..f53bfb27295f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = false; It's probably better to reset this at interface type switching, if it's not done anyway (we zero a lot of memory there, but not sure precisely what) Otherwise we'll surely forget this in some place like mesh or OCB ... Initially it must be false (0) anyway. Where do I look? Right now I'm mostly following the precedent of other control_port_* stuff. Regards, -Denis
[RFC v2 1/5] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 6 ++ include/uapi/linux/nl80211.h | 14 +- net/wireless/nl80211.c | 20 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3a4a1a903a4d..f46bdc4298f1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; @@ -3236,6 +3239,8 @@ struct cfg80211_ops { * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the * control port protocol ethertype. The device also honours the * control_port_no_encrypt flag. + * @WIPHY_FLAG_CONTROL_PORT_OVER_NL80211: This device supports sending and + * receiving control port frames over NL80211 instead of the netdevice. * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. @@ -3288,6 +3293,7 @@ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_5_10_MHZ= BIT(22), WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), WIPHY_FLAG_HAS_STATIC_WEP = BIT(24), + WIPHY_FLAG_CONTROL_PORT_OVER_NL80211= BIT(25), }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c587a61c32bf..8855b7eaf92c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1445,6 +1446,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2579,6 +2589,8 @@ enum nl80211_attrs { NL80211_ATTR_PMKR0_NAME, NL80211_ATTR_PORT_AUTHORIZED, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b3f8970c3a47..840ee6d73269 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -286,6 +286,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [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_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG }, [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, @@ -1547,6 +1548,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_
[RFC v2 5/5] mac80211: Add support for tx_control_port
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/main.c| 1 + net/mac80211/tx.c | 46 ++ 4 files changed, 51 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f53bfb27295f..71cb45e517b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3787,4 +3787,5 @@ const struct cfg80211_ops mac80211_config_ops = { .add_nan_func = ieee80211_add_nan_func, .del_nan_func = ieee80211_del_nan_func, .set_multicast_to_unicast = ieee80211_set_multicast_to_unicast, + .tx_control_port = ieee80211_tx_control_port, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f91aea6a4cb..be444305ef06 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1735,6 +1735,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta); void ieee80211_check_fast_xmit_all(struct ieee80211_local *local); void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata); void ieee80211_clear_fast_xmit(struct sta_info *sta); +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, u16 proto, bool unencrypted); /* HT */ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0785d04a80bc..fe163c31d431 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -976,6 +976,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* mac80211 supports control port protocol changing */ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; + local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_OVER_NL80211; if (ieee80211_hw_check(>hw, SIGNAL_DBM)) { local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 25904af38839..c22d2fa02d76 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4754,3 +4754,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, ieee80211_xmit(sdata, NULL, skb); local_bh_enable(); } + +int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, u16 proto, bool unencrypted) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + struct ethhdr *ehdr; + u32 flags; + + /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE +* or Pre-Authentication +*/ + if (proto != sdata->control_port_protocol && + proto != cpu_to_be16(0x88c7)) + return -EINVAL; + + if (unencrypted) + flags = IEEE80211_TX_INTFL_DONT_ENCRYPT; + else + flags = 0; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(struct ethhdr) + len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); + + skb_put_data(skb, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN); + ehdr->h_proto = proto; + + skb->dev = dev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + + __ieee80211_subif_start_xmit(skb, skb->dev, flags); + + return 0; +} -- 2.13.5
[RFC v2 4/5] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. Userspace should also provide the destination address and the protocol type to use when sending the frame. This is used to implement TX of Pre-authentication frames. If CONTROL_PORT_ETHERTYPE_NO_ENCRYPT is specified, then the driver will be asked not to encrypt the outgoing frame. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 9 net/wireless/nl80211.c | 60 - net/wireless/rdev-ops.h | 15 + net/wireless/trace.h| 25 + 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 84cba57dd8d0..5d1afe3579e7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2924,6 +2924,9 @@ struct cfg80211_pmk_conf { * (invoked with the wireless_dev mutex held) * @del_pmk: delete the previously configured PMK for the given authenticator. * (invoked with the wireless_dev mutex held) + * + * @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter + * tells the driver that the frame should not be encrypted. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -3217,6 +3220,12 @@ struct cfg80211_ops { const struct cfg80211_pmk_conf *conf); int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev, const u8 *aa); + + int (*tx_control_port)(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, const u16 proto, + const bool noencrypt); }; /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c0f2bb24e7dd..2c1082c7b1ea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12474,6 +12474,57 @@ static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info) return ret; } +static int nl80211_tx_control_port(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; + const u8 *buf; + size_t len; + u8 *dest; + u16 proto; + bool noencrypt; + int err; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_OVER_NL80211) || + !rdev->ops->tx_control_port) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_FRAME] || + !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) + return -EINVAL; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + wdev_unlock(wdev); + + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + dest = nla_data(info->attrs[NL80211_ATTR_MAC]); + proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + noencrypt = + nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]); + + return rdev_tx_control_port(rdev, dev, buf, len, + dest, cpu_to_be16(proto), noencrypt); + + out: + wdev_unlock(wdev); + return err; +} + #define NL80211_FLAG_NEED_WIPHY0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -13369,7 +13420,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, - + { + .cmd = NL80211_CMD_CONTROL_PORT_FRAME, + .doit = nl80211_tx_control_port, + .policy = nl80211_policy, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_family nl80211_fam __ro_after_init = { diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 0c06240d25af..fbd67e32bb91 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -714,6 +714,21 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, return ret; } +static inline int rdev_tx_control_port(struct cfg80211_registered_d
[RFC v2 2/5] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT or NL80211_CMD_ASSOCIATE Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 17 + include/uapi/linux/nl80211.h | 15 +++ net/wireless/nl80211.c | 59 net/wireless/trace.h | 21 4 files changed, 112 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f46bdc4298f1..84cba57dd8d0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5629,6 +5629,23 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - inform userspace about a received control port + * frame, e.g. EAPoL. This is used if userspace has specified it wants to + * receive control port frames over NL80211. + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @addr: The peer from which the frame was received + * @proto: frame protocol, typically PAE or Pre-authentication + * @unencrypted: Whether the frame was received unencrypted + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8855b7eaf92c..b902614e876e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -991,6 +991,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_MAX: highest used command number @@ -1199,6 +1210,8 @@ enum nl80211_commands { NL80211_CMD_RELOAD_REGDB, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1446,6 +1459,8 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * When included in %NL80211_CMD_CONTROL_PORT_FRAME it means that the + * control port frame was received unencrypted. * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) * will be sent directly to the network interface or sent via the NL80211 diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 840ee6d73269..c0f2bb24e7dd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14500,6 +14500,65 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_control_port(struct net_device *dev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, + bool unencrypted, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + +
[RFC v2 3/5] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Pre-authentication type frames (protocol: 0x88c7) are also forwarded over nl80211. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/cfg.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c| 2 ++ net/mac80211/rx.c | 31 --- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 46028e12e216..f53bfb27295f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = false; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +935,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = false; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26900025de2f..6f91aea6a4cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool control_port_over_nl80211; int encrypt_headroom; atomic_t num_tx_queued; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 39b660b9a908..fc71a906939b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4830,6 +4830,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_protocol = req->crypto.control_port_ethertype; sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = + req->crypto.control_port_over_nl80211; sdata->encrypt_headroom = ieee80211_cs_headroom(local, >crypto, sdata->vif.type); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b3cff69bfd66..28b74ae1ee48 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2326,16 +2326,41 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } #endif - if (skb) { + if (!skb) + goto try_xmit; + + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + + if (unlikely((skb->protocol == sdata->control_port_protocol || + skb->protocol == cpu_to_be16(0x88c7)) && +sdata->control_port_over_nl80211)) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + bool noencrypt; + + ehdr = eth_hdr(skb); + + if (status->flag & RX_FLAG_DECRYPTED) + noencrypt = false; + else + noencrypt = true; + + if (!cfg80211_rx_control_port(dev, skb->data, skb->len, + ehdr->h_source, + be16_to_cpu(skb->protocol), + noencrypt)) { + dev_kfree_skb(skb); + skb = NULL; + } + } else { /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); if (rx->napi) napi_gro_receive(rx->napi, skb); else netif_receive_skb(skb); } +try_xmit: if (xmit_skb) { /* * Send to wireless media and increase priority by 256 to -- 2.13.5
[RFC v2 0/5] EAPoL over NL80211
This patchset adds support for running 802.11 authentication mechanisms (e.g. 802.1X, 4-Way Handshake, etc) over NL80211 instead of putting them onto the network device. This has the advantage of fixing several long-standing race conditions that result from userspace operating on multiple transports in order to manage a 802.11 connection (e.g. NL80211 and wireless netdev, wlan0, etc). For example, userspace would sometimes see 4-Way handshake packets before NL80211 signaled that the connection has been established. Leading to ugly hacks or having the STA wait for retransmissions from the AP. This also provides a way to mitigate a particularly nasty race condition where the encryption key could be set prior to the 4-way handshake packet 4/4 being sent. This would result in the packet being sent encrypted and discarded by the peer. The mitigation strategy for this race is for userspace to explicitly tell the kernel that a particular EAPoL packet should not be encrypted. To make this possible this patchset introduces a new NL80211 command and several new attributes. A userspace that is capable of processing EAPoL packets over NL80211 includes a new NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute in its NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT requests being sent to the kernel. The previously added NL80211_ATTR_SOCKET_OWNER attribute must also be included. The latter is used by the kernel to send NL80211_CMD_CONTROL_PORT_FRAME notifications back to userspace via a netlink unicast. If the NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute is not specified, then legacy behavior is kept and control port packets continue to flow over the network interface. If control port over nl80211 transport is requested, then control port packets are intercepted just prior to being handed to the network device and sent over netlink via the NL80211_CMD_CONTROL_PORT_FRAME notification. NL80211_ATTR_CONTROL_PORT_ETHERTYPE and NL80211_ATTR_MAC are included to specify the control port frame protocol and source address respectively. If the control port frame was received unencrypted then NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag is also included. NL80211_ATTR_FRAME attribute contains the raw control port frame with all transport layer headers stripped (e.g. this would be the raw EAPoL frame). Userspace can reply to control port frames either via legacy methods (by sending frames to the network device) or via NL80211_CMD_CONTROL_PORT_FRAME request. Userspace would included NL80211_ATTR_FRAME with the raw control port frame as well as NL80211_Attr_MAC and NL80211_ATTR_CONTROL_PORT_ETHERTYPE attributes to specify the destination address and protocol respectively. This allows Pre-Authentication (protocol 0x88c7) frames to be sent via this mechanism as well. Finally, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT flag can be included to tell the driver to send the frame unencrypted, e.g. for 4-Way handshake 4/4 frames. The proposed patchset has been tested in a mac80211_hwsim based environment with hostapd and iwd. ChangeLog v2 - Added WIPHY_FLAG_CONTROL_PORT_OVER_NL80211 flag. This is a capability flag used by the drivers, e.g. that the driver supports control port over nl80211 capability. This capability is now checked when CONTROL_PORT_OVER_NL80211 is requested. - mac80211 rx path now forwards Pre-Authentication frames over NL80211 as well, if requested. Tweaked the signature of cfg80211_rx_control_port. - TX path reworked completely. tx_control_port method has been introduced to cfg80211_ops. An implementation of tx_control_port for mac80211 was added. Denis Kenzior (5): nl80211: Add CONTROL_PORT_OVER_NL80211 attribute nl80211: Add CMD_CONTROL_PORT_FRAME API mac80211: Send control port frames over nl80211 nl80211: Implement TX of control port frames mac80211: Add support for tx_control_port include/net/cfg80211.h | 32 ++ include/uapi/linux/nl80211.h | 29 - net/mac80211/cfg.c | 3 + net/mac80211/ieee80211_i.h | 4 ++ net/mac80211/main.c | 1 + net/mac80211/mlme.c | 2 + net/mac80211/rx.c| 31 +- net/mac80211/tx.c| 46 ++ net/wireless/nl80211.c | 139 ++- net/wireless/rdev-ops.h | 15 + net/wireless/trace.h | 46 ++ 11 files changed, 343 insertions(+), 5 deletions(-) -- 2.13.5
Re: [PATCH v2 1/3] cfg80211/nl80211: Optional authentication offload to userspace
Hi Jouni, Johannes, > + * User space uses the %NL80211_CMD_CONNECT command to the host driver for + * triggering a connection. The host driver selects a BSS and further uses + * this interface to offload only the authentication part to the user + * space. Authentication frames are passed between the driver and user + * space through the %NL80211_CMD_FRAME interface. The status of So this implies userspace must pre-register for authentication management frames, correct? And other applications could register to receive these frames as well? Would it not be easier (and more secure) to simply forward these directly to the application that triggered CMD_CONNECT instead? + * authentication is further indicated by user space to the host driver + * with the %NL80211_CMD_EXTERNAL_AUTH command through + * %NL80211_ATTR_STATUS_CODE attribute. This enables the driver to proceed + * with association on successful authentication. Driver shall use this + * %NL80211_ATTR_STATUS_CODE attribute to report the connect result to + * user space on an authentication failure. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ +int cfg80211_external_auth_request(struct net_device *dev, + struct cfg80211_external_auth_params *params, + gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EXTERNAL_AUTH); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, params->key_mgmt_suite) || + nla_put_u32(msg, NL80211_ATTR_EXTERNAL_AUTH_ACTION, + params->action) || + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid) || + nla_put(msg, NL80211_ATTR_SSID, params->ssid.ssid_len, + params->ssid.ssid)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(_fam, wiphy_net(>wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); Is there a reason this is being multicast and not unicast to the application that triggered the CONNECT? Who else besides the supplicant daemon might find this information useful? + return 0; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); + return -ENOBUFS; +} +EXPORT_SYMBOL(cfg80211_external_auth_request); + /* initialisation/exit functions */ int __init nl80211_init(void) Regards, -Denis
Re: [RFC 0/4] EAPoL over NL80211
Hi Arend, On 01/03/2018 02:24 PM, Arend Van Spriel wrote: On Tue, Jan 2, 2018 at 2:27 PM, Johannes Berg <johan...@sipsolutions.net> wrote: On Fri, 2017-12-29 at 12:29 -0600, Denis Kenzior wrote: Agreed, requiring both attributes is less than ideal, but I tried to make the initial RFC as minimal as possible. It also helped that iwd uses SOCKET_OWNER by default. What can be done is to always set conn_owner_nlportid and introduce another flag that would indicate whether 'connection tear-down on application exit' was requested. However, my opinion is that the current SOCKET_OWNER behavior should just be made default, especially for control port over nl80211 connections, even if SOCKET_OWNER was not requested. Once the controlling application dies, there's no hope of salvaging the connection, perform rekeys, etc. I think we should keep both attributes; it's better to be explicit that both are needed than to set socket-owner automatically. As I see it the problem is that SOCKET_OWNER behavior is actually two behaviors wrapped in one, ie. 1) make notifications unicast, and 2) tear-down on socket disconnect. So what is the reason for requiring this attribute. In the cover letter you mention it is for unicast notifications, but above you seem to put more weight in the tear-down behavior. From earlier discussion I recall that multicast netlink messages may not be received. Is that the reason for opting for unicast here. If so, I would suggest to mention that in the commit message. There are several ways I could have implemented EAPoL over NL80211 notifications: 1. Multicast it to the wide world 2. Setup a registration framework ala CMD_REGISTER_FRAME or CMD_UNEXPECTED_FRAME 3. Assume frames should be unicast to the process that initiated CMD_CONNECT I see no good reason why anyone would want option 1. Option 2 seemed pointless. Only the supplicant daemon (e.g. iwd or wpa_s) would really want to process these anyway. Is this the reasoning you want me to include in the cover letter? The simplest way of accomplishing 3 was to reuse the conn_owner_nlportid member that the kernel stores in the case that SOCKET_OWNER attribute is used. iwd always uses this by default and quite frankly in the case of EAPoL over NL80211 it doesn't make sense to not use it, at least to me. Without SOCKET_OWNER, if the supplicant daemon dies you have an un-managed, dangling connection. The biggest issue was that each driver defines a set of management frames it can accept via this mechanism. I'm not sure this is "the biggest issue", but I tend to agree with keeping them separate. Yes. Seems like dealing with mgmt and data adds quite a bit of complexity and/or redesign. Just another note. In the cover letter it is mentioned that eapol-over-nl80211 solves some long standing races. Now the example mentioned is indeed one for which wpa_supplicant temporarily stores M1 yes, this race has to be taken care of by the supplicant. We have similar workaround in iwd which I would love to get rid of. or at least that is what I suspect you are referring to. Another issue, for which we have a hack in brcmfmac, is a race between installing the keys through nl80211 and M4 being passed through the netdev which can result in M4 being sent out encrypted. Not sure if your discussion about DONT_CRYPT is about that. This is really a kernel issue being bled out into userspace. Many drivers seem to suffer from this race. I think Ben had a thread some time in June about this as well. But yes, I believe the main impetus to add a DONT_ENCRYPT flag for EAPoL frames sent over NL80211 is to fix this along with supporting weird protocols that explicitly want to be sent unencrypted. Regards, -Denis
Re: [RFC 4/4] nl80211: Implement TX of control port frames
Hi Arend, So essentially we'd need a new operation in cfg80211_ops that would accept the control port frame data and some control flags. Do we want to pass in an skb with all the 802.11 headers set or a 802.3 formatted skb (since that is what other data frames look like initially on the netdev). Our firmware expects EAPOL stuff to come in as 802.3 packet, which probably applies to the other full-mac devices as well. Is there any reason for passing 802.11 packets. I think it was suggested earlier somewhere in this thread to use 802.11 header similar to how mgmt_tx does things. To me it makes more sense to use 802.3 headers so I thought I would double check. Regards, -Denis
Re: [RFC 4/4] nl80211: Implement TX of control port frames
Hi Johannes, If so, can we do something like what ieee80211_process_sa_query_req in net/mac80211/rx.c or ieee80211_tdls_prep_mgmt_packet in net/mac80211/tdls.c do? E.g. use ieee80211_tx_skb or __ieee80211_subif_start_xmit or similar to inject the skb with the DONT_ENCRYPT flag? Yes, this will work - but like I said, it requires more control over the SKB than cfg80211 has today, and than you can get through the regular netdev xmit. So, I'm a bit lost here. You're saying this will work but then it won't. Are you saying this would only work for mac80211 based devices (e.g. ones that implement ieee80211_ops) but not ones that implement cfg80211_ops? I presume because those provide their own net_device_ops? Perhaps a new operation, where we pass a pre-built SKB and control flags? This would likely mean that legacy behavior would still have to be supported for quite some time (forever?) for drivers that don't get around to implementing this, which would be unfortunate. What do you mean by "legacy behaviour"? *Drivers* don't really need to do anything one way or the other, and mac80211 is the only thing implementing control port encrypt/ethertype right now, I suspect. When I say legacy I mean 'over netdev', e.g. not over nl80211. Okay, so what you're saying is that the current CONTROL_PORT_* stuff doesn't work on anything besides mac80211 since drivers can completely ignore stuff inside cfg80211_connect_params. And there's no way for userspace to know this ahead of time? So essentially we'd need a new operation in cfg80211_ops that would accept the control port frame data and some control flags. Do we want to pass in an skb with all the 802.11 headers set or a 802.3 formatted skb (since that is what other data frames look like initially on the netdev). Regards, -Denis
Re: [RFC 4/4] nl80211: Implement TX of control port frames
Hi Johannes, On 01/02/2018 07:30 AM, Johannes Berg wrote: On Thu, 2017-12-28 at 11:58 -0600, Denis Kenzior wrote: This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. A skbuf is built and then injected onto the netdev of the wireless device. The CONTROL_PORT_ETHERTYPE_NO_ENCRYPT will still in theory be honored by You mean CONTROL_PORT_NO_ENCRYPT :-) Right the underlying TX path code. I think this isn't good enough. That was my thinking as well There are cases where CONTROL_PORT_ETHERTYPE_NO_ENCRYPT should be unset, but specific frames still shouldn't be encrypted. So I think for this particular path it would be better to deprecate CONTROL_PORT_ETHERTYPE_NO_ENCRYPT entirely, and have a separate per- frame flag. That also means that we can't really implement it fully in cfg80211, but have to provide some functionality for the driver to do things to be able to honour such flags. Here's another thought I had while poking around. Given the above I don't want to pursue it too seriously unless you think it might work: We already have the IEEE80211_TX_INTFL_DONT_ENCRYPT flag on the skb and some drivers seem to honor this. At least that seems to be the intent as the CONTROL_PORT_NO_ENCRYPT flag ends up being translated to this somewhere in net/mac80211/tx.c. Are the drivers supposed to honor that flag? If so, can we do something like what ieee80211_process_sa_query_req in net/mac80211/rx.c or ieee80211_tdls_prep_mgmt_packet in net/mac80211/tdls.c do? E.g. use ieee80211_tx_skb or __ieee80211_subif_start_xmit or similar to inject the skb with the DONT_ENCRYPT flag? Perhaps a new operation, where we pass a pre-built SKB and control flags? This would likely mean that legacy behavior would still have to be supported for quite some time (forever?) for drivers that don't get around to implementing this, which would be unfortunate. Regards, -Denis
Re: [RFC 0/4] EAPoL over NL80211
Hi Arend, To make this possible this patchset introduces a new NL80211 command and several new attributes. A userspace that is capable of processing EAPoL packets over NL80211 includes a new NL80211_ATTR_CONTROL_PORT_OVER_NL80211 attribute in its NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT requests being sent to the kernel. The previously added NL80211_ATTR_SOCKET_OWNER attribute must also be included. Does it make sense to require a combination of attributes. It is always a bit awkward so prefer to avoid it. Could we implicitly make the netlink unicast for notifications when NL80211_ATTR_CONTROL_PORT_OVER_NL80211 is provided by user-space. Agreed, requiring both attributes is less than ideal, but I tried to make the initial RFC as minimal as possible. It also helped that iwd uses SOCKET_OWNER by default. What can be done is to always set conn_owner_nlportid and introduce another flag that would indicate whether 'connection tear-down on application exit' was requested. However, my opinion is that the current SOCKET_OWNER behavior should just be made default, especially for control port over nl80211 connections, even if SOCKET_OWNER was not requested. Once the controlling application dies, there's no hope of salvaging the connection, perform rekeys, etc. 2. It has been previously suggested that CMD_FRAME infrastructure is used to accomplish control port over nl80211 transport. However, it did not seem to be a good fit as the relevant code paths assume that only management frames are to be sent via this mechanism. Thoughts? What are the issues coming from that assumption? Does it assume 802.11 header is present? What else? Correct. There's also quite a bit of logic to figure out whether the frame is being sent offchannel or not; whether offchannel capability is present in the driver, etc. This can be ignored for control port frames, but makes the code path complicated. The biggest issue was that each driver defines a set of management frames it can accept via this mechanism. The set is structured using management frame type as an identifier and the code checks this set prior to accepting the frame to be sent via CMD_FRAME. Since control port frames are data frames it would probably require quite a bit of surgery in the core mac80211/wireless code and the driver code to make it work. Another issue is that cfg80211_mgmt_tx_params doesn't have a 'don't encrypt' setting. So that part would need to be added as well. Regards, -Denis
[RFC 2/4] nl80211: Add CMD_CONTROL_PORT_FRAME API
This commit also adds cfg80211_rx_control_port function. This is used to generate a CMD_CONTROL_PORT_FRAME event out to userspace. The conn_owner_nlportid is used as the unicast destination. This means that userspace must specify NL80211_ATTR_SOCKET_OWNER flag if control port over nl80211 routing is requested in NL80211_CMD_CONNECT or NL80211_CMD_ASSOCIATE Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 15 +++ include/uapi/linux/nl80211.h | 15 +++ net/wireless/nl80211.c | 62 net/wireless/trace.h | 15 +++ 4 files changed, 107 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0aa1c866a73b..cc480e252367 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5626,6 +5626,21 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, /** + * cfg80211_rx_control_port - inform userspace about a received control port + * frame, e.g. EAPoL. This is used if userspace has specified it wants to + * receive control port frames over NL80211. + * @dev: The device the frame matched to + * @buf: control port frame + * @len: length of the frame data + * @unencrypted: Whether the frame was received unencrypted + * + * Return: %true if the frame was passed to userspace + */ +bool cfg80211_rx_control_port(struct wireless_dev *wdev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, bool unencrypted); + +/** * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event * @dev: network device * @rssi_event: the triggered RSSI event diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8855b7eaf92c..b902614e876e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -991,6 +991,17 @@ * _CMD_CONNECT or _CMD_ROAM. If the 4 way handshake failed * _CMD_DISCONNECT should be indicated instead. * + * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request + * and RX notification. This command is used both as a request to transmit + * a control port frame and as a notification that a control port frame + * has been received. %NL80211_ATTR_FRAME is used to specify the + * frame contents. The frame is the raw EAPoL data, without ethernet or + * 802.11 headers. + * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added + * indicating the protocol type of the received frame; whether the frame + * was received unencrypted and the MAC address of the peer respectively. + * * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded. * * @NL80211_CMD_MAX: highest used command number @@ -1199,6 +1210,8 @@ enum nl80211_commands { NL80211_CMD_RELOAD_REGDB, + NL80211_CMD_CONTROL_PORT_FRAME, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1446,6 +1459,8 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * When included in %NL80211_CMD_CONTROL_PORT_FRAME it means that the + * control port frame was received unencrypted. * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) * will be sent directly to the network interface or sent via the NL80211 diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f5b4008f40da..220fe5bc57fd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -14490,6 +14490,68 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); +static int __nl80211_control_port(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + const u8 *buf, size_t len, + const u8 *addr, u16 proto, + bool unencrypted, gfp_t gfp) +{ + struct net_device *netdev = wdev->netdev; + struct sk_buff *msg; + void *hdr; + u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid); + + if (!nlportid) + return -ENOENT; + + msg = nlmsg_new(100 + len, gfp); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!hdr) { + nlmsg_free(msg); + return -ENOMEM; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + (netdev && nla_put_u32(ms
[RFC 3/4] mac80211: Send control port frames over nl80211
If userspace requested control port frames to go over 80211, then do so. The control packets are intercepted just prior to delivery of the packet to the underlying network device. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/mac80211/rx.c | 32 +--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b3cff69bfd66..13e786fe62a6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2326,16 +2326,42 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } #endif - if (skb) { + if (!skb) + goto try_xmit; + + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + + if (unlikely(skb->protocol == sdata->control_port_protocol && +sdata->control_port_over_nl80211)) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + bool noencrypt; + + ehdr = eth_hdr(skb); + + if (status->flag & RX_FLAG_DECRYPTED) + noencrypt = false; + else + noencrypt = true; + + if (!cfg80211_rx_control_port(>wdev, + skb->data, + skb->len, + ehdr->h_source, + be16_to_cpu(skb->protocol), + noencrypt)) { + dev_kfree_skb(skb); + skb = NULL; + } + } else { /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); if (rx->napi) napi_gro_receive(rx->napi, skb); else netif_receive_skb(skb); } +try_xmit: if (xmit_skb) { /* * Send to wireless media and increase priority by 256 to -- 2.13.5
[RFC 1/4] nl80211: Add CONTROL_PORT_OVER_NL80211 attribute
Signed-off-by: Denis Kenzior <denk...@gmail.com> --- include/net/cfg80211.h | 3 +++ include/uapi/linux/nl80211.h | 14 +- net/mac80211/cfg.c | 2 ++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 2 ++ net/wireless/nl80211.c | 10 ++ 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3a4a1a903a4d..0aa1c866a73b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -646,6 +646,8 @@ struct survey_info { * allowed through even on unauthorized ports * @control_port_no_encrypt: TRUE to prevent encryption of control port * protocol frames. + * @control_port_over_nl80211: TRUE if userspace expects to exchange control + * port frames over NL80211 instead of the network interface. * @wep_keys: static WEP keys, if not NULL points to an array of * CFG80211_MAX_WEP_KEYS WEP keys * @wep_tx_key: key index (0..3) of the default TX static WEP key @@ -661,6 +663,7 @@ struct cfg80211_crypto_settings { bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; + bool control_port_over_nl80211; struct key_params *wep_keys; int wep_tx_key; const u8 *psk; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c587a61c32bf..8855b7eaf92c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -542,7 +542,8 @@ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, + * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and * %NL80211_ATTR_WIPHY_FREQ_HINT. * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are * restrictions on BSS selection, i.e., they effectively prevent roaming @@ -1445,6 +1446,15 @@ enum nl80211_commands { * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom * ethertype frames used for key negotiation must not be encrypted. + * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control + * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE) + * will be sent directly to the network interface or sent via the NL80211 + * socket. If this attribute is missing, then legacy behavior of sending + * control port frames directly to the network interface is used. If the + * flag is included, then control port frames are sent over NL80211 instead + * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is + * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER + * flag. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2579,6 +2589,8 @@ enum nl80211_attrs { NL80211_ATTR_PMKR0_NAME, NL80211_ATTR_PORT_AUTHORIZED, + NL80211_ATTR_CONTROL_PORT_OVER_NL80211, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b77ee342b5f8..b6f37ae5e3be 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -925,6 +925,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, */ sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + sdata->control_port_over_nl80211 = false; sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, sdata->vif.type); @@ -934,6 +935,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_ethertype; vlan->control_port_no_encrypt = params->crypto.control_port_no_encrypt; + vlan->control_port_over_nl80211 = false; vlan->encrypt_headroom = ieee80211_cs_headroom(sdata->local, >crypto, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 26900025de2f..6f91aea6a4cb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,6 +899,7 @@ struct ieee80211_sub_if_data { u16 sequence_number; __be16 control_port_protocol; bool control_port_no_encrypt; + bool c
[RFC 4/4] nl80211: Implement TX of control port frames
This commit implements the TX side of NL80211_CMD_CONTROL_PORT_FRAME. Userspace provides the raw EAPoL frame using NL80211_ATTR_FRAME. A skbuf is built and then injected onto the netdev of the wireless device. The CONTROL_PORT_ETHERTYPE_NO_ENCRYPT will still in theory be honored by the underlying TX path code. Signed-off-by: Denis Kenzior <denk...@gmail.com> --- net/wireless/nl80211.c | 67 +- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 220fe5bc57fd..d6191579f044 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12464,6 +12464,64 @@ static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info) return ret; } +static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) +{ + struct wireless_dev *wdev = info->user_ptr[1]; + const u8 *buf; + u8 *dest; + size_t len; + struct ethhdr *ehdr; + int err; + + if (!info->attrs[NL80211_ATTR_FRAME]) + return -EINVAL; + + wdev_lock(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); + len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + + skb = dev_alloc_skb(sizeof(struct ethhdr) + len); + if (!skb) { + err = -ENOMEM; + goto out; + } + + skb_reserve(skb, sizeof(struct ethhdr)); + + dest = skb_put(skb, len); + memcpy(dest, buf, len); + + ehdr = skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, wdev->current_bss->pub.bssid, ETH_ALEN); + memcpy(ehdr->h_source, wdev_address(wdev), ETH_ALEN); + ehdr->h_proto = cpu_to_be16(ETH_P_PAE); // TODO: How to get ethertype? + + wdev_unlock(wdev); + + skb->dev = wdev->netdev; + skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(skb); + skb_reset_mac_header(skb); + dev_queue_xmit(skb); + return 0; + + out: + wdev_unlock(wdev); + return err; +} + #define NL80211_FLAG_NEED_WIPHY0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -13359,7 +13417,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, - + { + .cmd = NL80211_CMD_CONTROL_PORT_FRAME, + .doit = nl80211_tx_control_port, + .policy = nl80211_policy, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_family nl80211_fam __ro_after_init = { -- 2.13.5