All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2 RFC] cfg80211: connect/disconnect API
@ 2009-06-22 17:04 Samuel Ortiz
  2009-06-22 17:51 ` [PATCH 2/2 RFC] mac80211: connect API port Samuel Ortiz
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Samuel Ortiz @ 2009-06-22 17:04 UTC (permalink / raw)
  To: linux-wireless, Johannes Berg; +Cc: sameo, Zhu, Yi


This patch introduces the cfg80211 connect/disconnect API. The goal here is to
run the AUTH and ASSOC steps in one call. This is needed for some fullmac
cards that run both steps directly from the target, after the host driver
sends a connect command.
The connect/disconnect API is emulated through the auth/assoc/deauth hooks for
the cfg80211 devices that can only provide those.
This API also allows us to move some of the wext calls (ESSID, FREQ and AP)
from mac80211 or driver specific wext implementations to the cfg80211 layer.

Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
---
 include/linux/nl80211.h |   11 ++
 include/net/cfg80211.h  |   96 ++++++++++++++++++-
 net/wireless/Makefile   |    4 
 net/wireless/core.c     |   58 ++++++++---
 net/wireless/core.h     |   11 ++
 net/wireless/mlme.c     |   65 ++++++++++++
 net/wireless/nl80211.c  |  217 +++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    7 +
 net/wireless/sme.c      |  241 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/wext-sme.c |  238 +++++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 925 insertions(+), 23 deletions(-)

Index: iwm-2.6/include/linux/nl80211.h
===================================================================
--- iwm-2.6.orig/include/linux/nl80211.h	2009-06-22 18:42:44.000000000 +0200
+++ iwm-2.6/include/linux/nl80211.h	2009-06-22 18:46:30.000000000 +0200
@@ -242,6 +242,14 @@
  * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
  *	determined by the network interface.
  *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ *	requests to connect to a specified network but without separating
+ *	auth and assoc steps. It is also sent when the connection is
+ *	established and possibly when the card roamed.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ *	userspace that a connection was dropped by the AP or due to other
+ *	reasons.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -310,6 +318,9 @@ enum nl80211_commands {
 	NL80211_CMD_JOIN_IBSS,
 	NL80211_CMD_LEAVE_IBSS,
 
+	NL80211_CMD_CONNECT,
+	NL80211_CMD_DISCONNECT,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
Index: iwm-2.6/include/net/cfg80211.h
===================================================================
--- iwm-2.6.orig/include/net/cfg80211.h	2009-06-22 18:46:24.000000000 +0200
+++ iwm-2.6/include/net/cfg80211.h	2009-06-22 18:46:30.000000000 +0200
@@ -738,6 +738,37 @@ struct cfg80211_ibss_params {
 };
 
 /**
+ * struct cfg80211_connect_params - Connection parameters
+ *
+ * This structure provides information needed to complete IEEE 802.11
+ * authentication and association.
+ *
+ * @channel: The channel to use or %NULL if not specified (auto-select based
+ *	on scan results)
+ * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
+ *	results)
+ * @ssid: SSID
+ * @ssid_len: Length of ssid in octets
+ * @auth_type: Authentication type (algorithm)
+ * @assoc_ie: IEs for association request
+ * @assoc_ie_len: Length of assoc_ie in octets
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ *	required to assume that the port is unauthorized until authorized by
+ *	user space. Otherwise, port is marked authorized by default.
+ */
+struct cfg80211_connect_params {
+	struct ieee80211_channel *channel;
+	u8 *bssid;
+	u8 *ssid;
+	size_t ssid_len;
+	enum nl80211_auth_type auth_type;
+	u8 *ie;
+	size_t ie_len;
+	bool control_port;
+};
+
+/**
  * enum wiphy_params_flags - set_wiphy_params bitfield values
  * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
  * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed
@@ -841,6 +872,10 @@ enum tx_power_setting {
  * @deauth: Request to deauthenticate from the specified peer
  * @disassoc: Request to disassociate from the specified peer
  *
+ * @connect: Connect to the ESS with the specified parameters.
+ *	When connected, call cfg80211_connected().
+ * @disconnect: Disconnect from the BSS/ESS.
+ *
  * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
  *	cfg80211_ibss_joined(), also call that function when changing BSSID due
  *	to a merge.
@@ -944,6 +979,11 @@ struct cfg80211_ops {
 	int	(*disassoc)(struct wiphy *wiphy, struct net_device *dev,
 			    struct cfg80211_disassoc_request *req);
 
+	int	(*connect)(struct wiphy *wiphy, struct net_device *dev,
+			   struct cfg80211_connect_params *sme);
+	int	(*disconnect)(struct wiphy *wiphy, struct net_device *dev,
+			      u16 reason_code);
+
 	int	(*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
 			     struct cfg80211_ibss_params *params);
 	int	(*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
@@ -1168,16 +1208,25 @@ struct wireless_dev {
 	struct list_head list;
 	struct net_device *netdev;
 
-	/* currently used for IBSS - might be rearranged in the future */
+	/* currently used for IBSS and SME - might be rearranged later */
 	struct cfg80211_bss *current_bss;
 	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
 	u8 ssid_len;
+	struct ieee80211_channel *channel;
+	struct cfg80211_assoc_request assoc_req;
+	enum {
+		CFG80211_SME_IDLE,
+		CFG80211_SME_AUTH,
+		CFG80211_SME_ASSOC,
+		CFG80211_SME_CONNECTED,
+	} sme_state;
 
 #ifdef CONFIG_WIRELESS_EXT
 	/* wext data */
 	struct {
 		struct cfg80211_ibss_params ibss;
+		struct cfg80211_connect_params connect;
 		u8 bssid[ETH_ALEN];
 		s8 default_key, default_mgmt_key;
 	} wext;
@@ -1459,6 +1508,25 @@ int cfg80211_ibss_wext_giwap(struct net_
 			     struct iw_request_info *info,
 			     struct sockaddr *ap_addr, char *extra);
 
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_freq *freq, char *extra);
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       struct iw_point *data, char *ssid);
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       struct iw_point *data, char *ssid);
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct sockaddr *ap_addr, char *extra);
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct sockaddr *ap_addr, char *extra);
+
 struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
 					     struct iw_freq *freq);
 
@@ -1699,4 +1767,30 @@ void wiphy_rfkill_start_polling(struct w
  */
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 
+/**
+ * cfg80211_connected - notify cfg80211 that connection is established.
+ *
+ * @dev: network device
+ * @bssid: the BSSID of the AP
+ * @ie: association response IEs
+ * @ie_len: assoc response IEs length
+ * @gfp: allocation flags
+ *
+ * It should be called by the underlying drivers whenever connect() has
+ * succeeded.
+ */
+void cfg80211_connected(struct net_device *dev, const u8 *bssid,
+			u8 *ie, size_t ie_len, gfp_t gfp);
+
+/**
+ * cfg80211_connected - notify cfg80211 that connection was dropped
+ *
+ * @dev: network device
+ * @gfp: allocation flags
+ * @reason: reason code for the disconnection, set it to 0 when invalid.
+ *
+ */
+void cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u16 reason);
+
+
 #endif /* __NET_CFG80211_H */
Index: iwm-2.6/net/wireless/Makefile
===================================================================
--- iwm-2.6.orig/net/wireless/Makefile	2009-06-22 18:42:44.000000000 +0200
+++ iwm-2.6/net/wireless/Makefile	2009-06-22 18:46:30.000000000 +0200
@@ -5,8 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib8
 obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
 obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
 
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
-cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
+cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
 
 ccflags-y += -D__CHECK_ENDIAN__
Index: iwm-2.6/net/wireless/core.h
===================================================================
--- iwm-2.6.orig/net/wireless/core.h	2009-06-22 18:42:44.000000000 +0200
+++ iwm-2.6/net/wireless/core.h	2009-06-22 18:46:30.000000000 +0200
@@ -58,6 +58,8 @@ struct cfg80211_registered_device {
 	struct cfg80211_scan_request *scan_req; /* protected by RTNL */
 	unsigned long suspend_at;
 
+	struct work_struct sme_sm;
+
 #ifdef CONFIG_CFG80211_DEBUGFS
 	/* Debugfs entries */
 	struct wiphy_debugfsdentries {
@@ -170,6 +172,15 @@ void cfg80211_clear_ibss(struct net_devi
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, bool nowext);
 
+/* SME */
+void cfg80211_sme_work(struct work_struct *work);
+
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+		     struct net_device *dev,
+		     struct cfg80211_connect_params *connect);
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+			struct net_device *dev, u16 reason);
+
 /* internal helpers */
 int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
 				   const u8 *mac_addr);
Index: iwm-2.6/net/wireless/nl80211.c
===================================================================
--- iwm-2.6.orig/net/wireless/nl80211.c	2009-06-22 18:46:24.000000000 +0200
+++ iwm-2.6/net/wireless/nl80211.c	2009-06-22 18:46:30.000000000 +0200
@@ -347,6 +347,17 @@ static int nl80211_send_wiphy(struct sk_
 	CMD(join_ibss, JOIN_IBSS);
 
 #undef CMD
+
+	if (dev->ops->connect || dev->ops->auth) {
+		i++;
+		NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
+	}
+
+	if (dev->ops->disconnect || dev->ops->deauth) {
+		i++;
+		NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
+	}
+
 	nla_nest_end(msg, nl_cmds);
 
 	return genlmsg_end(msg, hdr);
@@ -3415,6 +3426,128 @@ unlock_rtnl:
 	return err;
 }
 
+static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	struct net_device *dev;
+	struct cfg80211_connect_params connect;
+	struct wiphy *wiphy;
+	int err;
+
+	memset(&connect, 0, sizeof(connect));
+
+	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_SSID] ||
+	    !nla_len(info->attrs[NL80211_ATTR_SSID]))
+		return -EINVAL;
+
+	rtnl_lock();
+
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		goto unlock_rtnl;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	wiphy = &drv->wiphy;
+
+	connect.bssid = NULL;
+	connect.channel = NULL;
+	connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+	connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+	connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+
+	if (info->attrs[NL80211_ATTR_IE]) {
+		connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+		connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+	}
+
+	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+		connect.channel =
+			ieee80211_get_channel(wiphy,
+			    nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+		if (!connect.channel ||
+		    connect.channel->flags & IEEE80211_CHAN_DISABLED) {
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+		connect.auth_type =
+			nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+		if (!nl80211_valid_auth_type(connect.auth_type)) {
+			err = -EINVAL;
+			goto out;
+		}
+	}
+
+	connect.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+
+	err = cfg80211_connect(drv, dev, &connect);
+
+out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+unlock_rtnl:
+	rtnl_unlock();
+	return err;
+}
+
+static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	struct net_device *dev;
+	int err;
+	u16 reason;
+
+	if (!info->attrs[NL80211_ATTR_REASON_CODE])
+		reason = WLAN_REASON_DEAUTH_LEAVING;
+	else
+		reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+
+	if (reason == 0)
+		return -EINVAL;
+
+	rtnl_lock();
+
+	err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+	if (err)
+		goto unlock_rtnl;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	if (!netif_running(dev)) {
+		err = -ENETDOWN;
+		goto out;
+	}
+
+	err = cfg80211_disconnect(drv, dev, reason);
+
+out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+unlock_rtnl:
+	rtnl_unlock();
+	return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -3628,6 +3761,18 @@ static struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_CONNECT,
+		.doit = nl80211_connect,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_DISCONNECT,
+		.doit = nl80211_disconnect,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
 	.name = "mlme",
@@ -3940,6 +4085,78 @@ void nl80211_send_assoc_timeout(struct c
 	nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr);
 }
 
+void nl80211_send_connected(struct cfg80211_registered_device *rdev,
+			    struct net_device *netdev, const u8 *bssid,
+			    const u8 *ie, size_t ie_len, 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_CONNECT);
+	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, bssid);
+	if (ie)
+		NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+
+}
+
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+			       struct net_device *netdev, gfp_t gfp, u16 reason)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
+	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);
+	if (reason)
+		NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+
+}
+
 void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, const u8 *bssid,
 			     gfp_t gfp)
Index: iwm-2.6/net/wireless/sme.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ iwm-2.6/net/wireless/sme.c	2009-06-22 18:46:30.000000000 +0200
@@ -0,0 +1,241 @@
+/*
+ * SME code for cfg80211's connect emulation.
+ *
+ * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009   Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/workqueue.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include "nl80211.h"
+
+void cfg80211_sme_work(struct work_struct *work)
+{
+	struct cfg80211_registered_device *drv =
+		container_of(work, struct cfg80211_registered_device, sme_sm);
+	struct wireless_dev *wdev;
+
+	rtnl_lock();
+	mutex_lock(&drv->devlist_mtx);
+
+	list_for_each_entry(wdev, &drv->netdev_list, list)
+		if (netif_running(wdev->netdev) &&
+		    wdev->sme_state == CFG80211_SME_ASSOC)
+			drv->ops->assoc(wdev->wiphy, wdev->netdev,
+					&wdev->assoc_req);
+
+	mutex_unlock(&drv->devlist_mtx);
+	rtnl_unlock();
+}
+
+void cfg80211_connected(struct net_device *dev, const u8 *bssid,
+			u8 *ie, size_t ie_len, gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_bss *bss;
+#ifdef CONFIG_WIRELESS_EXT
+	union iwreq_data wrqu;
+#endif
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return;
+
+	if (WARN_ON(!wdev->ssid_len))
+		return;
+
+	if (memcmp(bssid, wdev->bssid, ETH_ALEN) == 0)
+		return;
+
+	bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+			       wdev->ssid, wdev->ssid_len,
+			       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+
+	if (WARN_ON(!bss))
+		return;
+
+	if (wdev->current_bss) {
+		cfg80211_unhold_bss(wdev->current_bss);
+		cfg80211_put_bss(wdev->current_bss);
+	}
+
+	cfg80211_hold_bss(bss);
+	wdev->current_bss = bss;
+	memcpy(wdev->bssid, bssid, ETH_ALEN);
+	wdev->sme_state = CFG80211_SME_CONNECTED;
+
+	nl80211_send_connected(wiphy_to_dev(wdev->wiphy), dev, bssid,
+			       ie, ie_len, gfp);
+
+#ifdef CONFIG_WIRELESS_EXT
+	memset(&wrqu, 0, sizeof(wrqu));
+	wrqu.data.length = ie_len;
+	wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
+
+	memset(&wrqu, 0, sizeof(wrqu));
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+EXPORT_SYMBOL(cfg80211_connected);
+
+void cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u16 reason)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+#ifdef CONFIG_WIRELESS_EXT
+	union iwreq_data wrqu;
+#endif
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return;
+
+	if (WARN_ON(!wdev->ssid_len))
+		return;
+
+	if (wdev->current_bss) {
+		cfg80211_unhold_bss(wdev->current_bss);
+		cfg80211_put_bss(wdev->current_bss);
+	}
+
+	wdev->current_bss = NULL;
+	memset(wdev->bssid, 0, ETH_ALEN);
+	wdev->sme_state = CFG80211_SME_IDLE;
+
+	nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, gfp, reason);
+
+#ifdef CONFIG_WIRELESS_EXT
+	memset(&wrqu, 0, sizeof(wrqu));
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+EXPORT_SYMBOL(cfg80211_disconnected);
+
+int cfg80211_connect(struct cfg80211_registered_device *rdev,
+		     struct net_device *dev,
+		     struct cfg80211_connect_params *connect)
+{
+	int err;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (wdev->sme_state != CFG80211_SME_IDLE)
+		return -EALREADY;
+
+#ifdef CONFIG_WIRELESS_EXT
+	wdev->wext.connect.channel = connect->channel;
+#endif
+
+	wdev->channel = connect->channel;
+
+	if (!rdev->ops->connect) {
+		struct wireless_dev *wdev = dev->ieee80211_ptr;
+		struct cfg80211_auth_request auth_req;
+		int err;
+
+		/*
+		 * We split the connect_params into an auth req
+		 * and an assoc req.
+		 */
+		memset(&auth_req, 0, sizeof(auth_req));
+		auth_req.chan = connect->channel;
+		auth_req.peer_addr = connect->bssid;
+		auth_req.ssid = connect->ssid;
+		auth_req.ssid_len = connect->ssid_len;
+		auth_req.auth_type = connect->auth_type;
+		auth_req.ie = connect->ie;
+		auth_req.ie_len = connect->ie_len;
+
+		/*
+		 * Here we cache the assoc request. It will be used
+		 * when the cfg80211 user will call cfg80211_authenticated()
+		 * letting us know that we can move forward and call the
+		 * assoc hook.
+		 */
+		memset(&wdev->assoc_req, 0, sizeof(wdev->assoc_req));
+		if (connect->channel)
+			wdev->assoc_req.chan = kmemdup(connect->channel,
+					       sizeof(struct ieee80211_channel),
+						       GFP_ATOMIC);
+		if (connect->bssid)
+			wdev->assoc_req.peer_addr = kmemdup(connect->bssid,
+							    ETH_ALEN,
+							    GFP_ATOMIC);
+		wdev->assoc_req.ssid = kmemdup(connect->ssid,
+					       connect->ssid_len,
+					       GFP_ATOMIC);
+		wdev->assoc_req.ssid_len = connect->ssid_len;
+		if (connect->ie)
+			wdev->assoc_req.ie = kmemdup(connect->ie,
+						     connect->ie_len,
+						     GFP_ATOMIC);
+		wdev->assoc_req.ie_len = connect->ie_len;
+		wdev->assoc_req.control_port = connect->control_port;
+
+		if (!rdev->ops->auth || !rdev->ops->assoc)
+			return -EOPNOTSUPP;
+
+		err = rdev->ops->auth(&rdev->wiphy, dev, &auth_req);
+		if (err)
+			return err;
+	} else {
+		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
+
+		if (err)
+			return err;
+	}
+
+	wdev->sme_state = CFG80211_SME_AUTH;
+	memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+	wdev->ssid_len = connect->ssid_len;
+
+	return 0;
+}
+
+int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
+			struct net_device *dev, u16 reason)
+{
+	int err;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (!rdev->ops->disconnect) {
+		struct cfg80211_deauth_request deauth;
+
+		if (!rdev->ops->deauth)
+			return -EOPNOTSUPP;
+
+		memset(&deauth, 0, sizeof(deauth));
+
+		deauth.peer_addr = wdev->bssid;
+		deauth.reason_code = reason;
+
+		err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth);
+
+		if (err)
+			return err;
+	} else {
+		err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
+
+		if (err)
+			return err;
+	}
+
+	wdev->sme_state = CFG80211_SME_IDLE;
+
+	if (wdev->current_bss) {
+		cfg80211_unhold_bss(wdev->current_bss);
+		cfg80211_put_bss(wdev->current_bss);
+	}
+
+	wdev->current_bss = NULL;
+	wdev->ssid_len = 0;
+	memset(wdev->bssid, 0, ETH_ALEN);
+	kfree(wdev->assoc_req.chan);
+	kfree(wdev->assoc_req.peer_addr);
+	kfree(wdev->assoc_req.ssid);
+	kfree(wdev->assoc_req.ie);
+
+	return 0;
+}
Index: iwm-2.6/net/wireless/wext-sme.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ iwm-2.6/net/wireless/wext-sme.c	2009-06-22 18:46:30.000000000 +0200
@@ -0,0 +1,238 @@
+/*
+ * cfg80211 wext compat for managed mode.
+ *
+ * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2009   Intel Corporation. All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+
+static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+				     struct wireless_dev *wdev)
+{
+	if (!netif_running(wdev->netdev))
+		return 0;
+
+	if (wdev->wext.connect.ssid_len != 0)
+		return cfg80211_connect(rdev, wdev->netdev,
+					&wdev->wext.connect);
+
+	return 0;
+}
+
+int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_freq *freq, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	struct ieee80211_channel *chan;
+	int err;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	chan = cfg80211_wext_freq(wdev->wiphy, freq);
+	if (chan && IS_ERR(chan))
+		return PTR_ERR(chan);
+
+	if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
+		return -EINVAL;
+
+	if (wdev->wext.connect.channel == chan)
+		return 0;
+
+	if (wdev->sme_state != CFG80211_SME_IDLE) {
+		err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+					  dev, WLAN_REASON_DEAUTH_LEAVING);
+		if (err)
+			return err;
+	}
+
+	wdev->wext.connect.channel = chan;
+
+	if (wdev->sme_state == CFG80211_SME_IDLE &&
+	    wdev->wext.connect.channel) {
+		/* SSID is not set, we just want to switch channel */
+		if (!rdev->ops->set_channel)
+			return -EOPNOTSUPP;
+
+		return rdev->ops->set_channel(wdev->wiphy, chan,
+					      NL80211_CHAN_NO_HT);
+	}
+
+	err = rdev->ops->set_channel(wdev->wiphy, chan,
+				     NL80211_CHAN_NO_HT);
+	if (err)
+		return err;
+
+	return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
+
+int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_freq *freq, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct ieee80211_channel *chan = NULL;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	if (wdev->current_bss)
+		chan = wdev->current_bss->channel;
+	else if (wdev->wext.connect.channel)
+		chan = wdev->wext.connect.channel;
+
+	if (chan) {
+		freq->m = chan->center_freq;
+		freq->e = 6;
+		return 0;
+	}
+
+	/* no channel if not joining */
+	return -EINVAL;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq);
+
+int cfg80211_mgd_wext_siwessid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       struct iw_point *data, char *ssid)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	size_t len = data->length;
+	int err;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	if (wdev->sme_state != CFG80211_SME_IDLE) {
+		err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+					  dev, WLAN_REASON_DEAUTH_LEAVING);
+		if (err)
+			return err;
+	}
+
+	/* iwconfig uses nul termination in SSID.. */
+	if (len > 0 && ssid[len - 1] == '\0')
+		len--;
+
+	if (data->flags) {
+		wdev->wext.connect.ssid = wdev->ssid;
+		memcpy(wdev->wext.connect.ssid, ssid, len);
+		wdev->wext.connect.ssid_len = len;
+	} else
+		wdev->wext.connect.ssid_len = 0;
+
+	wdev->wext.connect.control_port = false;
+
+	return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
+
+int cfg80211_mgd_wext_giwessid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       struct iw_point *data, char *ssid)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	data->flags = 0;
+
+	if (wdev->ssid_len) {
+		data->flags = 1;
+		data->length = wdev->ssid_len;
+		memcpy(ssid, wdev->ssid, data->length);
+	} else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
+		data->flags = 1;
+		data->length = wdev->wext.connect.ssid_len;
+		memcpy(ssid, wdev->wext.connect.ssid, data->length);
+	} else
+		data->flags = 0;
+
+	return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid);
+
+int cfg80211_mgd_wext_siwap(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct sockaddr *ap_addr, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	u8 *bssid = ap_addr->sa_data;
+	int err;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	if (ap_addr->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+
+	/* automatic mode */
+	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
+		bssid = NULL;
+
+	/* both automatic */
+	if (!bssid && !wdev->wext.connect.bssid)
+		return 0;
+
+	/* fixed already - and no change */
+	if (wdev->wext.connect.bssid && bssid &&
+	    compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+		return 0;
+
+	if (wdev->sme_state != CFG80211_SME_IDLE) {
+		err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
+					  dev, WLAN_REASON_DEAUTH_LEAVING);
+		if (err)
+			return err;
+	}
+
+	if (bssid) {
+		memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
+		wdev->wext.connect.bssid = wdev->wext.bssid;
+	} else
+		wdev->wext.connect.bssid = NULL;
+
+	return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
+
+int cfg80211_mgd_wext_giwap(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct sockaddr *ap_addr, char *extra)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	/* call only for station! */
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+		return -EINVAL;
+
+	ap_addr->sa_family = ARPHRD_ETHER;
+
+	if (wdev->wext.connect.bssid) {
+		memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
+		return 0;
+	}
+
+	memcpy(ap_addr->sa_data, wdev->bssid, ETH_ALEN);
+	return 0;
+}
+/* temporary symbol - mark GPL - in the future the handler won't be */
+EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap);
Index: iwm-2.6/net/wireless/mlme.c
===================================================================
--- iwm-2.6.orig/net/wireless/mlme.c	2009-06-22 18:46:24.000000000 +0200
+++ iwm-2.6/net/wireless/mlme.c	2009-06-22 18:46:30.000000000 +0200
@@ -14,33 +14,90 @@
 
 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
 {
-	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	u16 status_code;
+	struct ieee80211_mgmt *mgmt;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	mgmt = (struct ieee80211_mgmt *)buf;
+	status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
 	nl80211_send_rx_auth(rdev, dev, buf, len);
+
+	if (status_code != WLAN_STATUS_SUCCESS)
+		wdev->sme_state = CFG80211_SME_IDLE;
+	else {
+		wdev->sme_state = CFG80211_SME_ASSOC;
+		schedule_work(&rdev->sme_sm);
+	}
 }
 EXPORT_SYMBOL(cfg80211_send_rx_auth);
 
 void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
 {
-	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	u16 status_code;
+	struct ieee80211_mgmt *mgmt;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	mgmt = (struct ieee80211_mgmt *)buf;
+	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
 	nl80211_send_rx_assoc(rdev, dev, buf, len);
+
+	if (status_code != WLAN_STATUS_SUCCESS)
+		wdev->sme_state = CFG80211_SME_AUTH;
+	else {
+		u8 *ie = mgmt->u.assoc_resp.variable;
+
+		wdev->sme_state = CFG80211_SME_CONNECTED;
+		cfg80211_connected(dev, mgmt->bssid,
+				   ie, len - (ie - (u8 *) mgmt),
+				   GFP_ATOMIC);
+	}
 }
 EXPORT_SYMBOL(cfg80211_send_rx_assoc);
 
 void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
 {
-	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
 	nl80211_send_deauth(rdev, dev, buf, len);
+
+	if (wdev->sme_state == CFG80211_SME_CONNECTED ||
+	    wdev->sme_state == CFG80211_SME_ASSOC) {
+		u16 reason_code;
+		struct ieee80211_mgmt *mgmt;
+
+		mgmt = (struct ieee80211_mgmt *)buf;
+		reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
+		cfg80211_disconnected(dev, GFP_ATOMIC, reason_code);
+	}
 }
 EXPORT_SYMBOL(cfg80211_send_deauth);
 
 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
 {
-	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
 	nl80211_send_disassoc(rdev, dev, buf, len);
+
+	if (wdev->sme_state == CFG80211_SME_CONNECTED) {
+		u16 reason_code;
+		struct ieee80211_mgmt *mgmt;
+
+		mgmt = (struct ieee80211_mgmt *)buf;
+		reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+		cfg80211_disconnected(dev, GFP_ATOMIC, reason_code);
+	}
 }
 EXPORT_SYMBOL(cfg80211_send_disassoc);
 
Index: iwm-2.6/net/wireless/core.c
===================================================================
--- iwm-2.6.orig/net/wireless/core.c	2009-06-22 18:46:24.000000000 +0200
+++ iwm-2.6/net/wireless/core.c	2009-06-22 18:46:30.000000000 +0200
@@ -321,6 +321,7 @@ struct wiphy *wiphy_new(const struct cfg
 	}
 
 	INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
+	INIT_WORK(&drv->sme_sm, cfg80211_sme_work);
 
 	/*
 	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
@@ -481,6 +482,8 @@ void wiphy_unregister(struct wiphy *wiph
 	/* unlock again before freeing */
 	mutex_unlock(&drv->mtx);
 
+	cancel_work_sync(&drv->sme_sm);
+
 	cfg80211_debugfs_drv_del(drv);
 
 	/* If this device got a regulatory hint tell core its
@@ -526,54 +529,77 @@ static int cfg80211_netdev_notifier_call
 					 void *ndev)
 {
 	struct net_device *dev = ndev;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev;
 
-	if (!dev->ieee80211_ptr)
+	if (!wdev)
 		return NOTIFY_DONE;
 
-	rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+	rdev = wiphy_to_dev(wdev->wiphy);
 
-	WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
+	WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
 
 	switch (state) {
 	case NETDEV_REGISTER:
 		mutex_lock(&rdev->devlist_mtx);
-		list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
+		list_add(&wdev->list, &rdev->netdev_list);
 		if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
 				      "phy80211")) {
 			printk(KERN_ERR "wireless: failed to add phy80211 "
 				"symlink to netdev!\n");
 		}
-		dev->ieee80211_ptr->netdev = dev;
+		wdev->netdev = dev;
+		wdev->sme_state = CFG80211_SME_IDLE;
+
 #ifdef CONFIG_WIRELESS_EXT
-		dev->ieee80211_ptr->wext.default_key = -1;
-		dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+		wdev->wext.default_key = -1;
+		wdev->wext.default_mgmt_key = -1;
 #endif
 		mutex_unlock(&rdev->devlist_mtx);
 		break;
 	case NETDEV_GOING_DOWN:
-		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+		if (!wdev->ssid_len)
+			break;
+
+		switch (wdev->iftype) {
+		case NL80211_IFTYPE_ADHOC:
+			cfg80211_leave_ibss(rdev, dev, true);
+			break;
+		case NL80211_IFTYPE_STATION:
+			cfg80211_disconnect(rdev, dev,
+					    WLAN_REASON_DEAUTH_LEAVING);
 			break;
-		if (!dev->ieee80211_ptr->ssid_len)
+		default:
 			break;
-		cfg80211_leave_ibss(rdev, dev, true);
+		}
+
 		break;
 	case NETDEV_UP:
 #ifdef CONFIG_WIRELESS_EXT
-		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+		switch (wdev->iftype) {
+		case NL80211_IFTYPE_ADHOC:
+			if (wdev->wext.ibss.ssid_len &&
+			    cfg80211_join_ibss(rdev, dev, &wdev->wext.ibss))
+				return NOTIFY_STOP;
 			break;
-		if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
+		case NL80211_IFTYPE_STATION:
+			if (wdev->wext.connect.ssid_len &&
+			    cfg80211_connect(rdev, dev, &wdev->wext.connect))
+				return NOTIFY_STOP;
 			break;
-		cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
-		break;
+		default:
+			break;
+		}
 #endif
+		break;
 	case NETDEV_UNREGISTER:
 		mutex_lock(&rdev->devlist_mtx);
-		if (!list_empty(&dev->ieee80211_ptr->list)) {
+		if (!list_empty(&wdev->list)) {
 			sysfs_remove_link(&dev->dev.kobj, "phy80211");
-			list_del_init(&dev->ieee80211_ptr->list);
+			list_del_init(&wdev->list);
 		}
 		mutex_unlock(&rdev->devlist_mtx);
+		wdev->sme_state = CFG80211_SME_IDLE;
 		break;
 	case NETDEV_PRE_UP:
 		if (rfkill_blocked(rdev->rfkill))
Index: iwm-2.6/net/wireless/nl80211.h
===================================================================
--- iwm-2.6.orig/net/wireless/nl80211.h	2009-06-22 18:42:44.000000000 +0200
+++ iwm-2.6/net/wireless/nl80211.h	2009-06-22 18:46:30.000000000 +0200
@@ -31,6 +31,13 @@ extern void nl80211_send_auth_timeout(st
 extern void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
 				       struct net_device *netdev,
 				       const u8 *addr);
+void nl80211_send_connected(struct cfg80211_registered_device *rdev,
+			    struct net_device *netdev, const u8 *bssid,
+			    const u8 *ie, size_t ie_len, gfp_t gfp);
+void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
+			       struct net_device *netdev, gfp_t gfp,
+			       u16 reason);
+
 extern void
 nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 			    struct net_device *netdev, const u8 *addr,
-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* [PATCH 2/2 RFC] mac80211: connect API port
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
@ 2009-06-22 17:51 ` Samuel Ortiz
  2009-06-23 11:19   ` Johannes Berg
  2009-06-22 19:08 ` [PATCH 1/2 RFC] cfg80211: connect/disconnect API Johannes Berg
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Samuel Ortiz @ 2009-06-22 17:51 UTC (permalink / raw)
  To: linux-wireless, Johannes Berg; +Cc: Zhu, Yi


