linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] cfg80211: add the new IBSS_STA event
@ 2012-12-10 10:21 Antonio Quartulli
  2012-12-10 10:21 ` [PATCH] mac80211: in AD-HOC mode wait for the AUTH response Antonio Quartulli
  0 siblings, 1 reply; 4+ messages in thread
From: Antonio Quartulli @ 2012-12-10 10:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Antonio Quartulli

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 <antonio@open-mesh.com>
---

This patchset fixes an incorrect state handling in the IBSS/RSN
"cooperation" between kernel and userspace.
It would probably be more appropriate to create a much general
event signaling mechanism (e.g. trigger an event each time a
station changes its internal state), but at the moment it is
much more important to fix the issue. Re-engineering can be
done later and with a proper idea.

I'm not sending this to mac80211 because I don't think it would
make it for this kernel release.

Cheers,


 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


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH] mac80211: in AD-HOC mode wait for the AUTH response
  2012-12-10 10:21 [PATCH 1/2] cfg80211: add the new IBSS_STA event Antonio Quartulli
@ 2012-12-10 10:21 ` Antonio Quartulli
  2012-12-10 10:43   ` Nicolas Cavallari
  0 siblings, 1 reply; 4+ messages in thread
From: Antonio Quartulli @ 2012-12-10 10:21 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Antonio Quartulli

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 <antonio@open-mesh.com>
---
 net/mac80211/ibss.c     | 97 ++++++++++++++++++++++++++++++++++++++++---------
 net/mac80211/sta_info.h |  2 +
 2 files changed, 81 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 700d0ed..9a11ec3 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,19 +284,12 @@ 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);
@@ -309,7 +302,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *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 +351,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 +404,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 +446,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 +517,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 +628,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 +711,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 +747,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 +1037,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


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] mac80211: in AD-HOC mode wait for the AUTH response
  2012-12-10 10:21 ` [PATCH] mac80211: in AD-HOC mode wait for the AUTH response Antonio Quartulli
@ 2012-12-10 10:43   ` Nicolas Cavallari
  2012-12-10 10:49     ` Antonio Quartulli
  0 siblings, 1 reply; 4+ messages in thread
From: Nicolas Cavallari @ 2012-12-10 10:43 UTC (permalink / raw)
  To: Antonio Quartulli; +Cc: Johannes Berg, linux-wireless

On 10/12/2012 11:21, Antonio Quartulli wrote:
> 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 <antonio@open-mesh.com>
> ---
>  net/mac80211/ibss.c     | 97 ++++++++++++++++++++++++++++++++++++++++---------
>  net/mac80211/sta_info.h |  2 +
>  2 files changed, 81 insertions(+), 18 deletions(-)
> 
> diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
> index 700d0ed..9a11ec3 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,19 +284,12 @@ 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);

If userspace registered for auth frames, then we shouldn't wait for auth responses,
as this code will never see them.

I'm also curious about compatibility with the current wpa_supplicant which does not know
about that new event.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] mac80211: in AD-HOC mode wait for the AUTH response
  2012-12-10 10:43   ` Nicolas Cavallari
@ 2012-12-10 10:49     ` Antonio Quartulli
  0 siblings, 0 replies; 4+ messages in thread
From: Antonio Quartulli @ 2012-12-10 10:49 UTC (permalink / raw)
  To: Nicolas Cavallari; +Cc: Johannes Berg, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 917 bytes --]

On Mon, Dec 10, 2012 at 11:43:15 +0100, Nicolas Cavallari wrote:
> > -	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);
> 
> If userspace registered for auth frames, then we shouldn't wait for auth responses,
> as this code will never see them.
> 

Correct. I think in this case the station should immediately be authenticated in
this point using an else branch.

> I'm also curious about compatibility with the current wpa_supplicant which does not know
> about that new event.

Yeah. A patch has already been prepared, I'll send it once this patchset gets
accepted.

Thank you for reviewing!
Cheers,

-- 
Antonio Quartulli

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

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-12-10 10:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-10 10:21 [PATCH 1/2] cfg80211: add the new IBSS_STA event Antonio Quartulli
2012-12-10 10:21 ` [PATCH] mac80211: in AD-HOC mode wait for the AUTH response Antonio Quartulli
2012-12-10 10:43   ` Nicolas Cavallari
2012-12-10 10:49     ` Antonio Quartulli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).