2011-03-05 01:25:16

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

From: Javier Cardona <[email protected]>

This series adds the capability to authenticate and manage stations from userspace.

Changes from v1: (all suggested by Johannes)
- Userspace actually creates the stations instead of setting the AUTH flag.
- Fix hole that would allow peer links between secured and open peers.
- Pass multiple IEs through generic IE nl80211 attribute
- Remove SAE constant

Javier Cardona (4):
mac80211: Enable mesh security from userspace
mac80211: Let user space receive and send mesh auth/deauth frames
mac80211: Accept mesh auth frames before a peer link has been
established
mac80211: Let userspace create stations when mesh security is enabled

include/linux/nl80211.h | 13 +++++++++----
include/net/cfg80211.h | 10 ++++++----
net/mac80211/cfg.c | 16 ++++++++--------
net/mac80211/ieee80211_i.h | 5 +++--
net/mac80211/main.c | 4 +++-
net/mac80211/mesh.c | 10 +++++++---
net/mac80211/mesh_plink.c | 13 +++++++++----
net/mac80211/rx.c | 3 ++-
net/mac80211/tx.c | 2 +-
net/wireless/mesh.c | 5 +++--
net/wireless/nl80211.c | 40 +++++++++++++++++++++++++++++++++++-----
11 files changed, 86 insertions(+), 35 deletions(-)



2011-03-08 18:56:35

by Javier Cardona

[permalink] [raw]
Subject: Re: [RFC] mac80211: New notification to discover mesh peer candidates.

On Tue, Mar 8, 2011 at 7:10 AM, Johannes Berg <[email protected]> wrote:
> On Mon, 2011-03-07 at 18:11 -0800, Javier Cardona wrote:
>> Notify userspace when a beacon/presp is received from a suitable mesh
>> peer candidate for whom no sta information exists. ?Userspace can then
>> decide to create a sta info for the candidate. ?If userspace is not
>> ready to authenticate the peer right away, it can create the sta info
>> with the authenticated flag unset and set it later.
>
> I'm a little worried about this creating lots of bogus stations if
> somebody is attacking the mesh. Will that be relevant? Would it be
> better to just pass up any beacon that matches the mesh ID, trading CPU
> resources for memory?

With this approach, when security is enabled, the decision to create
the station is still made by the userspace daemon. A normal sequence
would be:

beacon is received
mesh_matches_local is true
no peer exists
send NEW_PEER_CANDIDATE notification
userspace creates unauthenticated station (optionally, to stop notifications)
userspace authenticates station
userspace sets authenticated flag

But alternatively userspace can create no station at all. In that
case a NEW_PEER_CANDIDATE notification is sent for every beacon
received.

If somebody decides to attack the mesh by sending bogus mesh beacons,
userspace may decide not to create stations and ignore the
notifications. You see a problem in this?

> Also, this goes back to the "authenticate station" rather than full
> station management in userspace, right?

Partially. The station must still be created by userspace. We add
the possibility to set the autenticated flag sometime after creation.
I would also like to support the creation of a mesh candidate station
with the ASSOC flag unset, which is not possible at this time.

--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-05 01:25:37

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 3/4 v2] mac80211: Accept mesh auth frames before a peer link has been established

From: Javier Cardona <[email protected]>


Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/rx.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5c1930b..fe0f1e3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -502,7 +502,8 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)

if (ieee80211_is_probe_req(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control) ||
- ieee80211_is_beacon(hdr->frame_control))
+ ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control))
return RX_CONTINUE;

return RX_DROP_MONITOR;
--
1.7.1


2011-03-05 19:14:10

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 4/4 v2] mac80211: Let userspace create stations when mesh security is enabled

On Sat, Mar 5, 2011 at 6:01 AM, Johannes Berg <[email protected]> wrote:
> On Fri, 2011-03-04 at 17:24 -0800, Thomas Pedersen wrote:
>
>> +++ b/net/mac80211/mesh_plink.c
>> @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
>> ? ? ? if (!sta)
>> ? ? ? ? ? ? ? return NULL;
>>
>> - ? ? sta->flags = WLAN_STA_AUTHORIZED;
>> + ? ? sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
>> ? ? ? sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
>> ? ? ? rate_control_rate_init(sta);
>
> This is just for consistency now, right? The AUTH flag isn't tested, but
> stations from userspace will have it set, afaiu?

Right.


--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-07 19:03:57

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/4 v3] mac80211: Enable mesh security from userspace

On Mon, 2011-03-07 at 10:47 -0800, Javier Cardona wrote:

> >> + * @is_secure: or not
> >
> > Given what we just discussed over in the other thread, should we rename
> > this to "userspace_station_mgmt" or something like that?
>
> Are you suggesting to change the name of the flag both in nl80211 and cfg80211?

Yeah, I was.

> Currently ENABLE_SECURITY means "let userspace manage stations", but
> also "ok to accept mesh management frames from secure mesh peers".
> And when the Authenticated Mesh Peering Exchange is implemented, it
> will probably mean "verify mesh peering frames in userspace" and
> "protect mesh peering frames". You either do all these tasks or none,
> so for nl80211 I would prefer a single flag.

Indeed. I forgot about the RSN checking part etc. I suppose we should
just leave it as is then.

> > Also, does it make sense to advertise support for this somehow?
> > Otherwise the new tools will have strange failure cases on older
> > kernels;
>
> Ah, I see. Older kernels would not return an error to userspace if an
> attempt to set a non existing flag was made, right?

Right.

> Are you suggesting to define something like an
> NL80211_MESHCONF_CAPABILITIES mask?

I haven't thought about how I'd do it really -- yes something like that
might make sense.

> > and I can also imagine situations where the mesh APIs are in
> > firmware or so that can't cope with userspace station mgmt.
>
> Ah mesh in firmware... who would want to do that? :)

:-)

johannes


2011-03-22 21:39:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/5 v4] mac80211: Enable mesh security from userspace

On Fri, 2011-03-18 at 13:22 -0700, Javier Cardona wrote:
> Userspace can enable mesh security by providing an RSN IE and setting
> the MESH_SETUP_ENABLE_SECURITY flag.
>
> Also, rename vendor_ie to just ie to reflect that the same attribute may
> be used to pass other IEs, like for instance RSN.

I still think there should be some sort of advertising about whether or
not secure mesh is support so userspace can actually tell the
difference.

Also, can you do the IE rename thing in a separate patch please?

johannes


2011-03-05 20:23:37

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

On Sat, 2011-03-05 at 12:01 -0800, Javier Cardona wrote:
> >> > How does userspace know when to authenticate with a new peer?
> >
> >> Authentication is triggered by the reception of a beacon or presp from
> >> a compatible mesh peer with security enabled.
> >
> > Ok ... so I read from this that it actually parses out the beacon frames
> > from scan results? It seems that it should rather signal beacon frames
> > for unknown peers to userspace somehow, so userspace doesn't have to
> > poll scan results?
>
> Discovery (and much more) on that prototype can certainly be improved.
> Not sure what you mean from "signal beacon frames
> for unknown peers" but yes, the current polled approach is probably
> not what we want. The mesh stack should trigger an event when a mesh
> beacon is received from a station that has not been created.

Right. But in any case, the secure flag doesn't really need to mean
"secure", it can simply mean "userspace manages stations". I was
thinking first that maybe there's something else that triggers this in a
secure case, but of course that can't be true since it's symmetric.

Therefore, I think we should allow userspace the flexibility to say it
manages stations even when the RSN information isn't there, no?

johannes


2011-03-18 20:22:54

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 0/5 v4] {mac|nl}80211: Support for SAE mesh authentication in userspace

This series adds support for SAE authentication of mesh peers in userspace. A
fork of wpa_supplicant that can authenticate mesh peers is available here:
https://github.com/cozybit/hostap-sae . Our intent is to work with hostap
maintainers to merge that functionality upstream soon.

A simpler daemon is also available here: https://github.com/cozybit/authsae.

