2012-12-10 11:17:19

by Antonio Quartulli

[permalink] [raw]
Subject: [PATCHv2 1/2] cfg80211: add the new IBSS_STA event

In IBSS mode it could be the case that a station being added
is not ready for starting higher level routines (e.g. key
exchange when IBSS/RSN is enabled). In particular, this can
happen when we are waiting for the AUTH response message.

This IBSS_STA event is triggered after the NEW_STA one and
only when the upper layer is allowed to assume that the new
peer is ready

Signed-off-by: Antonio Quartulli <[email protected]>
---

1/2 v2:
* untouched
2/2 v2:
* if userspace registered for auth frames, the new station is immediately
authenticated and the new IBSS_STA event is triggered.

include/net/cfg80211.h | 8 ++++++++
include/uapi/linux/nl80211.h | 2 ++
net/wireless/mlme.c | 9 +++++++++
net/wireless/nl80211.c | 33 +++++++++++++++++++++++++++++++++
net/wireless/nl80211.h | 3 +++
5 files changed, 55 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8e6a6b7..3266c03 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3497,6 +3497,14 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);

/**
+ * cfg80211_ibss_sta - notify userspace that the ibss station is ready
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @gfp: allocation flags
+ */
+void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
+
+/**
* cfg80211_del_sta - notify userspace about deletion of a station
*
* @dev: the netdev
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index e3e19f8..7e0911e 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -736,6 +736,8 @@ enum nl80211_commands {

NL80211_CMD_SET_MCAST_RATE,

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

/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 5e8123e..f9493fc 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -612,6 +612,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
}
EXPORT_SYMBOL(cfg80211_new_sta);

+void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
+{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ nl80211_send_ibss_sta_event(rdev, dev, mac_addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_ibss_sta);
+
void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f45706a..2d27911 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8564,6 +8564,39 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
nl80211_mlme_mcgrp.id, gfp);
}

+void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *mac_addr,
+ gfp_t gfp)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_IBSS_STATION);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ 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_send_sta_del_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
gfp_t gfp)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2acba84..429f5d6 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -85,6 +85,9 @@ void nl80211_send_remain_on_channel_cancel(
void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
struct station_info *sinfo, gfp_t gfp);
+void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *mac_addr,
+ gfp_t gfp);
void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *mac_addr,
gfp_t gfp);
--
1.8.0



2012-12-10 11:17:20

by Antonio Quartulli

[permalink] [raw]
Subject: [PATCHv2 2/2] mac80211: in AD-HOC mode wait for the AUTH response

To prevent race conditions between kernel state and
user-space application knowledge, it is better to wait for
a new peer to be completely authenticated before telling the
userspace that it is ready to start authorization
(IBSS/RSN).

Use the IBSS_STA event to tell userspace when a station is
authenticated and ready.

It could still be the case that the other node joining the
AD-HOC cell does not implement AUTH messages exchange,
therefore a fallback mechanism will authenticate the peer
after a timeout set for the purpose expires

Signed-off-by: Antonio Quartulli <[email protected]>
---
net/mac80211/ibss.c | 100 +++++++++++++++++++++++++++++++++++++++---------
net/mac80211/sta_info.h | 2 +
2 files changed, 84 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 700d0ed..80828b0 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -30,6 +30,7 @@

#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+#define IEEE80211_IBSS_AUTH_TIMEOUT (HZ / 2)

#define IEEE80211_IBSS_MAX_STA_ENTRIES 128

@@ -273,8 +274,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
false);
}

-static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
- bool auth)
+static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
__acquires(RCU)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -284,32 +284,28 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,

ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);

- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
- /* authorize the station only if the network is not RSN protected. If
- * not wait for the userspace to authorize it */
- if (!sta->sdata->u.ibss.control_port)
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
-
rate_control_rate_init(sta);

/* If it fails, maybe we raced another insertion? */
if (sta_info_insert_rcu(sta))
return sta_info_get(sdata, addr);
- if (auth && !sdata->u.ibss.auth_frame_registrations) {
+ if (!sdata->u.ibss.auth_frame_registrations) {
ibss_dbg(sdata,
"TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
sdata->vif.addr, addr, sdata->u.ibss.bssid);
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
addr, sdata->u.ibss.bssid, NULL, 0, 0);
+ } else {
+ ieee80211_ibss_auth_sta(sta);
}
+
return sta;
}

static struct sta_info *
ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, const u8 *addr,
- u32 supp_rates, bool auth)
+ u32 supp_rates)
__acquires(RCU)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
@@ -358,7 +354,23 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
sta->sta.supp_rates[band] = supp_rates |
ieee80211_mandatory_rates(local, band);