With the connect()/disconnect() API, some of the mac80211 STA wext
hooks can now move to cfg80211.

Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
---
 net/mac80211/cfg.c  |   40 +++++++++++++++++----------
 net/mac80211/mlme.c |   15 ----------
 net/mac80211/wext.c |   76 +++++++++-------------------------------------------
 3 files changed, 39 insertions(+), 92 deletions(-)

Index: iwm-2.6/net/mac80211/cfg.c
===================================================================
--- iwm-2.6.orig/net/mac80211/cfg.c	2009-06-22 18:42:43.000000000 +0200
+++ iwm-2.6/net/mac80211/cfg.c	2009-06-22 18:46:35.000000000 +0200
@@ -1173,6 +1173,7 @@ static int ieee80211_auth(struct wiphy *
 			  struct cfg80211_auth_request *req)
 {
 	struct ieee80211_sub_if_data *sdata;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -1193,12 +1194,20 @@ static int ieee80211_auth(struct wiphy *
 		return -EOPNOTSUPP;
 	}
 
-	memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
-	sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-	sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
+	if (req->peer_addr) {
+		memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
+		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
+		sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
+	} else {
+		memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
+		sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
+		sdata->u.mgd.flags &= ~IEEE80211_STA_BSSID_SET;
+	}
 
-	/* TODO: req->chan */
-	sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
+	if (!wdev->channel)
+		sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
+	else
+		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
 	if (req->ssid) {
 		sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
@@ -1220,6 +1229,7 @@ static int ieee80211_auth(struct wiphy *
 
 	sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
 	sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
+
 	ieee80211_sta_req_auth(sdata);
 	return 0;
 }
@@ -1232,27 +1242,26 @@ static int ieee80211_assoc(struct wiphy 
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 ||
-	    !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
+	if ((req->peer_addr &&
+	     memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0) ||
+	     !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
 		return -ENOLINK; /* not authenticated */
 
 	sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
 	sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
 
-	/* TODO: req->chan */
-	sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
-
 	if (req->ssid) {
 		sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
 		memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
 		sdata->u.mgd.ssid_len = req->ssid_len;
 		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
-	} else
-		sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
+	}
 
-	ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
-	if (ret && ret != -EALREADY)
-		return ret;
+	if (req->ie) {
+		ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
+		if (ret && ret != -EALREADY)
+			return ret;
+	}
 
 	if (req->use_mfp) {
 		sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
@@ -1269,6 +1278,7 @@ static int ieee80211_assoc(struct wiphy 
 
 	sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
 	sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
+
 	ieee80211_sta_req_auth(sdata);
 	return 0;
 }
Index: iwm-2.6/net/mac80211/wext.c
===================================================================
--- iwm-2.6.orig/net/mac80211/wext.c	2009-06-22 18:42:43.000000000 +0200
+++ iwm-2.6/net/mac80211/wext.c	2009-06-22 18:46:35.000000000 +0200
@@ -61,7 +61,7 @@ static int ieee80211_ioctl_siwfreq(struc
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
 	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
-		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
+		return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
 	if (freq->e == 0) {
@@ -95,9 +95,6 @@ static int ieee80211_ioctl_siwfreq(struc
 	if (local->oper_channel == chan)
 		return 0;
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION)
-		ieee80211_sta_req_auth(sdata);
-
 	local->oper_channel = chan;
 	local->oper_channel_type = NL80211_CHAN_NO_HT;
 	ieee80211_hw_config(local, 0);
@@ -115,6 +112,8 @@ static int ieee80211_ioctl_giwfreq(struc
 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
 
 	freq->m = local->oper_channel->center_freq;
 	freq->e = 6;
@@ -128,31 +127,11 @@ static int ieee80211_ioctl_siwessid(stru
 				    struct iw_point *data, char *ssid)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	size_t len = data->length;
-	int ret;
 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
-	/* iwconfig uses nul termination in SSID.. */
-	if (len > 0 && ssid[len - 1] == '\0')
-		len--;
-
-	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		if (data->flags)
-			sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
-		else
-			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
-
-		ret = ieee80211_sta_set_ssid(sdata, ssid, len);
-		if (ret)
-			return ret;
-
-		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
-		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-		ieee80211_sta_req_auth(sdata);
-		return 0;
-	}
+	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
 
 	return -EOPNOTSUPP;
 }
@@ -162,23 +141,14 @@ static int ieee80211_ioctl_giwessid(stru
 				    struct iw_request_info *info,
 				    struct iw_point *data, char *ssid)
 {
-	size_t len;
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
-	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
-		if (res == 0) {
-			data->length = len;
-			data->flags = 1;
-		} else
-			data->flags = 0;
-		return res;
-	}
+	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
 
 	return -EOPNOTSUPP;
 }
@@ -193,24 +163,10 @@ static int ieee80211_ioctl_siwap(struct 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		int ret;
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
 
-		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
-			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
-				IEEE80211_STA_AUTO_CHANNEL_SEL;
-		else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
-			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
-		else
-			sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-		ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
-		if (ret)
-			return ret;
-		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
-		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-		ieee80211_sta_req_auth(sdata);
-		return 0;
-	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+	if (sdata->vif.type == NL80211_IFTYPE_WDS) {
 		/*
 		 * If it is necessary to update the WDS peer address
 		 * while the interface is running, then we need to do
@@ -240,14 +196,10 @@ static int ieee80211_ioctl_giwap(struct 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
 
-	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
-			ap_addr->sa_family = ARPHRD_ETHER;
-			memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);
-		} else
-			memset(&ap_addr->sa_data, 0, ETH_ALEN);
-		return 0;
-	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
+
+	if (sdata->vif.type == NL80211_IFTYPE_WDS) {
 		ap_addr->sa_family = ARPHRD_ETHER;
 		memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
 		return 0;
Index: iwm-2.6/net/mac80211/mlme.c
===================================================================
--- iwm-2.6.orig/net/mac80211/mlme.c	2009-06-22 18:42:43.000000000 +0200
+++ iwm-2.6/net/mac80211/mlme.c	2009-06-22 18:46:35.000000000 +0200
@@ -868,17 +868,6 @@ static u32 ieee80211_handle_bss_capabili
 	return changed;
 }
 
-static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)
-{
-	union iwreq_data wrqu;
-
-	memset(&wrqu, 0, sizeof(wrqu));
-	if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)
-		memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
-}
-
 static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -991,8 +980,6 @@ static void ieee80211_set_associated(str
 
 	netif_tx_start_all_queues(sdata->dev);
 	netif_carrier_on(sdata->dev);
-
-	ieee80211_sta_send_apinfo(sdata);
 }
 
 static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
@@ -1143,8 +1130,6 @@ static void ieee80211_set_disassoc(struc
 	changed |= BSS_CHANGED_ASSOC;
 	sdata->vif.bss_conf.assoc = false;
 
-	ieee80211_sta_send_apinfo(sdata);
-
 	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
 		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
 		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
  2009-06-22 17:51 ` [PATCH 2/2 RFC] mac80211: connect API port Samuel Ortiz
@ 2009-06-22 19:08 ` Johannes Berg
  2009-06-23 11:49   ` Samuel Ortiz
  2009-06-22 19:27 ` Johannes Berg
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Johannes Berg @ 2009-06-22 19:08 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

On Mon, 2009-06-22 at 19:04 +0200, Samuel Ortiz wrote:

>  /**
> + * struct cfg80211_connect_params - Connection parameters
> + *
> + * This structure provides information needed to complete IEEE 802.11
> + * authentication and association.
> + *
> + * @channel: The channel to use or %NULL if not specified (auto-select based
> + *	on scan results)
> + * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
> + *	results)
> + * @ssid: SSID
> + * @ssid_len: Length of ssid in octets
> + * @auth_type: Authentication type (algorithm)
> + * @assoc_ie: IEs for association request
> + * @assoc_ie_len: Length of assoc_ie in octets
> + * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
> + *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
> + *	required to assume that the port is unauthorized until authorized by
> + *	user space. Otherwise, port is marked authorized by default.

One question I just had -- if bssid is NULL, and the card selects the
BSSID, I suppose it will also roam by itself if it can [1]. Don't we
need a "roamed" event for that then, even if we're not yet adding a
->roam() call?

johannes

[1] yes, we need to have a way to export roaming capabilities of the
card to user space

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
  2009-06-22 17:51 ` [PATCH 2/2 RFC] mac80211: connect API port Samuel Ortiz
  2009-06-22 19:08 ` [PATCH 1/2 RFC] cfg80211: connect/disconnect API Johannes Berg
@ 2009-06-22 19:27 ` Johannes Berg
  2009-06-23 11:24 ` Johannes Berg
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-22 19:27 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

On Mon, 2009-06-22 at 19:04 +0200, Samuel Ortiz wrote:

> +/**
> + * cfg80211_connected - notify cfg80211 that connection was dropped
> + *
> + * @dev: network device
> + * @gfp: allocation flags
> + * @reason: reason code for the disconnection, set it to 0 when invalid.
> + *
> + */
> +void cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u16 reason);

Shouldn't this also be called, with reason == 0, when a ->disconnect()
call has succeeded? Not sure why it can ever fail, but we have to give
userspace an event somehow.

> +		/*
> +		 * Here we cache the assoc request. It will be used
> +		 * when the cfg80211 user will call cfg80211_authenticated()
> +		 * letting us know that we can move forward and call the
> +		 * assoc hook.
> +		 */
> +		memset(&wdev->assoc_req, 0, sizeof(wdev->assoc_req));
> +		if (connect->channel)
> +			wdev->assoc_req.chan = kmemdup(connect->channel,
> +					       sizeof(struct ieee80211_channel),
> +						       GFP_ATOMIC);

??
->channel always points into the registered channels, that can't go
stale until the wiphy is killed.

> +		if (connect->bssid)
> +			wdev->assoc_req.peer_addr = kmemdup(connect->bssid,
> +							    ETH_ALEN,
> +							    GFP_ATOMIC);

just point it to wdev->bssid?

> +		wdev->assoc_req.ssid = kmemdup(connect->ssid,
> +					       connect->ssid_len,
> +					       GFP_ATOMIC);
> +		wdev->assoc_req.ssid_len = connect->ssid_len;

wdev->ssid?

> +		if (connect->ie)
> +			wdev->assoc_req.ie = kmemdup(connect->ie,
> +						     connect->ie_len,
> +						     GFP_ATOMIC);

Yes, this needs to be kmemdup'ed :) I don't think it needs GFP_ATOMIC
though? This should only be called from nl80211 or wext, i.e. in process
context.

> +	wdev->current_bss = NULL;
> +	wdev->ssid_len = 0;
> +	memset(wdev->bssid, 0, ETH_ALEN);
> +	kfree(wdev->assoc_req.chan);
> +	kfree(wdev->assoc_req.peer_addr);
> +	kfree(wdev->assoc_req.ssid);
> +	kfree(wdev->assoc_req.ie);

Better set = NULL too, since you don't set = NULL in _connect() if the
parameter isn't present.

>  void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
>  {
> -	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> +	u16 status_code;
> +	struct ieee80211_mgmt *mgmt;
> +	struct wireless_dev *wdev = dev->ieee80211_ptr;
> +	struct wiphy *wiphy = wdev->wiphy;
>  	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
> +
> +	mgmt = (struct ieee80211_mgmt *)buf;
> +	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
> +
>  	nl80211_send_rx_assoc(rdev, dev, buf, len);
> +
> +	if (status_code != WLAN_STATUS_SUCCESS)
> +		wdev->sme_state = CFG80211_SME_AUTH;
> +	else {
> +		u8 *ie = mgmt->u.assoc_resp.variable;

I wonder if we should give up, if non-successful auth? Wouldn't this
retry again and again? Well I guess you don't queue the work, but if
another interface causes it to be queued... so I guess we need to retry,
or something, but only a limited number of times? Not sure really.

>  void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
>  {
> -	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> +	struct wireless_dev *wdev = dev->ieee80211_ptr;
> +	struct wiphy *wiphy = wdev->wiphy;
>  	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
> +
>  	nl80211_send_deauth(rdev, dev, buf, len);
> +
> +	if (wdev->sme_state == CFG80211_SME_CONNECTED ||
> +	    wdev->sme_state == CFG80211_SME_ASSOC) {
> +		u16 reason_code;
> +		struct ieee80211_mgmt *mgmt;
> +
> +		mgmt = (struct ieee80211_mgmt *)buf;
> +		reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
> +
> +		cfg80211_disconnected(dev, GFP_ATOMIC, reason_code);
> +	}

This might be interesting -- you could get a disconnected event without
ever asking for connected. But that indicates we need yet another event:
"I've given up on connect"?

>  EXPORT_SYMBOL(cfg80211_send_deauth);
>  
>  void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
>  {
> -	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
> +	struct wireless_dev *wdev = dev->ieee80211_ptr;
> +	struct wiphy *wiphy = wdev->wiphy;
>  	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
> +
>  	nl80211_send_disassoc(rdev, dev, buf, len);
> +
> +	if (wdev->sme_state == CFG80211_SME_CONNECTED) {
> +		u16 reason_code;
> +		struct ieee80211_mgmt *mgmt;
> +
> +		mgmt = (struct ieee80211_mgmt *)buf;
> +		reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
> +
> +		cfg80211_disconnected(dev, GFP_ATOMIC, reason_code);
> +	}

I suspect it needs to be valid to call this without a frame, if you just
get that indication from firmware somehow. However, then there's no
reason code to pass. Maybe we just need a second exported symbol in that
case and not worry about it now. Doesn't need to be perfect, after
all :)

>  EXPORT_SYMBOL(cfg80211_send_disassoc);
>  
> Index: iwm-2.6/net/wireless/core.c
> ===================================================================
> --- iwm-2.6.orig/net/wireless/core.c	2009-06-22 18:46:24.000000000 +0200
> +++ iwm-2.6/net/wireless/core.c	2009-06-22 18:46:30.000000000 +0200
> @@ -321,6 +321,7 @@ struct wiphy *wiphy_new(const struct cfg
>  	}
>  
>  	INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
> +	INIT_WORK(&drv->sme_sm, cfg80211_sme_work);
>  
>  	/*
>  	 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
> @@ -481,6 +482,8 @@ void wiphy_unregister(struct wiphy *wiph
>  	/* unlock again before freeing */
>  	mutex_unlock(&drv->mtx);
>  
> +	cancel_work_sync(&drv->sme_sm);
> +
>  	cfg80211_debugfs_drv_del(drv);
>  
>  	/* If this device got a regulatory hint tell core its
> @@ -526,54 +529,77 @@ static int cfg80211_netdev_notifier_call
>  					 void *ndev)
>  {
>  	struct net_device *dev = ndev;
> +	struct wireless_dev *wdev = dev->ieee80211_ptr;
>  	struct cfg80211_registered_device *rdev;
>  
> -	if (!dev->ieee80211_ptr)
> +	if (!wdev)
>  		return NOTIFY_DONE;
>  
> -	rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
> +	rdev = wiphy_to_dev(wdev->wiphy);
>  
> -	WARN_ON(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_UNSPECIFIED);
> +	WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
>  
>  	switch (state) {
>  	case NETDEV_REGISTER:
>  		mutex_lock(&rdev->devlist_mtx);
> -		list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
> +		list_add(&wdev->list, &rdev->netdev_list);
>  		if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
>  				      "phy80211")) {
>  			printk(KERN_ERR "wireless: failed to add phy80211 "
>  				"symlink to netdev!\n");
>  		}
> -		dev->ieee80211_ptr->netdev = dev;
> +		wdev->netdev = dev;
> +		wdev->sme_state = CFG80211_SME_IDLE;
> +
>  #ifdef CONFIG_WIRELESS_EXT
> -		dev->ieee80211_ptr->wext.default_key = -1;
> -		dev->ieee80211_ptr->wext.default_mgmt_key = -1;
> +		wdev->wext.default_key = -1;
> +		wdev->wext.default_mgmt_key = -1;
>  #endif
>  		mutex_unlock(&rdev->devlist_mtx);
>  		break;
>  	case NETDEV_GOING_DOWN:
> -		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
> +		if (!wdev->ssid_len)
> +			break;
> +
> +		switch (wdev->iftype) {
> +		case NL80211_IFTYPE_ADHOC:
> +			cfg80211_leave_ibss(rdev, dev, true);
> +			break;
> +		case NL80211_IFTYPE_STATION:
> +			cfg80211_disconnect(rdev, dev,
> +					    WLAN_REASON_DEAUTH_LEAVING);
>  			break;
> -		if (!dev->ieee80211_ptr->ssid_len)
> +		default:
>  			break;
> -		cfg80211_leave_ibss(rdev, dev, true);
> +		}
> +
>  		break;
>  	case NETDEV_UP:
>  #ifdef CONFIG_WIRELESS_EXT
> -		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
> +		switch (wdev->iftype) {
> +		case NL80211_IFTYPE_ADHOC:
> +			if (wdev->wext.ibss.ssid_len &&
> +			    cfg80211_join_ibss(rdev, dev, &wdev->wext.ibss))
> +				return NOTIFY_STOP;
>  			break;
> -		if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
> +		case NL80211_IFTYPE_STATION:
> +			if (wdev->wext.connect.ssid_len &&
> +			    cfg80211_connect(rdev, dev, &wdev->wext.connect))
> +				return NOTIFY_STOP;
>  			break;
> -		cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
> -		break;
> +		default:
> +			break;
> +		}
>  #endif
> +		break;

Wow, that fixes a bad bug if you don't have wext configured. Good thing
that's currently pretty much impossible.

Thanks!

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 2/2 RFC] mac80211: connect API port
  2009-06-22 17:51 ` [PATCH 2/2 RFC] mac80211: connect API port Samuel Ortiz
@ 2009-06-23 11:19   ` Johannes Berg
  2009-06-23 11:37     ` Samuel Ortiz
  0 siblings, 1 reply; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:19 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

On Mon, 2009-06-22 at 19:51 +0200, Samuel Ortiz wrote:
> With the connect()/disconnect() API, some of the mac80211 STA wext
> hooks can now move to cfg80211.
> 
> Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
> ---
>  net/mac80211/cfg.c  |   40 +++++++++++++++++----------
>  net/mac80211/mlme.c |   15 ----------

---
 net/mac80211/mlme.c |   54 ----------------------------------------------------
 1 file changed, 54 deletions(-)

--- wireless-testing.orig/net/mac80211/mlme.c	2009-06-23 13:18:25.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-06-23 13:18:37.000000000 +0200
@@ -868,59 +868,6 @@ static u32 ieee80211_handle_bss_capabili
 	return changed;
 }
 
-static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	char *buf;
-	size_t len;
-	int i;
-	union iwreq_data wrqu;
-
-	if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
-		return;
-
-	buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
-				ifmgd->assocresp_ies_len), GFP_KERNEL);
-	if (!buf)
-		return;
-
-	len = sprintf(buf, "ASSOCINFO(");
-	if (ifmgd->assocreq_ies) {
-		len += sprintf(buf + len, "ReqIEs=");
-		for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifmgd->assocreq_ies[i]);
-		}
-	}
-	if (ifmgd->assocresp_ies) {
-		if (ifmgd->assocreq_ies)
-			len += sprintf(buf + len, " ");
-		len += sprintf(buf + len, "RespIEs=");
-		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifmgd->assocresp_ies[i]);
-		}
-	}
-	len += sprintf(buf + len, ")");
-
-	if (len > IW_CUSTOM_MAX) {
-		len = sprintf(buf, "ASSOCRESPIE=");
-		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
-			len += sprintf(buf + len, "%02x",
-				       ifmgd->assocresp_ies[i]);
-		}
-	}
-
-	if (len <= IW_CUSTOM_MAX) {
-		memset(&wrqu, 0, sizeof(wrqu));
-		wrqu.data.length = len;
-		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
-	}
-
-	kfree(buf);
-}
-
-
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 				     u32 bss_info_changed)
 {
@@ -953,7 +900,6 @@ static void ieee80211_set_associated(str
 
 	ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
 	memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
-	ieee80211_sta_send_associnfo(sdata);
 
 	ifmgd->last_probe = jiffies;
 	ieee80211_led_assoc(local, 1);



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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
                   ` (2 preceding siblings ...)
  2009-06-22 19:27 ` Johannes Berg
@ 2009-06-23 11:24 ` Johannes Berg
  2009-06-23 11:25 ` Johannes Berg
  2009-06-23 11:28 ` Johannes Berg
  5 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:24 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

[  176.185771] WARNING: at /home/johannes/sys/wireless-testing/net/wireless/sme.c:46 cfg80211_connected+0x149/0x150()
[  176.197900] Hardware name: 
[  176.202752] Pid: 468, comm: phy1 Tainted: G        W  2.6.30-wl #71
[  176.209012] Call Trace:
[  176.218526]  [<ffffffff8024ae93>] warn_slowpath_common+0x73/0xc0
[  176.219258]  [<ffffffff8024aeef>] warn_slowpath_null+0xf/0x20
[  176.219966]  [<ffffffff805a58f9>] cfg80211_connected+0x149/0x150
[  176.221854]  [<ffffffff805a5136>] cfg80211_send_rx_assoc+0x96/0xa0
[  176.226272]  [<ffffffff805b28ec>] ieee80211_rx_mgmt_assoc_resp+0x71c/0x8a0

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
                   ` (3 preceding siblings ...)
  2009-06-23 11:24 ` Johannes Berg
@ 2009-06-23 11:25 ` Johannes Berg
  2009-06-23 11:28 ` Johannes Berg
  5 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:25 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

And this, symmetric to the first one:

[  302.975063] WARNING: at /home/johannes/sys/wireless-testing/net/wireless/sme.c:95 cfg80211_disconnected+0x9d/0xc0()
[  302.976435] Hardware name: 
[  302.976869] Pid: 1321, comm: wpa_supplicant Tainted: G        W  2.6.30-wl #71
[  302.977819] Call Trace:
[  302.980113]  [<ffffffff8024ae93>] warn_slowpath_common+0x73/0xc0
[  302.981529]  [<ffffffff8024aeef>] warn_slowpath_null+0xf/0x20
[  302.982356]  [<ffffffff805a578d>] cfg80211_disconnected+0x9d/0xc0
[  302.983205]  [<ffffffff805a5092>] cfg80211_send_deauth+0x72/0x80
[  302.995239]  [<ffffffff805af634>] ieee80211_send_deauth_disassoc+0x144/0x160
[  303.005284]  [<ffffffff805af7e5>] ieee80211_set_disassoc+0x195/0x3d0
[  303.023982]  [<ffffffff805afac2>] ieee80211_sta_deauthenticate+0x42/0x50
[  303.027995]  [<ffffffff805b6ef7>] ieee80211_deauth+0x17/0x20
[  303.028830]  [<ffffffff8059dd7b>] nl80211_deauthenticate+0x14b/0x160

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
                   ` (4 preceding siblings ...)
  2009-06-23 11:25 ` Johannes Berg
@ 2009-06-23 11:28 ` Johannes Berg
  5 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:28 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

Also, something seems to be wrong with the IEs:

hostapd says:
STA 02:00:00:00:01:00: No WPA/RSN IE in association request

and the client gets:
[  469.426983] wlan1: RX AssocResp from 00:11:24:91:07:4d (capab=0x411 status=40 aid=0)
[  469.428119] wlan1: AP denied association (code=40)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 2/2 RFC] mac80211: connect API port
  2009-06-23 11:19   ` Johannes Berg
@ 2009-06-23 11:37     ` Samuel Ortiz
  2009-06-23 11:41       ` Johannes Berg
  0 siblings, 1 reply; 12+ messages in thread
From: Samuel Ortiz @ 2009-06-23 11:37 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Zhu, Yi

Hi Johannes,

On Tue, Jun 23, 2009 at 01:19:07PM +0200, Johannes Berg wrote:
> On Mon, 2009-06-22 at 19:51 +0200, Samuel Ortiz wrote:
> > With the connect()/disconnect() API, some of the mac80211 STA wext
> > hooks can now move to cfg80211.
> > 
> > Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com>
> > ---
> >  net/mac80211/cfg.c  |   40 +++++++++++++++++----------
> >  net/mac80211/mlme.c |   15 ----------
> 
> ---
>  net/mac80211/mlme.c |   54 ----------------------------------------------------
>  1 file changed, 54 deletions(-)
I thought about this one, but wasnt sure since we're now sending an
IWEVASSOCRESPIE event while the current code is sending a custom one. I guess
it's fine, just wanted to know if Jouni is fine with it.

Cheers,
Samuel.


> --- wireless-testing.orig/net/mac80211/mlme.c	2009-06-23 13:18:25.000000000 +0200
> +++ wireless-testing/net/mac80211/mlme.c	2009-06-23 13:18:37.000000000 +0200
> @@ -868,59 +868,6 @@ static u32 ieee80211_handle_bss_capabili
>  	return changed;
>  }
>  
> -static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
> -{
> -	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
> -	char *buf;
> -	size_t len;
> -	int i;
> -	union iwreq_data wrqu;
> -
> -	if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
> -		return;
> -
> -	buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
> -				ifmgd->assocresp_ies_len), GFP_KERNEL);
> -	if (!buf)
> -		return;
> -
> -	len = sprintf(buf, "ASSOCINFO(");
> -	if (ifmgd->assocreq_ies) {
> -		len += sprintf(buf + len, "ReqIEs=");
> -		for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
> -			len += sprintf(buf + len, "%02x",
> -				       ifmgd->assocreq_ies[i]);
> -		}
> -	}
> -	if (ifmgd->assocresp_ies) {
> -		if (ifmgd->assocreq_ies)
> -			len += sprintf(buf + len, " ");
> -		len += sprintf(buf + len, "RespIEs=");
> -		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
> -			len += sprintf(buf + len, "%02x",
> -				       ifmgd->assocresp_ies[i]);
> -		}
> -	}
> -	len += sprintf(buf + len, ")");
> -
> -	if (len > IW_CUSTOM_MAX) {
> -		len = sprintf(buf, "ASSOCRESPIE=");
> -		for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
> -			len += sprintf(buf + len, "%02x",
> -				       ifmgd->assocresp_ies[i]);
> -		}
> -	}
> -
> -	if (len <= IW_CUSTOM_MAX) {
> -		memset(&wrqu, 0, sizeof(wrqu));
> -		wrqu.data.length = len;
> -		wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
> -	}
> -
> -	kfree(buf);
> -}
> -
> -
>  static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
>  				     u32 bss_info_changed)
>  {
> @@ -953,7 +900,6 @@ static void ieee80211_set_associated(str
>  
>  	ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
>  	memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
> -	ieee80211_sta_send_associnfo(sdata);
>  
>  	ifmgd->last_probe = jiffies;
>  	ieee80211_led_assoc(local, 1);
> 
> 

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH 2/2 RFC] mac80211: connect API port
  2009-06-23 11:37     ` Samuel Ortiz
@ 2009-06-23 11:41       ` Johannes Berg
  0 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:41 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

On Tue, 2009-06-23 at 13:37 +0200, Samuel Ortiz wrote:
> Hi Johannes,

> >  net/mac80211/mlme.c |   54 ----------------------------------------------------
> >  1 file changed, 54 deletions(-)
> I thought about this one, but wasnt sure since we're now sending an
> IWEVASSOCRESPIE event while the current code is sending a custom one. I guess
> it's fine, just wanted to know if Jouni is fine with it.

Complicated story, but it boils down to this being ok if (and only if!)
we put in the wext compat event patch. If not, we need to send the
custom event in cfg80211. Maybe that's safer for now.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-22 19:08 ` [PATCH 1/2 RFC] cfg80211: connect/disconnect API Johannes Berg
@ 2009-06-23 11:49   ` Samuel Ortiz
  2009-06-23 11:53     ` Johannes Berg
  0 siblings, 1 reply; 12+ messages in thread
From: Samuel Ortiz @ 2009-06-23 11:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Zhu, Yi

On Mon, Jun 22, 2009 at 09:08:39PM +0200, Johannes Berg wrote:
> On Mon, 2009-06-22 at 19:04 +0200, Samuel Ortiz wrote:
> 
> >  /**
> > + * struct cfg80211_connect_params - Connection parameters
> > + *
> > + * This structure provides information needed to complete IEEE 802.11
> > + * authentication and association.
> > + *
> > + * @channel: The channel to use or %NULL if not specified (auto-select based
> > + *	on scan results)
> > + * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
> > + *	results)
> > + * @ssid: SSID
> > + * @ssid_len: Length of ssid in octets
> > + * @auth_type: Authentication type (algorithm)
> > + * @assoc_ie: IEs for association request
> > + * @assoc_ie_len: Length of assoc_ie in octets
> > + * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
> > + *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
> > + *	required to assume that the port is unauthorized until authorized by
> > + *	user space. Otherwise, port is marked authorized by default.
> 
> One question I just had -- if bssid is NULL, and the card selects the
> BSSID, I suppose it will also roam by itself if it can [1]. Don't we
> need a "roamed" event for that then, even if we're not yet adding a
> ->roam() call?
I guess userspace will get 2 events: a disconnect one and then a connect one.
Not exactly a "roamed" event though, I agree.

Cheers,
Samuel.

 
> johannes
> 
> [1] yes, we need to have a way to export roaming capabilities of the
> card to user space



-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH 1/2 RFC] cfg80211: connect/disconnect API
  2009-06-23 11:49   ` Samuel Ortiz
@ 2009-06-23 11:53     ` Johannes Berg
  0 siblings, 0 replies; 12+ messages in thread
From: Johannes Berg @ 2009-06-23 11:53 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: linux-wireless, Zhu, Yi

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

On Tue, 2009-06-23 at 13:49 +0200, Samuel Ortiz wrote:

> > One question I just had -- if bssid is NULL, and the card selects the
> > BSSID, I suppose it will also roam by itself if it can [1]. Don't we
> > need a "roamed" event for that then, even if we're not yet adding a
> > ->roam() call?
> I guess userspace will get 2 events: a disconnect one and then a connect one.
> Not exactly a "roamed" event though, I agree.

Ok, I guess then it needs to distinguish between a disconnect that it
caused locally (or some other userspace tool), and a disconnect that the
AP caused.

OTOH, I don't think this is appropriate. I think after a disconnect
event, the kernel/device should stop doing _anything_. Otherwise we'll,
on a smaller scale, repeat the wext problem where you don't know whether
the device is currently doing something or not.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

end of thread, other threads:[~2009-06-23 11:53 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-22 17:04 [PATCH 1/2 RFC] cfg80211: connect/disconnect API Samuel Ortiz
2009-06-22 17:51 ` [PATCH 2/2 RFC] mac80211: connect API port Samuel Ortiz
2009-06-23 11:19   ` Johannes Berg
2009-06-23 11:37     ` Samuel Ortiz
2009-06-23 11:41       ` Johannes Berg
2009-06-22 19:08 ` [PATCH 1/2 RFC] cfg80211: connect/disconnect API Johannes Berg
2009-06-23 11:49   ` Samuel Ortiz
2009-06-23 11:53     ` Johannes Berg
2009-06-22 19:27 ` Johannes Berg
2009-06-23 11:24 ` Johannes Berg
2009-06-23 11:25 ` Johannes Berg
2009-06-23 11:28 ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.