Re: [PATCH v6 2/3] mac80211: Define new driver callback replace_key

2018-08-16 Thread Denis Kenzior

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

2018-08-16 Thread Denis Kenzior

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

2018-07-11 Thread Denis Kenzior

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

2018-07-10 Thread Denis Kenzior

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?

2018-07-10 Thread Denis Kenzior

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

2018-07-03 Thread Denis Kenzior
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

2018-07-03 Thread Denis Kenzior

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

2018-07-03 Thread Denis Kenzior
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?

2018-06-29 Thread Denis Kenzior

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

2018-06-19 Thread Denis Kenzior
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

2018-06-19 Thread Denis Kenzior
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

2018-06-18 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior
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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-22 Thread Denis Kenzior

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

2018-05-21 Thread Denis Kenzior
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

2018-05-21 Thread Denis Kenzior
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

2018-05-18 Thread Denis Kenzior

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

2018-05-18 Thread Denis Kenzior

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

2018-03-27 Thread Denis Kenzior

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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-26 Thread Denis Kenzior
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

2018-03-22 Thread Denis Kenzior

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

2018-03-21 Thread Denis Kenzior

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

2018-03-21 Thread Denis Kenzior

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

2018-03-21 Thread Denis Kenzior

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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-03-13 Thread Denis Kenzior
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

2018-02-20 Thread Denis Kenzior

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

2018-01-31 Thread Denis Kenzior

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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior

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

2018-01-31 Thread Denis Kenzior

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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-31 Thread Denis Kenzior
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

2018-01-15 Thread Denis Kenzior

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

2018-01-15 Thread Denis Kenzior

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

2018-01-10 Thread Denis Kenzior
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

2018-01-10 Thread Denis Kenzior
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

2018-01-10 Thread Denis Kenzior
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

2018-01-10 Thread Denis Kenzior
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

2018-01-10 Thread Denis Kenzior
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

2018-01-10 Thread Denis Kenzior
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

2018-01-04 Thread Denis Kenzior

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

2018-01-03 Thread Denis Kenzior

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

2018-01-03 Thread Denis Kenzior

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

2018-01-03 Thread Denis Kenzior

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

2018-01-02 Thread Denis Kenzior

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

2017-12-29 Thread Denis Kenzior

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

2017-12-28 Thread Denis Kenzior
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

2017-12-28 Thread Denis Kenzior
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

2017-12-28 Thread Denis Kenzior
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

2017-12-28 Thread Denis Kenzior
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



  1   2   >