- return ieee80211_ibss_finish_sta(sta, auth);
+ return ieee80211_ibss_finish_sta(sta);
+}
+
+static void ieee80211_ibss_auth_sta(struct sta_info *sta)
+{
+ if (sta->sta_state > IEEE80211_STA_NONE)
+ return;
+
+ sta_info_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+ /* authorize the station only if the network is not RSN protected. If
+ * not wait for the userspace to authorize it
+ */
+ if (!sta->sdata->u.ibss.control_port)
+ sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+
+ cfg80211_ibss_sta(sta->sdata->dev, sta->sta.addr, GFP_KERNEL);
}

static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
@@ -395,13 +407,36 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
"RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);

- if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
+ if (auth_alg != WLAN_AUTH_OPEN)
return;

- sta_info_destroy_addr(sdata, mgmt->sa);
- sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
rcu_read_unlock();

+ if (auth_transaction == 2) {
+ ibss_dbg(sdata, "Authenticating STA %pM\n", sta->sta.addr);
+ ieee80211_ibss_auth_sta(sta);
+ return;
+ }
+
+ /* drop bogus auth frames (auth_transaction can be only 1 or 2) */
+ if (auth_transaction != 1)
+ return;
+
+ if (sta && sdata->u.ibss.control_port &&
+ sta->sta_state == IEEE80211_STA_AUTHORIZED) {
+ ibss_dbg(sdata, "Resetting STA %pM state for IBSS Encryption\n",
+ sta->sta.addr);
+ sta_info_destroy_addr(sdata, mgmt->sa);
+ sta = NULL;
+ }
+
+ if (!sta) {
+ sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0);
+ rcu_read_unlock();
+ }
+
/*
* if we have any problem in allocating the new station, we reply with a
* DEAUTH frame to tell the other end that we had a problem
@@ -414,12 +449,16 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
return;
}

+ sta->last_auth = jiffies;
+
/*
* IEEE 802.11 standard does not require authentication in IBSS
* networks and most implementations do not seem to use it.
* However, try to reply to authentication attempts if someone
* has actually implemented this.
*/
+ ibss_dbg(sdata, "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=2)\n",
+ sdata->vif.addr, mgmt->sa, sdata->u.ibss.bssid);
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0);
}
@@ -481,7 +520,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
} else {
rcu_read_unlock();
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
- mgmt->sa, supp_rates, true);
+ mgmt->sa, supp_rates);
}
}

@@ -592,7 +631,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_join_ibss(sdata, bss);
supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
- supp_rates, true);
+ supp_rates);
rcu_read_unlock();
}

@@ -675,6 +714,29 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
return active;
}

+static void ieee80211_ibss_auth_expire(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (sdata != sta->sdata)
+ continue;
+
+ if (sta->sta_state > IEEE80211_STA_NONE)
+ continue;
+
+ if (time_after(jiffies,
+ sta->last_auth + IEEE80211_IBSS_AUTH_TIMEOUT)) {
+ ibss_dbg(sdata,
+ "Authenticating IBSS STA %pM by timeout\n",
+ sta->sta.addr);
+ ieee80211_ibss_auth_sta(sta);
+ }
+ }
+}
+
+
/*
* This function is called with state == IEEE80211_IBSS_MLME_JOINED
*/
@@ -688,6 +750,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));

+ ieee80211_ibss_auth_expire(sdata);
+
ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);

if (time_before(jiffies, ifibss->last_scan_completed +
@@ -976,7 +1040,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
list_del(&sta->list);
spin_unlock_bh(&ifibss->incomplete_lock);

- ieee80211_ibss_finish_sta(sta, true);
+ ieee80211_ibss_finish_sta(sta);
rcu_read_unlock();
spin_lock_bh(&ifibss->incomplete_lock);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 1489bca..3c150a4 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -244,6 +244,7 @@ struct sta_ampdu_mlme {
* @rx_bytes: Number of bytes received from this STA
* @wep_weak_iv_count: number of weak WEP IVs received from this station
* @last_rx: time (in jiffies) when last frame was received from this STA
+ * @last_auth: jiffies of last auth packet with seq = 1
* @last_connected: time (in seconds) when a station got connected
* @num_duplicates: number of duplicate frames received from this STA
* @rx_fragments: number of received MPDUs
@@ -324,6 +325,7 @@ struct sta_info {
unsigned long rx_packets, rx_bytes;
unsigned long wep_weak_iv_count;
unsigned long last_rx;
+ unsigned long last_auth;
long last_connected;
unsigned long num_duplicates;
unsigned long rx_fragments;
--
1.8.0


2012-12-11 16:54:24

by Antonio Quartulli

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] cfg80211: add the new IBSS_STA event

Hi Will,

On Tue, Dec 11, 2012 at 11:37:44AM -0500, Will Hawkins wrote:
> Will this give IBSS something equivalent to the 802.11s
> NL80211_CMD_NEW_PEER_CANDIDATE?
>

I'm not very familiar with the 802.11s code, but after having given a look,
they seem to be similar. The difference is that the IBSS_STA event is triggered
only after the new station has been AUTHENTICATED, while NNEW_PEER_CANDIDATE
seems to be triggered right after having "intercepted" a new peer.

So in IBSS, with this patchset, you will have these sequence:

0) detection of a new node
1) sta_info creation and NEW_STA is triggered (this event has not been removed)
2) sta gets authenticated
3) IBSS_STA triggered => sta is ready to be handled by userspace (e.g. wpa_s)