They both require the changes proposed in this series to operate. Also, both
are based on the SAE reference implementation from Dan Harkins available here:
http://sourceforge.net/projects/authsae/

v2: (all suggested by Johannes)
- Userspace actually creates the stations instead of setting the AUTH flag.
- Fix hole that would allow peer links between secured and open peers.
- Pass multiple IEs through generic IE nl80211 attribute
- Remove SAE constant

v3: (again Johannes)
- Fix API backward compatibilty of NL80211_MESH_SETUP_IE
- Remove check for presence of RSN IE

v4: (also hinted by Johannes)
- New peer event to avoid having to scan for mesh peer candidates
- NEW_STATION command can also accept a PLINK_ACTION argument to
trigger or block peer link establishment immediately after an authenticated
station is created.

Javier Cardona (5):
mac80211: Enable mesh security from userspace
mac80211: Let user space receive and send mesh auth/deauth frames
mac80211: Accept mesh auth frames before a peer link has been
established
mac80211: Let userspace create stations when mesh security is enabled
mac80211: New notification to discover mesh peer candidates.

include/linux/nl80211.h | 27 +++++++++++++++++---
include/net/cfg80211.h | 39 +++++++++++++++++++++++++---
net/mac80211/cfg.c | 22 ++++++++++------
net/mac80211/ieee80211_i.h | 5 ++-
net/mac80211/main.c | 4 ++-
net/mac80211/mesh.c | 14 ++++++----
net/mac80211/mesh.h | 3 +-
net/mac80211/mesh_plink.c | 35 ++++++++++++++++++++-----
net/mac80211/rx.c | 3 +-
net/mac80211/tx.c | 2 +-
net/wireless/core.h | 6 ++++
net/wireless/mesh.c | 46 ++++++++++++++++++++++++++++++++-
net/wireless/nl80211.c | 60 +++++++++++++++++++++++++++++++++++++++----
net/wireless/nl80211.h | 4 +++
net/wireless/util.c | 5 +++
15 files changed, 232 insertions(+), 43 deletions(-)


2011-03-08 02:11:37

by Javier Cardona

[permalink] [raw]
Subject:

Johannes,

This is the peer discovery approach we had in mind. As you see this brings
back the use of the AUTHENTICATED flag. The idea is that unathenticated
stations are not considered new and won't trigger NEW_CANDIDATE notifications.

Suggestions appreciated.


2011-03-05 20:17:36

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 1/4 v3] mac80211: Enable mesh security from userspace

Userspace can enable mesh security by providing an RSN IE and setting
the MESH_SETUP_ENABLE_SECURITY flag.

Also, rename vendor_ie to just ie to reflect that the same attribute may
be used to pass other IEs, like for instance RSN.

Changes from v2: (from Johannes)
- Fix API backward compatibilty of NL80211_MESH_SETUP_IE
- Remove check for presence of RSN IE

