All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] cfg80211: add channel switch notify event
@ 2012-04-06 20:35 Thomas Pedersen
  2012-04-06 20:35 ` [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen
  2012-04-12  3:37 ` [PATCH v3 1/2] cfg80211: add channel switch notify event Johannes Berg
  0 siblings, 2 replies; 6+ messages in thread
From: Thomas Pedersen @ 2012-04-06 20:35 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless, Thomas Pedersen

The firmware may decide to switch channels while already beaconing, e.g.
in response to a cfg80211 connect request on a different vif. Add this
event to notify userspace when an AP or GO interface has successfully
migrated to a new channel, so it can update its configuration
accordingly.

Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>
---
v2: update wdev->channel (Johannes)
    enforce AP or GO interface type

v3: only support GFP_KERNEL context (Johannes)

 include/linux/nl80211.h |    7 +++++++
 include/net/cfg80211.h  |   11 +++++++++++
 net/wireless/mlme.c     |   27 +++++++++++++++++++++++++++
 net/wireless/nl80211.c  |   32 ++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    4 ++++
 5 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e474f6e..49f2bbe 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -548,6 +548,11 @@
  * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
  *      No Acknowledgement Policy should be applied.
  *
+ * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
+ *	independently of the userspace SME, send this event indicating
+ *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
+ *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -689,6 +694,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_SET_NOACK_MAP,
 
+	NL80211_CMD_CH_SWITCH_NOTIFY,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 69b7ad3..0f246b6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3340,6 +3340,17 @@ int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 				 enum nl80211_channel_type channel_type);
 
 /*
+ * cfg80211_ch_switch_notify - update wdev channel and notify userspace
+ * @dev: the device which switched channels
+ * @freq: new channel frequency (in MHz)
+ * @type: channel type
+ *
+ * Acquires wdev_lock, so must only be called from sleepable driver context!
+ */
+void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
+			       enum nl80211_channel_type type);
+
+/*
  * cfg80211_calculate_bitrate - calculate actual bitrate (in 100Kbps units)
  * @rate: given rate_info to calculate bitrate from
  *
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index f5a7ac3..50da120 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -928,6 +928,33 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
 
+void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
+			       enum nl80211_channel_type type)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+	struct ieee80211_channel *chan;
+
+	wdev_lock(wdev);
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+		    wdev->iftype != NL80211_IFTYPE_P2P_GO))
+		goto out;
+
+	chan = rdev_freq_to_chan(rdev, freq, type);
+	if (WARN_ON(!chan))
+		goto out;
+
+	wdev->channel = chan;
+
+	nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
+out:
+	wdev_unlock(wdev);
+	return;
+}
+EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
 bool cfg80211_rx_spurious_frame(struct net_device *dev,
 				const u8 *addr, gfp_t gfp)
 {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4c1eb94..d5d489f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7890,6 +7890,38 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 	nlmsg_free(msg);
 }
 
+void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+			      struct net_device *netdev, int freq,
+			      enum nl80211_channel_type type, 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_CH_SWITCH_NOTIFY);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type);
+
+	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_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 				struct net_device *netdev, const u8 *peer,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 4ffe50d..01a1122 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -118,6 +118,10 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 				    struct net_device *netdev, int index,
 				    const u8 *bssid, bool preauth, gfp_t gfp);
 
+void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+			      struct net_device *dev, int freq,
+			      enum nl80211_channel_type type, gfp_t gfp);
+
 bool nl80211_unexpected_frame(struct net_device *dev,
 			      const u8 *addr, gfp_t gfp);
 bool nl80211_unexpected_4addr_frame(struct net_device *dev,
-- 
1.7.4.1


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

* [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches
  2012-04-06 20:35 [PATCH v3 1/2] cfg80211: add channel switch notify event Thomas Pedersen
@ 2012-04-06 20:35 ` Thomas Pedersen
  2012-04-09 15:05   ` Kalle Valo
  2012-04-12  6:56   ` Kalle Valo
  2012-04-12  3:37 ` [PATCH v3 1/2] cfg80211: add channel switch notify event Johannes Berg
  1 sibling, 2 replies; 6+ messages in thread
From: Thomas Pedersen @ 2012-04-06 20:35 UTC (permalink / raw)
  To: kvalo; +Cc: ath6kl-devel, linux-wireless, Thomas Pedersen

If an ath6kl AP vif is beaconing on one channel, and a STA vif
associates on a different channel, a WMI_DISCONNECT event will be sent
to the AP vif. Make the AP vif follow the STA interface, and notify
userspace.

Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>
---
v2: coalesce formats (Joe)
v3: cfg80211 API changed

 drivers/net/wireless/ath/ath6kl/cfg80211.c |   15 ++++++++
 drivers/net/wireless/ath/ath6kl/cfg80211.h |    2 +
 drivers/net/wireless/ath/ath6kl/core.h     |    2 +
 drivers/net/wireless/ath/ath6kl/main.c     |   55 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath6kl/wmi.h      |   12 ++++++
 5 files changed, 85 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 1272508..1079bf1 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1015,6 +1015,20 @@ out:
 	vif->scan_req = NULL;
 }
 
+void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
+				      enum wmi_phy_mode mode)
+{
+	enum nl80211_channel_type type;
+
+	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+		   "channel switch notify nw_type %d freq %d mode %d\n",
+		   vif->nw_type, freq, mode);
+
+	type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
+
+	cfg80211_ch_switch_notify(vif->ndev, freq, type);
+}
+
 static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 				   u8 key_index, bool pairwise,
 				   const u8 *mac_addr,
@@ -2643,6 +2657,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 			return res;
 	}
 
+	memcpy(&vif->profile, &p, sizeof(p));
 	res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
 	if (res < 0)
 		return res;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index c5def43..5ea8cbb 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode {
 struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
 					enum nl80211_iftype type,
 					u8 fw_vif_idx, u8 nw_type);
+void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
+				      enum wmi_phy_mode mode);
 void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
 
 void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 75b1d86..0b4078d 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -540,6 +540,7 @@ struct ath6kl_vif {
 	u8 assoc_bss_dtim_period;
 	struct net_device_stats net_stats;
 	struct target_stats target_stats;
+	struct wmi_connect_cmd profile;
 
 	struct list_head mc_filter;
 };
@@ -628,6 +629,7 @@ struct ath6kl {
 	u8 sta_list_index;
 	struct ath6kl_req_key ap_mode_bkey;
 	struct sk_buff_head mcastpsq;
+	u32 want_ch_switch;
 
 	/*
 	 * FIXME: protects access to mcastpsq but is actually useless as
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 7f3addd..58468e0 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -434,6 +434,13 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
 		break;
 	}
 
+	if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
+		ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+		/* we actually don't know the phymode, default to HT20 */
+		ath6kl_cfg80211_ch_switch_notify(vif, channel,
+						 WMI_11G_HT20);
+	}
+
 	ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
 	set_bit(CONNECTED, &vif->flags);
 	netif_carrier_on(vif->ndev);