> That's how I am reading it, but I just wanted to get some more context.
> If this is what you are adding, it's great! Just exactly what I need.

I hope the explanation above is enough, otherwise feel free to ask more :-)

>
> Thanks for your work Antonio.
>


np, thank Open-Mesh for having given me the chance to work on this ;)

Cheers,

> Will
>
> On 12/10/2012 06:16 AM, Antonio Quartulli wrote:
> > In IBSS mode it could be the case that a station being added
> > is not ready for starting higher level routines (e.g. key
> > exchange when IBSS/RSN is enabled). In particular, this can
> > happen when we are waiting for the AUTH response message.
> >
> > This IBSS_STA event is triggered after the NEW_STA one and
> > only when the upper layer is allowed to assume that the new
> > peer is ready
> >
> > Signed-off-by: Antonio Quartulli <[email protected]>
> > ---
> >
> > 1/2 v2:
> > * untouched
> > 2/2 v2:
> > * if userspace registered for auth frames, the new station is immediately
> > authenticated and the new IBSS_STA event is triggered.
> >
> > include/net/cfg80211.h | 8 ++++++++
> > include/uapi/linux/nl80211.h | 2 ++
> > net/wireless/mlme.c | 9 +++++++++
> > net/wireless/nl80211.c | 33 +++++++++++++++++++++++++++++++++
> > net/wireless/nl80211.h | 3 +++
> > 5 files changed, 55 insertions(+)
> >
> > diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> > index 8e6a6b7..3266c03 100644
> > --- a/include/net/cfg80211.h
> > +++ b/include/net/cfg80211.h
> > @@ -3497,6 +3497,14 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
> > struct station_info *sinfo, gfp_t gfp);
> >
> > /**
> > + * cfg80211_ibss_sta - notify userspace that the ibss station is ready
> > + * @dev: the netdev
> > + * @mac_addr: the station's address
> > + * @gfp: allocation flags
> > + */
> > +void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
> > +
> > +/**
> > * cfg80211_del_sta - notify userspace about deletion of a station
> > *
> > * @dev: the netdev
> > diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> > index e3e19f8..7e0911e 100644
> > --- a/include/uapi/linux/nl80211.h
> > +++ b/include/uapi/linux/nl80211.h
> > @@ -736,6 +736,8 @@ enum nl80211_commands {
> >
> > NL80211_CMD_SET_MCAST_RATE,
> >
> > + NL80211_CMD_IBSS_STATION,
> > +
> > /* add new commands above here */
> >
> > /* used to define NL80211_CMD_MAX below */
> > diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
> > index 5e8123e..f9493fc 100644
> > --- a/net/wireless/mlme.c
> > +++ b/net/wireless/mlme.c
> > @@ -612,6 +612,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
> > }
> > EXPORT_SYMBOL(cfg80211_new_sta);
> >
> > +void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
> > +{
> > + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> > + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
> > +
> > + nl80211_send_ibss_sta_event(rdev, dev, mac_addr, gfp);
> > +}
> > +EXPORT_SYMBOL(cfg80211_ibss_sta);
> > +
> > void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
> > {
> > struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> > diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> > index f45706a..2d27911 100644
> > --- a/net/wireless/nl80211.c
> > +++ b/net/wireless/nl80211.c
> > @@ -8564,6 +8564,39 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
> > nl80211_mlme_mcgrp.id, gfp);
> > }
> >
> > +void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
> > + struct net_device *dev, const u8 *mac_addr,
> > + gfp_t gfp)
> > +{
> > + struct sk_buff *msg;
> > + void *hdr;
> > +
> > + msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
> > + if (!msg)
> > + return;
> > +
> > + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_IBSS_STATION);
> > + if (!hdr) {
> > + nlmsg_free(msg);
> > + return;
> > + }
> > +
> > + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
> > + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
> > + goto nla_put_failure;
> > +
> > + genlmsg_end(msg, hdr);
> > +
> > + 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_send_sta_del_event(struct cfg80211_registered_device *rdev,
> > struct net_device *dev, const u8 *mac_addr,
> > gfp_t gfp)
> > diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
> > index 2acba84..429f5d6 100644
> > --- a/net/wireless/nl80211.h
> > +++ b/net/wireless/nl80211.h
> > @@ -85,6 +85,9 @@ void nl80211_send_remain_on_channel_cancel(
> > void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
> > struct net_device *dev, const u8 *mac_addr,
> > struct station_info *sinfo, gfp_t gfp);
> > +void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
> > + struct net_device *dev, const u8 *mac_addr,
> > + gfp_t gfp);
> > void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
> > struct net_device *dev, const u8 *mac_addr,
> > gfp_t gfp);
> >