Signed-off-by: Javier Cardona <[email protected]>
---
include/linux/nl80211.h | 13 +++++++++----
include/net/cfg80211.h | 10 ++++++----
net/mac80211/cfg.c | 16 ++++++++--------
net/mac80211/ieee80211_i.h | 5 +++--
net/mac80211/mesh.c | 6 +++---
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/tx.c | 2 +-
net/wireless/mesh.c | 5 +++--
net/wireless/nl80211.c | 39 ++++++++++++++++++++++++++++++++++-----
9 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 3002218..14a2a31 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -545,6 +545,7 @@ enum nl80211_commands {
/* source-level API compatibility */
#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE

/**
* enum nl80211_attrs - nl80211 netlink attributes
@@ -1686,9 +1687,12 @@ enum nl80211_meshconf_params {
* vendor specific path metric or disable it to use the default Airtime
* metric.
*
- * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information
- * element that vendors will use to identify the path selection methods and
- * metrics in use.
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_SECURITY: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
*
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -1697,7 +1701,8 @@ enum nl80211_mesh_setup_params {
__NL80211_MESH_SETUP_INVALID,
NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
- NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
+ NL80211_MESH_SETUP_IE,
+ NL80211_MESH_SETUP_ENABLE_SECURITY,

/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1ac5786..9610123 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -654,8 +654,9 @@ struct mesh_config {
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @path_sel_proto: which path selection protocol to use
* @path_metric: which metric to use
- * @vendor_ie: vendor information elements (optional)
- * @vendor_ie_len: length of vendor information elements
+ * @ie: vendor information elements (optional)
+ * @ie_len: length of vendor information elements
+ * @is_secure: or not
*
* These parameters are fixed when the mesh is created.
*/
@@ -664,8 +665,9 @@ struct mesh_setup {
u8 mesh_id_len;
u8 path_sel_proto;
u8 path_metric;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7b701dc..9270c03 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1019,26 +1019,26 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
u8 *new_ie;
const u8 *old_ie;

- /* first allocate the new vendor information element */
+ /* allocate information elements */
new_ie = NULL;
- old_ie = ifmsh->vendor_ie;
+ old_ie = ifmsh->ie;

- ifmsh->vendor_ie_len = setup->vendor_ie_len;
- if (setup->vendor_ie_len) {
- new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
+ ifmsh->ie_len = setup->ie_len;
+ if (setup->ie_len) {
+ new_ie = kmemdup(setup->ie, setup->ie_len,
GFP_KERNEL);
if (!new_ie)
return -ENOMEM;
}
+ ifmsh->ie = new_ie;
+ kfree(old_ie);

/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
- ifmsh->vendor_ie = new_ie;
-
- kfree(old_ie);
+ ifmsh->is_secure = setup->is_secure;

return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a404017..7d1cb36 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -488,8 +488,9 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2a57cc0..1c244c0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -279,9 +279,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;

- if (sdata->u.mesh.vendor_ie) {
- int len = sdata->u.mesh.vendor_ie_len;
- const u8 *data = sdata->u.mesh.vendor_ie;
+ if (sdata->u.mesh.ie) {
+ int len = sdata->u.mesh.ie_len;
+ const u8 *data = sdata->u.mesh.ie;
if (skb_tailroom(skb) > len)
memcpy(skb_put(skb, len), data, len);
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 44b5393..c705b20 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
__le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 081dcaf..38f6c2d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2262,7 +2262,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,

/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
if (!skb)
goto out;

diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 73e39c1..c51e3c5 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -53,8 +53,9 @@ const struct mesh_config default_mesh_config = {
const struct mesh_setup default_mesh_setup = {
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
- .vendor_ie = NULL,
- .vendor_ie_len = 0,
+ .ie = NULL,
+ .ie_len = 0,
+ .is_secure = false,
};

int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4ebce42..cc1ee41 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2804,7 +2828,8 @@ static const struct nla_policy
nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
- [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY,
+ [NL80211_MESH_SETUP_ENABLE_SECURITY] = { .type = NLA_FLAG },
+ [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
};

@@ -2906,13 +2931,15 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
IEEE80211_PATH_METRIC_VENDOR :
IEEE80211_PATH_METRIC_AIRTIME;

- if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) {
+
+ if (tb[NL80211_MESH_SETUP_IE]) {
struct nlattr *ieattr =
- tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
+ tb[NL80211_MESH_SETUP_IE];
if (!is_valid_ie_attr(ieattr))
return -EINVAL;
- setup->vendor_ie = nla_data(ieattr);
- setup->vendor_ie_len = nla_len(ieattr);
+ setup->ie = nla_data(ieattr);
+ setup->ie_len = nla_len(ieattr);
}
+ setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_ENABLE_SECURITY]);

return 0;
--
1.7.1


2011-03-05 20:02:18

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

On Sat, Mar 5, 2011 at 11:50 AM, Johannes Berg
<[email protected]> wrote:
> On Sat, 2011-03-05 at 11:40 -0800, Javier Cardona wrote:
>> On Sat, Mar 5, 2011 at 6:06 AM, Johannes Berg <[email protected]> wrote:
>> > I have a more generic question since I haven't seen the userspace bits:
>
>> There's a working prototype here:
>> https://github.com/cozybit/authsae/blob/master/linux/meshd-nl80211.c
>> The intent is to merge that functionality into wpa_supplicant at some point.
>>
>> > How does userspace know when to authenticate with a new peer?
>
>> Authentication is triggered by the reception of a beacon or presp from
>> a compatible mesh peer with security enabled.
>
> Ok ... so I read from this that it actually parses out the beacon frames
> from scan results? It seems that it should rather signal beacon frames
> for unknown peers to userspace somehow, so userspace doesn't have to
> poll scan results?

Discovery (and much more) on that prototype can certainly be improved.
Not sure what you mean from "signal beacon frames
for unknown peers" but yes, the current polled approach is probably
not what we want. The mesh stack should trigger an event when a mesh
beacon is received from a station that has not been created.

--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-05 14:01:46

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 4/4 v2] mac80211: Let userspace create stations when mesh security is enabled

On Fri, 2011-03-04 at 17:24 -0800, Thomas Pedersen wrote:

> +++ b/net/mac80211/mesh_plink.c
> @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
> if (!sta)
> return NULL;
>
> - sta->flags = WLAN_STA_AUTHORIZED;
> + sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
> sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
> rate_control_rate_init(sta);

This is just for consistency now, right? The AUTH flag isn't tested, but
stations from userspace will have it set, afaiu?

johannes


2011-03-05 01:25:25

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 1/4 v2] mac80211: Enable mesh security from userspace

From: Javier Cardona <[email protected]>

Userspace can enable mesh security by providing an RSN IE and setting
the MESH_SETUP_ENABLE_SECURITY flag.

Also, rename vendor_ie to just ie to reflect that the same attribute may
be used to pass other IEs, like for instance RSN.

Signed-off-by: Javier Cardona <[email protected]>
---
include/linux/nl80211.h | 13 +++++++++----
include/net/cfg80211.h | 10 ++++++----
net/mac80211/cfg.c | 16 ++++++++--------
net/mac80211/ieee80211_i.h | 5 +++--
net/mac80211/mesh.c | 6 +++---
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/tx.c | 2 +-
net/wireless/mesh.c | 5 +++--
net/wireless/nl80211.c | 39 ++++++++++++++++++++++++++++++++++-----
9 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 3002218..14a2a31 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -545,6 +545,7 @@ enum nl80211_commands {
/* source-level API compatibility */
#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_IE NL80211_MESH_SETUP_IE

/**
* enum nl80211_attrs - nl80211 netlink attributes
@@ -1686,9 +1687,12 @@ enum nl80211_meshconf_params {
* vendor specific path metric or disable it to use the default Airtime
* metric.
*
- * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information
- * element that vendors will use to identify the path selection methods and
- * metrics in use.
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_SECURITY: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
*
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -1697,7 +1701,8 @@ enum nl80211_mesh_setup_params {
__NL80211_MESH_SETUP_INVALID,
NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
- NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
+ NL80211_MESH_SETUP_IE,
+ NL80211_MESH_SETUP_ENABLE_SECURITY,

/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1ac5786..9610123 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -654,8 +654,9 @@ struct mesh_config {
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @path_sel_proto: which path selection protocol to use
* @path_metric: which metric to use
- * @vendor_ie: vendor information elements (optional)
- * @vendor_ie_len: length of vendor information elements
+ * @ie: vendor information elements (optional)
+ * @ie_len: length of vendor information elements
+ * @is_secure: or not
*
* These parameters are fixed when the mesh is created.
*/
@@ -664,8 +665,9 @@ struct mesh_setup {
u8 mesh_id_len;
u8 path_sel_proto;
u8 path_metric;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7b701dc..9270c03 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1019,26 +1019,26 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
u8 *new_ie;
const u8 *old_ie;

- /* first allocate the new vendor information element */
+ /* allocate information elements */
new_ie = NULL;
- old_ie = ifmsh->vendor_ie;
+ old_ie = ifmsh->ie;

- ifmsh->vendor_ie_len = setup->vendor_ie_len;
- if (setup->vendor_ie_len) {
- new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
+ ifmsh->ie_len = setup->ie_len;
+ if (setup->ie_len) {
+ new_ie = kmemdup(setup->ie, setup->ie_len,
GFP_KERNEL);
if (!new_ie)
return -ENOMEM;
}
+ ifmsh->ie = new_ie;
+ kfree(old_ie);

/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
- ifmsh->vendor_ie = new_ie;
-
- kfree(old_ie);
+ ifmsh->is_secure = setup->is_secure;

return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a404017..7d1cb36 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -488,8 +488,9 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2a57cc0..1c244c0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -279,9 +279,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;

- if (sdata->u.mesh.vendor_ie) {
- int len = sdata->u.mesh.vendor_ie_len;
- const u8 *data = sdata->u.mesh.vendor_ie;
+ if (sdata->u.mesh.ie) {
+ int len = sdata->u.mesh.ie_len;
+ const u8 *data = sdata->u.mesh.ie;
if (skb_tailroom(skb) > len)
memcpy(skb_put(skb, len), data, len);
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 44b5393..c705b20 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
__le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 081dcaf..38f6c2d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2262,7 +2262,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,

/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
if (!skb)
goto out;

diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 73e39c1..c51e3c5 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -53,8 +53,9 @@ const struct mesh_config default_mesh_config = {
const struct mesh_setup default_mesh_setup = {
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
- .vendor_ie = NULL,
- .vendor_ie_len = 0,
+ .ie = NULL,
+ .ie_len = 0,
+ .is_secure = false,
};

int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4ebce42..cc1ee41 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -284,6 +284,30 @@ static bool is_valid_ie_attr(const struct nlattr *attr)
return true;
}

+/* Check that an assumed valid IE attribute contains the given element ID */
+static bool eid_in_ie_attr(const struct nlattr *attr, u8 eid)
+{
+ const u8 *pos;
+ int len;
+
+ pos = nla_data(attr);
+ len = nla_len(attr);
+
+ while (len) {
+ u8 elemlen;
+ len -= 2;
+
+ if (pos[0] == eid)
+ return true;
+
+ elemlen = pos[1];
+ len -= elemlen;
+ pos += 2 + elemlen;
+ }
+
+ return false;
+}
+
/* message building helper */
static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
int flags, u8 cmd)
@@ -2804,7 +2828,8 @@ static const struct nla_policy
nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
- [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY,
+ [NL80211_MESH_SETUP_ENABLE_SECURITY] = { .type = NLA_FLAG },
+ [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
};

@@ -2906,13 +2931,17 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
IEEE80211_PATH_METRIC_VENDOR :
IEEE80211_PATH_METRIC_AIRTIME;

- if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) {
+
+ if (tb[NL80211_MESH_SETUP_IE]) {
struct nlattr *ieattr =
- tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
+ tb[NL80211_MESH_SETUP_IE];
if (!is_valid_ie_attr(ieattr))
return -EINVAL;
- setup->vendor_ie = nla_data(ieattr);
- setup->vendor_ie_len = nla_len(ieattr);
+ setup->ie = nla_data(ieattr);
+ setup->ie_len = nla_len(ieattr);
+ if (eid_in_ie_attr(ieattr, WLAN_EID_RSN))
+ setup->is_secure =
+ nla_get_flag(tb[NL80211_MESH_SETUP_ENABLE_SECURITY]);
}

return 0;
--
1.7.1


2011-03-05 01:25:30

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 2/4 v2] mac80211: Let user space receive and send mesh auth/deauth frames

From: Javier Cardona <[email protected]>


Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/main.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 2543e48..bff7237 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -542,7 +542,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_MESH_POINT] = {
.tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4),
},
};

--
1.7.1


2011-03-05 19:35:20

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 1/4 v2] mac80211: Enable mesh security from userspace

On Sat, Mar 5, 2011 at 6:05 AM, Johannes Berg <[email protected]> wrote:
> On Fri, 2011-03-04 at 17:24 -0800, Thomas Pedersen wrote:
>
>
>> +#define NL80211_MESH_SETUP_VENDOR_IE NL80211_MESH_SETUP_IE
>
>> - ? ? NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
>> + ? ? NL80211_MESH_SETUP_IE,
>> + ? ? NL80211_MESH_SETUP_ENABLE_SECURITY,
>
> Clearly the intent was to be API compatible (ABI is guaranteed anyway),
> but that seems to not work this way since the names don't match.

Ouch, you are right. Should have been
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
We'll send a fixup.

>> + ? ? if (tb[NL80211_MESH_SETUP_IE]) {
>> ? ? ? ? ? ? ? struct nlattr *ieattr =
>> - ? ? ? ? ? ? ? ? ? ? tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
>> + ? ? ? ? ? ? ? ? ? ? tb[NL80211_MESH_SETUP_IE];
>> ? ? ? ? ? ? ? if (!is_valid_ie_attr(ieattr))
>> ? ? ? ? ? ? ? ? ? ? ? return -EINVAL;
>> - ? ? ? ? ? ? setup->vendor_ie = nla_data(ieattr);
>> - ? ? ? ? ? ? setup->vendor_ie_len = nla_len(ieattr);
>> + ? ? ? ? ? ? setup->ie = nla_data(ieattr);
>> + ? ? ? ? ? ? setup->ie_len = nla_len(ieattr);
>> + ? ? ? ? ? ? if (eid_in_ie_attr(ieattr, WLAN_EID_RSN))
>> + ? ? ? ? ? ? ? ? ? ? setup->is_secure =
>> + ? ? ? ? ? ? ? ? ? ? nla_get_flag(tb[NL80211_MESH_SETUP_ENABLE_SECURITY]);
>
> That last check seems a bit pointless -- I'd trust userspace (aka allow
> it to shoot itself in the foot) and not check that there's RSN
> information when it says it wants security -- maybe WAPI will come up
> with mesh security at some point ;-)

Enabling security without an RSN will result in mesh node that can't
communicate with anyone in the mesh, secured or not. I prefer
keeping that check in place to avoid annoying misconfigurations. You
still think it's pointless? (In fact I was contemplating a more
strict check by returning EINVAL instead of ignoring the request when
userspace enables security and does not pass an RSN.)

--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-22 21:42:07

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 5/5 v4] mac80211: New notification to discover mesh peer candidates.

