* [PATCH 1/2] cfg80211: add channel switch notify event @ 2012-04-04 18:56 Thomas Pedersen 2012-04-04 18:56 ` [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen 0 siblings, 1 reply; 5+ messages in thread From: Thomas Pedersen @ 2012-04-04 18:56 UTC (permalink / raw) To: linux-wireless; +Cc: ath6kl-devel, 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> --- include/linux/nl80211.h | 7 +++++++ include/net/cfg80211.h | 10 ++++++++++ net/wireless/mlme.c | 11 +++++++++++ net/wireless/nl80211.c | 32 ++++++++++++++++++++++++++++++++ net/wireless/nl80211.h | 4 ++++ 5 files changed, 64 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..eadc897 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3340,6 +3340,16 @@ int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, enum nl80211_channel_type channel_type); /* + * cfg80211_ch_switch_notify - notify userspace about netdev channel switch + * @dev: the device which switched channels + * @freq: new channel frequency (in MHz) + * @type: channel type + * @gfp: allocation flags + */ +void cfg80211_ch_switch_notify(struct net_device *dev, int freq, + enum nl80211_channel_type type, gfp_t gfp); + +/* * 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..895a5ba 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -928,6 +928,17 @@ 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, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_ch_switch_notify(rdev, dev, freq, type, gfp); +} +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] 5+ messages in thread
* [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches 2012-04-04 18:56 [PATCH 1/2] cfg80211: add channel switch notify event Thomas Pedersen @ 2012-04-04 18:56 ` Thomas Pedersen 2012-04-04 19:02 ` Joe Perches 0 siblings, 1 reply; 5+ messages in thread From: Thomas Pedersen @ 2012-04-04 18:56 UTC (permalink / raw) To: linux-wireless; +Cc: ath6kl-devel, 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> --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 14 +++++++ 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, 84 insertions(+), 1 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 1272508..5d7eac7 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1015,6 +1015,19 @@ out: vif->scan_req = NULL; } +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int channel, + 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", vif->nw_type, channel, mode); + + type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + + cfg80211_ch_switch_notify(vif->ndev, channel, type, GFP_KERNEL); +} + static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr, @@ -2643,6 +2656,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..7fc7518 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 channel, + 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] 5+ messages in thread
* Re: [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches 2012-04-04 18:56 ` [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen @ 2012-04-04 19:02 ` Joe Perches 2012-04-04 20:00 ` Pedersen, Thomas 0 siblings, 1 reply; 5+ messages in thread From: Joe Perches @ 2012-04-04 19:02 UTC (permalink / raw) To: Thomas Pedersen; +Cc: linux-wireless, ath6kl-devel On Wed, 2012-04-04 at 11:56 -0700, 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. trivia: > diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c [] > @@ -1015,6 +1015,19 @@ out: > vif->scan_req = NULL; > } > > +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int channel, > + 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", vif->nw_type, channel, mode); Please coalesce formats. If you had, you'd've seen a problem with this format. Add a newline "\n" terminator to it too. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches 2012-04-04 19:02 ` Joe Perches @ 2012-04-04 20:00 ` Pedersen, Thomas 2012-04-04 20:09 ` Joe Perches 0 siblings, 1 reply; 5+ messages in thread From: Pedersen, Thomas @ 2012-04-04 20:00 UTC (permalink / raw) To: Joe Perches; +Cc: linux-wireless, ath6kl-devel Hi Joe, On Wed, Apr 04, 2012 at 12:02:58PM -0700, Joe Perches wrote: > On Wed, 2012-04-04 at 11:56 -0700, 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. > > trivia: > > > diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c > [] > > @@ -1015,6 +1015,19 @@ out: > > vif->scan_req = NULL; > > } > > > > +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int channel, > > + 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", vif->nw_type, channel, mode); > > Please coalesce formats. > If you had, you'd've seen a problem with this format. > Add a newline "\n" terminator to it too. I'm not sure what you mean by "coalesce formats". The freq / channel semantic mismatch? I'll change that and add a newline as well. Thanks for looking. Thomas ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches 2012-04-04 20:00 ` Pedersen, Thomas @ 2012-04-04 20:09 ` Joe Perches 0 siblings, 0 replies; 5+ messages in thread From: Joe Perches @ 2012-04-04 20:09 UTC (permalink / raw) To: Pedersen, Thomas; +Cc: linux-wireless, ath6kl-devel On Wed, 2012-04-04 at 13:00 -0700, Pedersen, Thomas wrote: > > > + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "channel switch notify nw_type %d" > > > + "freq %d mode %d", vif->nw_type, channel, mode); > > > > Please coalesce formats. > > If you had, you'd've seen a problem with this format. > > Add a newline "\n" terminator to it too. > > I'm not sure what you mean by "coalesce formats". The freq / channel > semantic mismatch? I'll change that and add a newline as well. There's currently no space between a "%d" and "freq". There should be one. It'd be better and less error prone like this: ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "channel switch notify nw_type %d freq %d mode %d\n", vif->nw_type, channel, mode); cheers, Joe ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-04-04 20:09 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-04-04 18:56 [PATCH 1/2] cfg80211: add channel switch notify event Thomas Pedersen 2012-04-04 18:56 ` [PATCH 2/2] ath6kl: handle concurrent AP-STA channel switches Thomas Pedersen 2012-04-04 19:02 ` Joe Perches 2012-04-04 20:00 ` Pedersen, Thomas 2012-04-04 20:09 ` Joe Perches
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).