--
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara


Attachments:
(No filename) (5.99 kB)
(No filename) (836.00 B)
Download all attachments

2012-12-11 16:47:17

by Will Hawkins

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] cfg80211: add the new IBSS_STA event

Will this give IBSS something equivalent to the 802.11s
NL80211_CMD_NEW_PEER_CANDIDATE?

That's how I am reading it, but I just wanted to get some more context.
If this is what you are adding, it's great! Just exactly what I need.

Thanks for your work Antonio.

Will

On 12/10/2012 06:16 AM, Antonio Quartulli wrote:
> In IBSS mode it could be the case that a station being added
> is not ready for starting higher level routines (e.g. key
> exchange when IBSS/RSN is enabled). In particular, this can
> happen when we are waiting for the AUTH response message.
>
> This IBSS_STA event is triggered after the NEW_STA one and
> only when the upper layer is allowed to assume that the new
> peer is ready
>
> Signed-off-by: Antonio Quartulli <[email protected]>
> ---
>
> 1/2 v2:
> * untouched
> 2/2 v2:
> * if userspace registered for auth frames, the new station is immediately
> authenticated and the new IBSS_STA event is triggered.
>
> include/net/cfg80211.h | 8 ++++++++
> include/uapi/linux/nl80211.h | 2 ++
> net/wireless/mlme.c | 9 +++++++++
> net/wireless/nl80211.c | 33 +++++++++++++++++++++++++++++++++
> net/wireless/nl80211.h | 3 +++
> 5 files changed, 55 insertions(+)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 8e6a6b7..3266c03 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -3497,6 +3497,14 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
> struct station_info *sinfo, gfp_t gfp);
>
> /**
> + * cfg80211_ibss_sta - notify userspace that the ibss station is ready
> + * @dev: the netdev
> + * @mac_addr: the station's address
> + * @gfp: allocation flags
> + */
> +void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
> +
> +/**
> * cfg80211_del_sta - notify userspace about deletion of a station
> *
> * @dev: the netdev
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index e3e19f8..7e0911e 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -736,6 +736,8 @@ enum nl80211_commands {
>
> NL80211_CMD_SET_MCAST_RATE,
>
> + NL80211_CMD_IBSS_STATION,
> +
> /* add new commands above here */
>
> /* used to define NL80211_CMD_MAX below */
> diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
> index 5e8123e..f9493fc 100644
> --- a/net/wireless/mlme.c
> +++ b/net/wireless/mlme.c
> @@ -612,6 +612,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
> }
> EXPORT_SYMBOL(cfg80211_new_sta);
>
> +void cfg80211_ibss_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
> +{
> + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
> +
> + nl80211_send_ibss_sta_event(rdev, dev, mac_addr, gfp);
> +}
> +EXPORT_SYMBOL(cfg80211_ibss_sta);
> +
> void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
> {
> struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index f45706a..2d27911 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -8564,6 +8564,39 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
> nl80211_mlme_mcgrp.id, gfp);
> }
>
> +void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
> + struct net_device *dev, const u8 *mac_addr,
> + gfp_t gfp)
> +{
> + struct sk_buff *msg;
> + void *hdr;
> +
> + msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
> + if (!msg)
> + return;
> +
> + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_IBSS_STATION);
> + if (!hdr) {
> + nlmsg_free(msg);
> + return;
> + }
> +
> + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
> + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
> + goto nla_put_failure;
> +
> + genlmsg_end(msg, hdr);
> +
> + 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_send_sta_del_event(struct cfg80211_registered_device *rdev,
> struct net_device *dev, const u8 *mac_addr,
> gfp_t gfp)
> diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
> index 2acba84..429f5d6 100644
> --- a/net/wireless/nl80211.h
> +++ b/net/wireless/nl80211.h
> @@ -85,6 +85,9 @@ void nl80211_send_remain_on_channel_cancel(
> void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
> struct net_device *dev, const u8 *mac_addr,
> struct station_info *sinfo, gfp_t gfp);
> +void nl80211_send_ibss_sta_event(struct cfg80211_registered_device *rdev,
> + struct net_device *dev, const u8 *mac_addr,
> + gfp_t gfp);
> void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
> struct net_device *dev, const u8 *mac_addr,
> gfp_t gfp);
>