On Fri, 2011-03-18 at 13:22 -0700, Javier Cardona wrote:

> @@ -1170,6 +1182,7 @@ enum nl80211_iftype {
> * @NL80211_STA_FLAG_WME: station is WME/QoS capable
> * @NL80211_STA_FLAG_MFP: station uses management frame protection
> * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
> + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
> * @__NL80211_STA_FLAG_AFTER_LAST: internal use

This looks a little odd, but doesn't really matter.


> +void cfg80211_notify_new_peer_candidate(struct net_device *dev,
> + const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
> +{
> + struct wireless_dev *wdev = dev->ieee80211_ptr;
> + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
> + struct cfg80211_event *ev;
> + unsigned long flags;
> +
> + ev = kzalloc(sizeof(*ev), gfp);
> + if (!ev)
> + return;
> + ev->type = EVENT_NEW_CANDIDATE;
> + memcpy(ev->nc.macaddr, macaddr, ETH_ALEN);
> + if (ie_len && ie) {
> + ev->nc.ie = kmemdup(ie, ie_len, gfp);
> + ev->nc.ie_len = (ev->nc.ie) ? ie_len : 0;
> + }
> +
> + spin_lock_irqsave(&wdev->event_lock, flags);
> + list_add_tail(&ev->list, &wdev->event_list);
> + spin_unlock_irqrestore(&wdev->event_lock, flags);
> + queue_work(cfg80211_wq, &rdev->event_work);

Why schedule out here and all the complexity with that? Seems pointless,
just pass the gfp through to nl80211?


Also, this changes the APIs again. Do you think you could collect the
API changes into a separate patch and combine them in nl80211/cfg80211?

johannes


2011-03-18 20:23:12

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 4/5 v4] mac80211: Let userspace create stations when mesh security is enabled

Userspace can enable mesh security via the new
MESH_SETUP_ENABLE_SECURITY flag and by providing an RSN information
element. When that happens, the mesh stack will delegate station
management to userspace.

Signed-off-by: Javier Cardona <[email protected]>
Tested-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh.c | 4 ++++
net/mac80211/mesh_plink.c | 11 ++++++++---
net/wireless/nl80211.c | 1 +
3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 1c244c0..47a26c0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -573,6 +573,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);

+ /* ignore beacons from secure mesh peers if our security is off */
+ if (elems.rsn_len && !sdata->u.mesh.is_secure)
+ return;
+
if (elems.ds_params && elems.ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
else
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c705b20..b4b1c53 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;

- sta->flags = WLAN_STA_AUTHORIZED;
+ sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta);

@@ -248,8 +248,9 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta = sta_info_get(sdata, hw_addr);
if (!sta) {
rcu_read_unlock();
-
- sta = mesh_plink_alloc(sdata, hw_addr, rates);
+ /* Userspace handles peer allocation when security is enabled */
+ if (!sdata->u.mesh.is_secure)
+ sta = mesh_plink_alloc(sdata, hw_addr, rates);
if (!sta)
return;
if (sta_info_insert_rcu(sta)) {
@@ -449,6 +450,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return;
}
+ if (elems.rsn_len && !sdata->u.mesh.is_secure) {
+ mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+ return;
+ }

ftype = mgmt->u.action.u.plink_action.action_code;
ie_len = elems.peer_link_len;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a45c12c..316e08f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2329,6 +2329,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)

if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EINVAL;

--
1.7.1


2011-03-18 20:23:10

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 3/5 v4] mac80211: Accept mesh auth frames before a peer link has been established


Signed-off-by: Javier Cardona <[email protected]>
Tested-by: Thomas Pedersen <[email protected]>
---
net/mac80211/rx.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5c1930b..fe0f1e3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -502,7 +502,8 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)

if (ieee80211_is_probe_req(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control) ||
- ieee80211_is_beacon(hdr->frame_control))
+ ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control))
return RX_CONTINUE;

return RX_DROP_MONITOR;
--
1.7.1


2011-03-05 19:40:54

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

On Sat, Mar 5, 2011 at 6:06 AM, Johannes Berg <[email protected]> wrote:
> I have a more generic question since I haven't seen the userspace bits:
There's a working prototype here:
https://github.com/cozybit/authsae/blob/master/linux/meshd-nl80211.c
The intent is to merge that functionality into wpa_supplicant at some point.

> How does userspace know when to authenticate with a new peer?
Authentication is triggered by the reception of a beacon or presp from
a compatible mesh peer with security enabled.

--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-05 01:25:44

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 4/4 v2] mac80211: Let userspace create stations when mesh security is enabled

From: Javier Cardona <[email protected]>

Userspace can enable mesh security via the new
MESH_SETUP_ENABLE_SECURITY flag and by providing an RSN information
element. When that happens, the mesh stack will delegate station
management to userspace.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh.c | 4 ++++
net/mac80211/mesh_plink.c | 11 ++++++++---
net/wireless/nl80211.c | 1 +
3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 1c244c0..47a26c0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -573,6 +573,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);

+ /* ignore beacons from secure mesh peers if our security is off */
+ if (elems.rsn_len && !sdata->u.mesh.is_secure)
+ return;
+
if (elems.ds_params && elems.ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
else
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c705b20..b4b1c53 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;

- sta->flags = WLAN_STA_AUTHORIZED;
+ sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta);