@@ -582,6 +589,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
 	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status);
 }
 
+static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
+{
+
+	struct ath6kl *ar = vif->ar;
+
+	vif->next_chan = cpu_to_le16(channel);
+	vif->profile.ch = cpu_to_le16(channel);
+
+	switch (vif->nw_type) {
+	case AP_NETWORK:
+		return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
+						    &vif->profile);
+	default:
+		ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type);
+		return -ENOTSUPP;
+	}
+}
+
+static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
+{
+
+	struct ath6kl_vif *vif;
+	int res = 0;
+
+	if (!ar->want_ch_switch)
+		return;
+
+	spin_lock_bh(&ar->list_lock);
+	list_for_each_entry(vif, &ar->vif_list, list) {
+		if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
+			res = ath6kl_commit_ch_switch(vif, channel);
+
+		if (res)
+			ath6kl_err("channel switch failed nw_type %d res %d\n",
+				   vif->nw_type, res);
+	}
+	spin_unlock_bh(&ar->list_lock);
+}
+
 void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
 			  u16 listen_int, u16 beacon_int,
 			  enum network_type net_type, u8 beacon_ie_len,
@@ -599,9 +645,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
 	memcpy(vif->bssid, bssid, sizeof(vif->bssid));
 	vif->bss_ch = channel;
 
-	if ((vif->nw_type == INFRA_NETWORK))
+	if ((vif->nw_type == INFRA_NETWORK)) {
 		ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
 					      vif->listen_intvl_t, 0);
+		ath6kl_check_ch_switch(ar, channel);
+	}
 
 	netif_wake_queue(vif->ndev);
 