@@ -248,8 +248,9 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta = sta_info_get(sdata, hw_addr);
if (!sta) {
rcu_read_unlock();
-
- sta = mesh_plink_alloc(sdata, hw_addr, rates);
+ /* Userspace handles peer allocation when security is enabled */
+ if (!sdata->u.mesh.is_secure)
+ sta = mesh_plink_alloc(sdata, hw_addr, rates);
if (!sta)
return;
if (sta_info_insert_rcu(sta)) {
@@ -449,6 +450,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return;
}
+ if (elems.rsn_len && !sdata->u.mesh.is_secure) {
+ mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+ return;
+ }

ftype = mgmt->u.action.u.plink_action.action_code;
ie_len = elems.peer_link_len;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cc1ee41..8a8518f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2353,6 +2353,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)

if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EINVAL;

--
1.7.1


2011-03-08 02:11:42

by Javier Cardona

[permalink] [raw]
Subject: [RFC] mac80211: New notification to discover mesh peer candidates.

Notify userspace when a beacon/presp is received from a suitable mesh
peer candidate for whom no sta information exists. Userspace can then
decide to create a sta info for the candidate. If userspace is not
ready to authenticate the peer right away, it can create the sta info
with the authenticated flag unset and set it later.

Also, modify the NEW_STATION command to accept PLINK_ACTIONS, in case
userspace wants to create stations and initiate a peer link right away
(for authenticated stations) or create a blocked station (for
debugging?).
---
include/linux/nl80211.h | 14 +++++++++++++
include/net/cfg80211.h | 29 ++++++++++++++++++++++++++++
net/mac80211/cfg.c | 6 +++++
net/mac80211/mesh.c | 4 +--
net/mac80211/mesh.h | 3 +-
net/mac80211/mesh_plink.c | 26 ++++++++++++++++++++----
net/wireless/core.h | 6 +++++
net/wireless/mesh.c | 41 ++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-
net/wireless/nl80211.h | 4 +++
net/wireless/util.c | 5 ++++
11 files changed, 174 insertions(+), 10 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f1bfa88..aa5e465 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,16 @@
* notification. This event is used to indicate that an unprotected
* disassociation frame was dropped when MFP is in use.
*
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ * beacon or probe response from a compatible mesh peer. This is only
+ * sent while no station information (sta_info) exists for the new peer
+ * candidate and when @NL80211_MESH_SETUP_ENABLE_SECURITY is set. On
+ * reception of this notification, userspace may decide to create a new
+ * station (@NL80211_CMD_NEW_STATION). To stop this notification from
+ * reoccurring, the userspace authentication daemon may want to create the
+ * new station with the AUTHENTICATED flag unset and maybe change it later
+ * depending on the authentication result.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -522,6 +532,8 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_DEAUTHENTICATE,
NL80211_CMD_UNPROT_DISASSOCIATE,

+ NL80211_CMD_NEW_PEER_CANDIDATE,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -1170,6 +1182,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
enum nl80211_sta_flags {
@@ -1178,6 +1191,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_SHORT_PREAMBLE,
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
+ NL80211_STA_FLAG_AUTHENTICATED,

/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9610123..1e7b007 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2443,6 +2443,35 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);

/**
+ * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
+ *
+ * @dev: network device
+ * @macaddr: the MAC address of the new candidate
+ * @ie: information elements advertised by the peer candidate
+ * @ie_len: lenght of the information elements buffer
+ * @gfp: allocation flags
+ *
+ * This function notifies cfg80211 that the mesh peer candidate has been
+ * detected, most likely via a beacon or, less likely, via a probe response.
+ * cfg80211 then sends a notification to userspace.
+ */
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp);
+
+/**
+ * __cfg80211_notify_new_candidate - see cfg80211_notify_new_candidate
+ *
+ * @dev: network device
+ * @macaddr: the MAC address of the new candidate
+ * @ie: information elements advertised by the peer candidate
+ * @ie_len: lenght of the information elements buffer
+ *
+ * Like cfg80211_notify_new_candidate(), but doesn't take the wdev lock.
+ */
+void __cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8 *ie, u8 ie_len);
+
+/**
* DOC: RFkill integration
*
* RFkill integration in cfg80211 is almost invisible to drivers,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9270c03..c8b87f7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -675,6 +675,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
}
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
+ sta->flags &= ~WLAN_STA_AUTH;
+ if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ sta->flags |= WLAN_STA_AUTH;
+ }
spin_unlock_irqrestore(&sta->flaglock, flags);

/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 47a26c0..1120797 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -590,9 +590,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (elems.mesh_id && elems.mesh_config &&
mesh_matches_local(&elems, sdata)) {
supp_rates = ieee80211_sta_get_rates(local, &elems, band);
-
- mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
- mesh_peer_accepts_plinks(&elems));
+ mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
}
}

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index b99e230..10acf1c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -226,7 +226,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
- struct ieee80211_sub_if_data *sdata, bool add);
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index b4b1c53..3e269dd 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -237,8 +237,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
return 0;
}

-void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
- bool peer_accepting_plinks)
+void mesh_neighbour_update(u8 *hw_addr, u32 rates,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -248,8 +249,13 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta = sta_info_get(sdata, hw_addr);
if (!sta) {
rcu_read_unlock();
- /* Userspace handles peer allocation when security is enabled */
- if (!sdata->u.mesh.is_secure)
+ /* Userspace handles peer allocation when security is enabled
+ * */
+ if (sdata->u.mesh.is_secure)
+ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+ elems->ie_start, elems->total_len,
+ GFP_KERNEL);
+ else
sta = mesh_plink_alloc(sdata, hw_addr, rates);
if (!sta)
return;
@@ -261,7 +267,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data

sta->last_rx = jiffies;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
- if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+ if (mesh_peer_accepts_plinks(elems) &&
+ sta->plink_state == PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
@@ -373,6 +380,9 @@ int mesh_plink_open(struct sta_info *sta)
__le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;

+ if (!test_sta_flags(sta, WLAN_STA_AUTH))
+ return -EPERM;
+
spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
@@ -485,6 +495,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
}

+ if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+ mpl_dbg("Mesh plink: Action frame from non-authenticated peer\n");
+ rcu_read_unlock();
+ return;
+ }
+
if (sta && sta->plink_state == PLINK_BLOCKED) {
rcu_read_unlock();
return;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 26a0a08..5ee28ae 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -213,6 +213,7 @@ enum cfg80211_event_type {
EVENT_ROAMED,
EVENT_DISCONNECTED,
EVENT_IBSS_JOINED,
+ EVENT_NEW_CANDIDATE,
};

struct cfg80211_event {
@@ -243,6 +244,11 @@ struct cfg80211_event {
struct {
u8 bssid[ETH_ALEN];
} ij;
+ struct {
+ u8 macaddr[ETH_ALEN];
+ const u8 *ie;
+ size_t ie_len;
+ } nc;
};
};

diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index c51e3c5..2e9b120 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -1,5 +1,6 @@
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
+#include "nl80211.h"
#include "core.h"

/* Default values, timeouts in ms */
@@ -106,6 +107,46 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
return err;
}

+void __cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8* macaddr, const u8* ie, u8 ie_len)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+ return;
+
+ nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
+ macaddr, ie, ie_len, GFP_KERNEL);
+ kfree(ie);
+}
+
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8* macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev), gfp);
+ if (!ev)
+ return;
+ ev->type = EVENT_NEW_CANDIDATE;
+ memcpy(ev->nc.macaddr, macaddr, ETH_ALEN);
+ if (ie_len && ie) {
+ ev->nc.ie = kmemdup(ie, ie_len, gfp);
+ ev->nc.ie_len = (ev->nc.ie) ? ie_len : 0;
+ }
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ queue_work(cfg80211_wq, &rdev->event_work);
+
+ return;
+}
+EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
+
static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 316e08f..8e8f5a1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1922,6 +1922,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
};

static int parse_station_flags(struct genl_info *info,
@@ -2262,7 +2263,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
if (params.supported_rates)
err = -EINVAL;
- if (params.sta_flags_mask)
+ if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHENTICATED))
err = -EINVAL;
break;
default:
@@ -2324,6 +2325,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);

+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ params.plink_action =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
if (parse_station_flags(info, &params))
return -EINVAL;

@@ -5789,6 +5794,45 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}

+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8* macaddr, const u8* ie, u8 ie_len,
+ gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr);
+ if (ie_len && ie) {
+ NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
+ }
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e3f7fa8..9fd1499 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -50,6 +50,10 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u16 reason,
const u8 *ie, size_t ie_len, bool from_ap);

+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8* macaddr, const u8* ie, u8 ie_len,
+ gfp_t gfp);
void
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6a750bc..33b9ccc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -753,6 +753,11 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
break;
+ case EVENT_NEW_CANDIDATE:
+ __cfg80211_notify_new_peer_candidate(wdev->netdev,
+ ev->nc.macaddr, ev->nc.ie,
+ ev->nc.ie_len);
+ break;
}
wdev_unlock(wdev);

--
1.7.1


2011-03-05 14:05:24

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/4 v2] mac80211: Enable mesh security from userspace

On Fri, 2011-03-04 at 17:24 -0800, Thomas Pedersen wrote:


> +#define NL80211_MESH_SETUP_VENDOR_IE NL80211_MESH_SETUP_IE

> - NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
> + NL80211_MESH_SETUP_IE,
> + NL80211_MESH_SETUP_ENABLE_SECURITY,

Clearly the intent was to be API compatible (ABI is guaranteed anyway),
but that seems to not work this way since the names don't match.

> + if (tb[NL80211_MESH_SETUP_IE]) {
> struct nlattr *ieattr =
> - tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
> + tb[NL80211_MESH_SETUP_IE];
> if (!is_valid_ie_attr(ieattr))
> return -EINVAL;
> - setup->vendor_ie = nla_data(ieattr);
> - setup->vendor_ie_len = nla_len(ieattr);
> + setup->ie = nla_data(ieattr);
> + setup->ie_len = nla_len(ieattr);
> + if (eid_in_ie_attr(ieattr, WLAN_EID_RSN))
> + setup->is_secure =
> + nla_get_flag(tb[NL80211_MESH_SETUP_ENABLE_SECURITY]);

That last check seems a bit pointless -- I'd trust userspace (aka allow
it to shoot itself in the foot) and not check that there's RSN
information when it says it wants security -- maybe WAPI will come up
with mesh security at some point ;-)

johannes


2011-03-08 15:10:07

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC] mac80211: New notification to discover mesh peer candidates.

On Mon, 2011-03-07 at 18:11 -0800, Javier Cardona wrote:
> Notify userspace when a beacon/presp is received from a suitable mesh
> peer candidate for whom no sta information exists. Userspace can then
> decide to create a sta info for the candidate. If userspace is not
> ready to authenticate the peer right away, it can create the sta info
> with the authenticated flag unset and set it later.

I'm a little worried about this creating lots of bogus stations if
somebody is attacking the mesh. Will that be relevant? Would it be
better to just pass up any beacon that matches the mesh ID, trading CPU
resources for memory?

Also, this goes back to the "authenticate station" rather than full
station management in userspace, right?

johannes


2011-03-18 20:23:05

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 1/5 v4] mac80211: Enable mesh security from userspace

Userspace can enable mesh security by providing an RSN IE and setting
the MESH_SETUP_ENABLE_SECURITY flag.

Also, rename vendor_ie to just ie to reflect that the same attribute may
be used to pass other IEs, like for instance RSN.