@@ -924,6 +972,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
 	struct ath6kl *ar = vif->ar;
 
 	if (vif->nw_type == AP_NETWORK) {
+		/* disconnect due to other STA vif switching channels */
+		if (reason == BSS_DISCONNECTED &&
+		    prot_reason_status == WMI_AP_REASON_STA_ROAM)
+			ar->want_ch_switch |= 1 << vif->fw_vif_idx;
+
 		if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
 			return;
 
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index b99e9bd..88a1603 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1145,6 +1145,7 @@ enum wmi_phy_mode {
 	WMI_11AG_MODE = 0x3,
 	WMI_11B_MODE = 0x4,
 	WMI_11GONLY_MODE = 0x5,
+	WMI_11G_HT20	= 0x6,
 };
 
 #define WMI_MAX_CHANNELS        32
@@ -1452,6 +1453,17 @@ enum wmi_disconnect_reason {
 	IBSS_MERGE = 0xe,
 };
 
+/* AP mode disconnect proto_reasons */
+enum ap_disconnect_reason {
+	WMI_AP_REASON_STA_LEFT		= 101,
+	WMI_AP_REASON_FROM_HOST		= 102,
+	WMI_AP_REASON_COMM_TIMEOUT	= 103,
+	WMI_AP_REASON_MAX_STA		= 104,
+	WMI_AP_REASON_ACL		= 105,
+	WMI_AP_REASON_STA_ROAM		= 106,
+	WMI_AP_REASON_DFS_CHANNEL	= 107,
+};
+
 #define ATH6KL_COUNTRY_RD_SHIFT        16
 
 struct ath6kl_wmi_regdomain {
-- 
1.7.4.1


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

* Re: [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches
  2012-04-06 20:35 ` [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen
@ 2012-04-09 15:05   ` Kalle Valo
  2012-04-11 19:35     ` John W. Linville
  2012-04-12  6:56   ` Kalle Valo
  1 sibling, 1 reply; 6+ messages in thread
From: Kalle Valo @ 2012-04-09 15:05 UTC (permalink / raw)
  To: John W. Linville; +Cc: Thomas Pedersen, ath6kl-devel, linux-wireless

On 04/06/2012 11:35 PM, Thomas Pedersen wrote:
> If an ath6kl AP vif is beaconing on one channel, and a STA vif
> associates on a different channel, a WMI_DISCONNECT event will be sent
> to the AP vif. Make the AP vif follow the STA interface, and notify
> userspace.
> 
> Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>

John, if it's ok for you I can take this patch ath6kl.git once you have
applied the cfg80211 patch.

Kalle

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

* Re: [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches
  2012-04-09 15:05   ` Kalle Valo
@ 2012-04-11 19:35     ` John W. Linville
  0 siblings, 0 replies; 6+ messages in thread
From: John W. Linville @ 2012-04-11 19:35 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Thomas Pedersen, ath6kl-devel, linux-wireless

On Mon, Apr 09, 2012 at 06:05:10PM +0300, Kalle Valo wrote:
> On 04/06/2012 11:35 PM, Thomas Pedersen wrote:
> > If an ath6kl AP vif is beaconing on one channel, and a STA vif
> > associates on a different channel, a WMI_DISCONNECT event will be sent
> > to the AP vif. Make the AP vif follow the STA interface, and notify
> > userspace.
> > 
> > Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>
> 
> John, if it's ok for you I can take this patch ath6kl.git once you have
> applied the cfg80211 patch.

OK.

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

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

* Re: [PATCH v3 1/2] cfg80211: add channel switch notify event
  2012-04-06 20:35 [PATCH v3 1/2] cfg80211: add channel switch notify event Thomas Pedersen
  2012-04-06 20:35 ` [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen
@ 2012-04-12  3:37 ` Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2012-04-12  3:37 UTC (permalink / raw)
  To: Thomas Pedersen; +Cc: kvalo, ath6kl-devel, linux-wireless

On Fri, 2012-04-06 at 13:35 -0700, Thomas Pedersen wrote:

>  /*
> + * cfg80211_ch_switch_notify - update wdev channel and notify userspace
> + * @dev: the device which switched channels
> + * @freq: new channel frequency (in MHz)
> + * @type: channel type
> + *
> + * Acquires wdev_lock, so must only be called from sleepable driver context!
> + */
> +void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
> +			       enum nl80211_channel_type type);

I think this could be a bit more detailed -- the driver authors won't
know what wdev_lock is (nor care), but the other consequence of it is
that the function absolutely must not be called in the context of a
cfg80211 call into the driver.

johannes


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

* Re: [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches
  2012-04-06 20:35 ` [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen
  2012-04-09 15:05   ` Kalle Valo
@ 2012-04-12  6:56   ` Kalle Valo
  1 sibling, 0 replies; 6+ messages in thread
From: Kalle Valo @ 2012-04-12  6:56 UTC (permalink / raw)
  To: Thomas Pedersen; +Cc: ath6kl-devel, linux-wireless

On 04/06/2012 11:35 PM, Thomas Pedersen wrote:
> If an ath6kl AP vif is beaconing on one channel, and a STA vif
> associates on a different channel, a WMI_DISCONNECT event will be sent
> to the AP vif. Make the AP vif follow the STA interface, and notify
> userspace.
> 
> Signed-off-by: Thomas Pedersen <c_tpeder@qca.qualcomm.com>

Thanks, applied. But there was a sparse warning:

drivers/net/wireless/ath/ath6kl/main.c:599:24: warning: incorrect type
in assignment (different base types)
drivers/net/wireless/ath/ath6kl/main.c:599:24:    expected unsigned
short [unsigned] [usertype] next_chan
drivers/net/wireless/ath/ath6kl/main.c:599:24:    got restricted __le16
[usertype] <noident>

I fixed it like this:

	vif->next_chan = channel;
	vif->profile.ch = cpu_to_le16(channel);

Please check my changes.

Kalle

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

end of thread, other threads:[~2012-04-12  6:56 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-06 20:35 [PATCH v3 1/2] cfg80211: add channel switch notify event Thomas Pedersen
2012-04-06 20:35 ` [PATCH v3 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen
2012-04-09 15:05   ` Kalle Valo
2012-04-11 19:35     ` John W. Linville
2012-04-12  6:56   ` Kalle Valo
2012-04-12  3:37 ` [PATCH v3 1/2] cfg80211: add channel switch notify event 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.