Signed-off-by: Javier Cardona <[email protected]>
Tested-by: Thomas Pedersen <[email protected]>
---
include/linux/nl80211.h | 13 +++++++++----
include/net/cfg80211.h | 10 ++++++----
net/mac80211/cfg.c | 16 ++++++++--------
net/mac80211/ieee80211_i.h | 5 +++--
net/mac80211/mesh.c | 6 +++---
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/tx.c | 2 +-
net/wireless/mesh.c | 5 +++--
net/wireless/nl80211.c | 13 ++++++++-----
9 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 3002218..f1bfa88 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -545,6 +545,7 @@ enum nl80211_commands {
/* source-level API compatibility */
#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE

/**
* enum nl80211_attrs - nl80211 netlink attributes
@@ -1686,9 +1687,12 @@ enum nl80211_meshconf_params {
* vendor specific path metric or disable it to use the default Airtime
* metric.
*
- * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information
- * element that vendors will use to identify the path selection methods and
- * metrics in use.
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_SECURITY: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
*
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -1697,7 +1701,8 @@ enum nl80211_mesh_setup_params {
__NL80211_MESH_SETUP_INVALID,
NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
- NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
+ NL80211_MESH_SETUP_IE,
+ NL80211_MESH_SETUP_ENABLE_SECURITY,

/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 60f7876..2334985 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -654,8 +654,9 @@ struct mesh_config {
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @path_sel_proto: which path selection protocol to use
* @path_metric: which metric to use
- * @vendor_ie: vendor information elements (optional)
- * @vendor_ie_len: length of vendor information elements
+ * @ie: vendor information elements (optional)
+ * @ie_len: length of vendor information elements
+ * @is_secure: or not
*
* These parameters are fixed when the mesh is created.
*/
@@ -664,8 +665,9 @@ struct mesh_setup {
u8 mesh_id_len;
u8 path_sel_proto;
u8 path_metric;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3342135..4f73085 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1023,26 +1023,26 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
u8 *new_ie;
const u8 *old_ie;

- /* first allocate the new vendor information element */
+ /* allocate information elements */
new_ie = NULL;
- old_ie = ifmsh->vendor_ie;
+ old_ie = ifmsh->ie;

- ifmsh->vendor_ie_len = setup->vendor_ie_len;
- if (setup->vendor_ie_len) {
- new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
+ ifmsh->ie_len = setup->ie_len;
+ if (setup->ie_len) {
+ new_ie = kmemdup(setup->ie, setup->ie_len,
GFP_KERNEL);
if (!new_ie)
return -ENOMEM;
}
+ ifmsh->ie = new_ie;
+ kfree(old_ie);

/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
- ifmsh->vendor_ie = new_ie;
-
- kfree(old_ie);
+ ifmsh->is_secure = setup->is_secure;

return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a404017..7d1cb36 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -488,8 +488,9 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
- const u8 *vendor_ie;
- u8 vendor_ie_len;
+ const u8 *ie;
+ u8 ie_len;
+ bool is_secure;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 2a57cc0..1c244c0 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -279,9 +279,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;

- if (sdata->u.mesh.vendor_ie) {
- int len = sdata->u.mesh.vendor_ie_len;
- const u8 *data = sdata->u.mesh.vendor_ie;
+ if (sdata->u.mesh.ie) {
+ int len = sdata->u.mesh.ie_len;
+ const u8 *data = sdata->u.mesh.ie;
if (skb_tailroom(skb) > len)
memcpy(skb_put(skb, len), data, len);
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 44b5393..c705b20 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
__le16 reason) {
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 081dcaf..38f6c2d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2262,7 +2262,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,

/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400 +
- sdata->u.mesh.vendor_ie_len);
+ sdata->u.mesh.ie_len);
if (!skb)
goto out;

diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 73e39c1..c51e3c5 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -53,8 +53,9 @@ const struct mesh_config default_mesh_config = {
const struct mesh_setup default_mesh_setup = {
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
- .vendor_ie = NULL,
- .vendor_ie_len = 0,
+ .ie = NULL,
+ .ie_len = 0,
+ .is_secure = false,
};

int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4ebce42..a45c12c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2804,7 +2804,8 @@ static const struct nla_policy
nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
- [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY,
+ [NL80211_MESH_SETUP_ENABLE_SECURITY] = { .type = NLA_FLAG },
+ [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
};

@@ -2906,14 +2907,16 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
IEEE80211_PATH_METRIC_VENDOR :
IEEE80211_PATH_METRIC_AIRTIME;

- if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) {
+
+ if (tb[NL80211_MESH_SETUP_IE]) {
struct nlattr *ieattr =
- tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
+ tb[NL80211_MESH_SETUP_IE];
if (!is_valid_ie_attr(ieattr))
return -EINVAL;
- setup->vendor_ie = nla_data(ieattr);
- setup->vendor_ie_len = nla_len(ieattr);
+ setup->ie = nla_data(ieattr);
+ setup->ie_len = nla_len(ieattr);
}
+ setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_ENABLE_SECURITY]);

return 0;
}
--
1.7.1


2011-03-18 20:23:15

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 5/5 v4] mac80211: New notification to discover mesh peer candidates.

Notify userspace when a beacon/presp is received from a suitable mesh
peer candidate for whom no sta information exists. Userspace can then
decide to create a sta info for the candidate. If userspace is not
ready to authenticate the peer right away, it can create the sta info
with the authenticated flag unset and set it later.

Also, modify the NEW_STATION command to accept PLINK_ACTIONS, in case
userspace wants to create stations and initiate a peer link right away
(for authenticated stations) or create a blocked station (for
debugging).

Signed-off-by: Javier Cardona <[email protected]>
Tested-by: Thomas Pedersen <[email protected]>
---
include/linux/nl80211.h | 14 +++++++++++++
include/net/cfg80211.h | 29 ++++++++++++++++++++++++++++
net/mac80211/cfg.c | 6 +++++
net/mac80211/mesh.c | 4 +--
net/mac80211/mesh.h | 3 +-
net/mac80211/mesh_plink.c | 26 ++++++++++++++++++++----
net/wireless/core.h | 6 +++++
net/wireless/mesh.c | 41 ++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-
net/wireless/nl80211.h | 4 +++
net/wireless/util.c | 5 ++++
11 files changed, 174 insertions(+), 10 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f1bfa88..aa5e465 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,16 @@
* notification. This event is used to indicate that an unprotected
* disassociation frame was dropped when MFP is in use.
*
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ * beacon or probe response from a compatible mesh peer. This is only
+ * sent while no station information (sta_info) exists for the new peer
+ * candidate and when @NL80211_MESH_SETUP_ENABLE_SECURITY is set. On
+ * reception of this notification, userspace may decide to create a new
+ * station (@NL80211_CMD_NEW_STATION). To stop this notification from
+ * reoccurring, the userspace authentication daemon may want to create the
+ * new station with the AUTHENTICATED flag unset and maybe change it later
+ * depending on the authentication result.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -522,6 +532,8 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_DEAUTHENTICATE,
NL80211_CMD_UNPROT_DISASSOCIATE,

+ NL80211_CMD_NEW_PEER_CANDIDATE,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -1170,6 +1182,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
enum nl80211_sta_flags {
@@ -1178,6 +1191,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_SHORT_PREAMBLE,
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
+ NL80211_STA_FLAG_AUTHENTICATED,

/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2334985..e4453c2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2451,6 +2451,35 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);

/**
+ * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
+ *
+ * @dev: network device
+ * @macaddr: the MAC address of the new candidate
+ * @ie: information elements advertised by the peer candidate
+ * @ie_len: lenght of the information elements buffer
+ * @gfp: allocation flags
+ *
+ * This function notifies cfg80211 that the mesh peer candidate has been
+ * detected, most likely via a beacon or, less likely, via a probe response.
+ * cfg80211 then sends a notification to userspace.
+ */
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp);
+
+/**
+ * __cfg80211_notify_new_candidate - see cfg80211_notify_new_candidate
+ *
+ * @dev: network device
+ * @macaddr: the MAC address of the new candidate
+ * @ie: information elements advertised by the peer candidate
+ * @ie_len: lenght of the information elements buffer
+ *
+ * Like cfg80211_notify_new_candidate(), but doesn't take the wdev lock.
+ */
+void __cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8 *ie, u8 ie_len);
+
+/**
* DOC: RFkill integration
*
* RFkill integration in cfg80211 is almost invisible to drivers,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4f73085..c57d653 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -675,6 +675,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
}
+
+ if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
+ sta->flags &= ~WLAN_STA_AUTH;
+ if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
+ sta->flags |= WLAN_STA_AUTH;
+ }
spin_unlock_irqrestore(&sta->flaglock, flags);

/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 47a26c0..1120797 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -590,9 +590,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (elems.mesh_id && elems.mesh_config &&
mesh_matches_local(&elems, sdata)) {
supp_rates = ieee80211_sta_get_rates(local, &elems, band);
-
- mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
- mesh_peer_accepts_plinks(&elems));
+ mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems);
}
}

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index b99e230..10acf1c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -226,7 +226,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
- struct ieee80211_sub_if_data *sdata, bool add);
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index b4b1c53..84e5b05 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -237,8 +237,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
return 0;
}

-void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
- bool peer_accepting_plinks)
+void mesh_neighbour_update(u8 *hw_addr, u32 rates,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
@@ -248,8 +249,13 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
sta = sta_info_get(sdata, hw_addr);
if (!sta) {
rcu_read_unlock();
- /* Userspace handles peer allocation when security is enabled */
- if (!sdata->u.mesh.is_secure)
+ /* Userspace handles peer allocation when security is enabled
+ * */
+ if (sdata->u.mesh.is_secure)
+ cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+ elems->ie_start, elems->total_len,
+ GFP_KERNEL);
+ else
sta = mesh_plink_alloc(sdata, hw_addr, rates);
if (!sta)
return;
@@ -261,7 +267,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data

sta->last_rx = jiffies;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
- if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+ if (mesh_peer_accepts_plinks(elems) &&
+ sta->plink_state == PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
@@ -373,6 +380,9 @@ int mesh_plink_open(struct sta_info *sta)
__le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;

+ if (!test_sta_flags(sta, WLAN_STA_AUTH))
+ return -EPERM;
+
spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
@@ -485,6 +495,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
return;
}

+ if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) {
+ mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
+ rcu_read_unlock();
+ return;
+ }
+
if (sta && sta->plink_state == PLINK_BLOCKED) {
rcu_read_unlock();
return;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 26a0a08..5ee28ae 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -213,6 +213,7 @@ enum cfg80211_event_type {
EVENT_ROAMED,
EVENT_DISCONNECTED,
EVENT_IBSS_JOINED,
+ EVENT_NEW_CANDIDATE,
};

struct cfg80211_event {
@@ -243,6 +244,11 @@ struct cfg80211_event {
struct {
u8 bssid[ETH_ALEN];
} ij;
+ struct {
+ u8 macaddr[ETH_ALEN];
+ const u8 *ie;
+ size_t ie_len;
+ } nc;
};
};

diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index c51e3c5..2a41b2a 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -1,5 +1,6 @@
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
+#include "nl80211.h"
#include "core.h"

/* Default values, timeouts in ms */
@@ -106,6 +107,46 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
return err;
}

+void __cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8* ie, u8 ie_len)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+ return;
+
+ nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
+ macaddr, ie, ie_len, GFP_KERNEL);
+ kfree(ie);
+}
+
+void cfg80211_notify_new_peer_candidate(struct net_device *dev,
+ const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct cfg80211_event *ev;
+ unsigned long flags;
+
+ ev = kzalloc(sizeof(*ev), gfp);
+ if (!ev)
+ return;
+ ev->type = EVENT_NEW_CANDIDATE;
+ memcpy(ev->nc.macaddr, macaddr, ETH_ALEN);
+ if (ie_len && ie) {
+ ev->nc.ie = kmemdup(ie, ie_len, gfp);
+ ev->nc.ie_len = (ev->nc.ie) ? ie_len : 0;
+ }
+
+ spin_lock_irqsave(&wdev->event_lock, flags);
+ list_add_tail(&ev->list, &wdev->event_list);
+ spin_unlock_irqrestore(&wdev->event_lock, flags);
+ queue_work(cfg80211_wq, &rdev->event_work);
+
+ return;
+}
+EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
+
static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 316e08f..fd10658 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1922,6 +1922,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },
};

static int parse_station_flags(struct genl_info *info,
@@ -2262,7 +2263,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
if (params.supported_rates)
err = -EINVAL;
- if (params.sta_flags_mask)
+ if (params.sta_flags_mask &
+ ~BIT(NL80211_STA_FLAG_AUTHENTICATED))
err = -EINVAL;
break;
default:
@@ -2324,6 +2326,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);

+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ params.plink_action =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
if (parse_station_flags(info, &params))
return -EINVAL;

@@ -5789,6 +5795,44 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}

+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *macaddr, const u8* ie, u8 ie_len,
+ gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr);
+ if (ie_len && ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
enum nl80211_key_type key_type, int key_id,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e3f7fa8..b7710b5 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -50,6 +50,10 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u16 reason,
const u8 *ie, size_t ie_len, bool from_ap);

+void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ const u8 *macaddr, const u8* ie, u8 ie_len,
+ gfp_t gfp);
void
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6a750bc..33b9ccc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -753,6 +753,11 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
break;
+ case EVENT_NEW_CANDIDATE:
+ __cfg80211_notify_new_peer_candidate(wdev->netdev,
+ ev->nc.macaddr, ev->nc.ie,
+ ev->nc.ie_len);
+ break;
}
wdev_unlock(wdev);

--
1.7.1


2011-03-05 14:06:04

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

I have a more generic question since I haven't seen the userspace bits:
How does userspace know when to authenticate with a new peer?

johannes


2011-03-05 19:42:10

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/4 v2] mac80211: Enable mesh security from userspace

On Sat, 2011-03-05 at 11:34 -0800, Javier Cardona wrote:

> > That last check seems a bit pointless -- I'd trust userspace (aka allow
> > it to shoot itself in the foot) and not check that there's RSN
> > information when it says it wants security -- maybe WAPI will come up
> > with mesh security at some point ;-)
>
> Enabling security without an RSN will result in mesh node that can't
> communicate with anyone in the mesh, secured or not.

Right, well, I keep thinking that maybe a daemon could still run an
unsecured mesh? But in any case I'm not so sure how that works at all --
see my reply to the intro mail.

> I prefer
> keeping that check in place to avoid annoying misconfigurations. You
> still think it's pointless? (In fact I was contemplating a more
> strict check by returning EINVAL instead of ignoring the request when
> userspace enables security and does not pass an RSN.)

I don't see how that misconfiguration could ever happen since you
wouldn't run the daemon if you don't want RSN, and iw would never set
the secure flag?

It just seems that if somebody wants to play with a protocol that
doesn't use the RSN IE but maybe adapts WPA to it, we could still allow
it to work.

johannes


2011-03-07 18:47:55

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 1/4 v3] mac80211: Enable mesh security from userspace

On Sat, Mar 5, 2011 at 12:26 PM, Johannes Berg
<[email protected]> wrote:
> On Sat, 2011-03-05 at 12:17 -0800, Javier Cardona wrote:
>> Userspace can enable mesh security by providing an RSN IE and setting
>> the MESH_SETUP_ENABLE_SECURITY flag.
>>
>> Also, rename vendor_ie to just ie to reflect that the same attribute may
>> be used to pass other IEs, like for instance RSN.
>>
>> Changes from v2: (from Johannes)
>> ?- Fix API backward compatibilty of NL80211_MESH_SETUP_IE
>> ?- Remove check for presence of RSN IE
>
> Should be after --- really :-)

Ah, so it stays out of the git commit message, right? OK.

>> + * @is_secure: or not
>
> Given what we just discussed over in the other thread, should we rename
> this to "userspace_station_mgmt" or something like that?

Are you suggesting to change the name of the flag both in nl80211 and cfg80211?

Currently ENABLE_SECURITY means "let userspace manage stations", but
also "ok to accept mesh management frames from secure mesh peers".
And when the Authenticated Mesh Peering Exchange is implemented, it
will probably mean "verify mesh peering frames in userspace" and
"protect mesh peering frames". You either do all these tasks or none,
so for nl80211 I would prefer a single flag.

For cfg80211 I have no clear opinion: two flags
(userspace_station_mgmt and is_secure)? one?. Let me know what makes
more sense to you and we'll do it.

> Also, does it make sense to advertise support for this somehow?
> Otherwise the new tools will have strange failure cases on older
> kernels;

Ah, I see. Older kernels would not return an error to userspace if an
attempt to set a non existing flag was made, right?
Are you suggesting to define something like an
NL80211_MESHCONF_CAPABILITIES mask?

> and I can also imagine situations where the mesh APIs are in
> firmware or so that can't cope with userspace station mgmt.

Ah mesh in firmware... who would want to do that? :)


--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-03-05 19:50:58

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 0/4 v2] {mac|nl}80211: Support for SAE mesh authentication in userspace

On Sat, 2011-03-05 at 11:40 -0800, Javier Cardona wrote:
> On Sat, Mar 5, 2011 at 6:06 AM, Johannes Berg <[email protected]> wrote:
> > I have a more generic question since I haven't seen the userspace bits:

> There's a working prototype here:
> https://github.com/cozybit/authsae/blob/master/linux/meshd-nl80211.c
> The intent is to merge that functionality into wpa_supplicant at some point.
>
> > How does userspace know when to authenticate with a new peer?

> Authentication is triggered by the reception of a beacon or presp from
> a compatible mesh peer with security enabled.

Ok ... so I read from this that it actually parses out the beacon frames
from scan results? It seems that it should rather signal beacon frames
for unknown peers to userspace somehow, so userspace doesn't have to
poll scan results?

johannes


2011-03-08 19:18:38

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC] mac80211: New notification to discover mesh peer candidates.

On Tue, 2011-03-08 at 10:56 -0800, Javier Cardona wrote:

> With this approach, when security is enabled, the decision to create
> the station is still made by the userspace daemon. A normal sequence
> would be:
>
> beacon is received
> mesh_matches_local is true
> no peer exists
> send NEW_PEER_CANDIDATE notification
> userspace creates unauthenticated station (optionally, to stop notifications)
> userspace authenticates station
> userspace sets authenticated flag
>
> But alternatively userspace can create no station at all. In that
> case a NEW_PEER_CANDIDATE notification is sent for every beacon
> received.

Ah, for some reason I thought mac80211 was now creating the
unauthenticated stations. I'll take another look.

johannes


2011-03-05 20:26:12

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/4 v3] mac80211: Enable mesh security from userspace

On Sat, 2011-03-05 at 12:17 -0800, Javier Cardona wrote:
> Userspace can enable mesh security by providing an RSN IE and setting
> the MESH_SETUP_ENABLE_SECURITY flag.
>
> Also, rename vendor_ie to just ie to reflect that the same attribute may
> be used to pass other IEs, like for instance RSN.
>
> Changes from v2: (from Johannes)
> - Fix API backward compatibilty of NL80211_MESH_SETUP_IE
> - Remove check for presence of RSN IE

Should be after --- really :-)

> + * @is_secure: or not

Given what we just discussed over in the other thread, should we rename
this to "userspace_station_mgmt" or something like that?

Also, does it make sense to advertise support for this somehow?
Otherwise the new tools will have strange failure cases on older
kernels; and I can also imagine situations where the mesh APIs are in
firmware or so that can't cope with userspace station mgmt.

johannes


2011-03-18 20:23:06

by Javier Cardona

[permalink] [raw]
Subject: [PATCH 2/5 v4] mac80211: Let user space receive and send mesh auth/deauth frames


Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/main.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 562d298..0ae9b22 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -545,7 +545,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_MESH_POINT] = {
.tx = 0xffff,
- .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4),
},
};

--
1.7.1