2011-08-29 12:24:11

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 00/20] ath6kl: AP mode and P2P

This set of patches adds preliminary support for AP mode and P2P
operations into ath6kl. Since these require a new firmware build
and more testing, the patches to actually enable either AP or P2P
modes are not included in the series. These will be submitted
after some more testing.

Edward Lu (4):
ath6kl: Support channel set request for startscan command
ath6kl: Fix a typo in ath6k context
ath6kl: Fix default key installation in AP mode
ath6kl: Do not clear CONNECT bit setting in AP mode for STA
disconnect

Jouni Malinen (16):
ath6kl: Add functionality for starting AP mode
ath6kl: Fix AP mode (Re)AssocReq IE processing
ath6kl: Delay initial group key setup in AP mode
ath6kl: Use change_station() to authorize/unauthorize STAs
ath6kl: Add new WMI commands and events for P2P
ath6kl: Implement remain_on_channel and cancel_remain_on_channel
ath6kl: Implement mgmt_tx
ath6kl: Request P2P capabilities during target init
ath6kl: Add cfg80211 calls for remain-on-channel events
ath6kl: Use set_appie command to add Probe Request IEs
ath6kl: Report received Probe Request frames to cfg80211
ath6kl: Notify cfg80211 of TX status of mgmt_tx frames
ath6kl: Report received Action frames to cfg80211
ath6kl: Advertise supported mgmt_stypes
ath6kl: Add support for new P2P iftypes in mode changes
ath6kl: Include P2P IE(s) in GO Probe Response depending on request

drivers/net/wireless/ath/ath6kl/cfg80211.c | 482 +++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/core.h | 31 +--
drivers/net/wireless/ath/ath6kl/init.c | 18 +-
drivers/net/wireless/ath/ath6kl/main.c | 96 ++++--
drivers/net/wireless/ath/ath6kl/wmi.c | 435 +++++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/wmi.h | 227 +++++++++++++-
6 files changed, 1222 insertions(+), 67 deletions(-)

--
1.7.4.1



2011-08-30 09:06:21

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 04/20] ath6kl: Use change_station() to authorize/unauthorize STAs

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> --- a/drivers/net/wireless/ath/ath6kl/wmi.h
> +++ b/drivers/net/wireless/ath/ath6kl/wmi.h
> @@ -1804,6 +1804,21 @@ struct wmi_tx_complete_event {
>
> /* Used with WMI_AP_SET_NUM_STA_CMDID */
>
> +/*
> + * Used with WMI_AP_SET_MLME_CMDID
> + */
> +struct wmi_ap_set_mlme_cmd {
> + u8 mac[ETH_ALEN];
> + u16 reason; /* 802.11 reason code */
> + u8 cmd; /* operation to perform */
> +/* MLME Commands */
> +#define WMI_AP_MLME_ASSOC 1 /* associate station */
> +#define WMI_AP_DISASSOC 2 /* disassociate station */
> +#define WMI_AP_DEAUTH 3 /* deauthenticate station */
> +#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
> +#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
> +} __packed;

Needs an endian annotation for u16. Also defines inside a struct are
IMHO a bit awkward.

Kalle

Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On Tue, Aug 30, 2011 at 03:21:24PM +0530, Vasanthakumar Thiagarajan wrote:
> On Tue, Aug 30, 2011 at 12:33:46PM +0300, Kalle Valo wrote:
> > On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > > From: Edward Lu <[email protected]>
> > > - if (num_chan)
> > > - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
> > > + if (num_chan) {
> > > + for (i = 0; i < num_chan; i++)
> > > + sc->ch_list[i] = cpu_to_le16(ch_list[i]);
> > > + }
> >
> > if (num_chan) is not needed, the for loop is enough.
>
> It is not that for loop would run once when num_chan is 0,
> may be it needs to go from 0 to num_chan -1?.

Oops, obviously i misread it.

Vasanth

2011-08-29 12:24:17

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

Use cfg80211 add/del_beacon callbacks for starting/stopping AP mode and
set_beacon to update AP configuration (mainly, to update Beacon and
Probe Response IEs).

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 176 ++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/core.h | 2 +
drivers/net/wireless/ath/ath6kl/wmi.c | 46 +++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 20 +++
4 files changed, 244 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 9128aa3..e486c1c 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1435,6 +1435,178 @@ static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
}
#endif

+static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (!test_bit(WLAN_ENABLED, &ar->flag)) {
+ ath6kl_err("%s: wlan disabled\n", __func__);
+ return -EIO;
+ }
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
+ __func__, chan->center_freq, chan->hw_value);
+ ar->next_chan = chan->center_freq;
+
+ return 0;
+}
+
+static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info, bool add)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ struct ieee80211_mgmt *mgmt;
+ u8 *ies;
+ int ies_len;
+ struct wmi_connect_cmd p;
+ int i;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
+
+ if (!test_bit(WMI_READY, &ar->flag))
+ return -EIO;
+
+ if (!test_bit(WLAN_ENABLED, &ar->flag))
+ return -EIO;
+
+ if (ar->next_mode != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ if (info->beacon_ies &&
+ ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
+ info->beacon_ies, info->beacon_ies_len))
+ return -EIO;
+ if (info->proberesp_ies &&
+ ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
+ info->proberesp_ies,
+ info->proberesp_ies_len))
+ return -EIO;
+ if (info->assocresp_ies &&
+ ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
+ info->assocresp_ies,
+ info->assocresp_ies_len))
+ return -EIO;
+
+ if (!add)
+ return 0;
+
+ /* TODO:
+ * info->interval
+ * info->dtim_period
+ */
+
+ if (info->head == NULL)
+ return -EINVAL;
+ mgmt = (struct ieee80211_mgmt *) info->head;
+ ies = mgmt->u.beacon.variable;
+ if (ies > info->head + info->head_len)
+ return -EINVAL;
+ ies_len = info->head + info->head_len - ies;
+
+ if (info->ssid == NULL)
+ return -EINVAL;
+ memcpy(ar->ssid, info->ssid, info->ssid_len);
+ ar->ssid_len = info->ssid_len;
+ if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
+ return -EOPNOTSUPP; /* TODO */
+
+ ar->dot11_auth_mode = OPEN_AUTH;
+
+ memset(&p, 0, sizeof(p));
+
+ for (i = 0; i < info->crypto.n_akm_suites; i++) {
+ switch (info->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ p.auth_mode |= WPA_AUTH;
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_AUTH;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ p.auth_mode |= WPA_PSK_AUTH;
+ if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ p.auth_mode |= WPA2_PSK_AUTH;
+ break;
+ }
+ }
+ if (p.auth_mode == 0)
+ p.auth_mode = NONE_AUTH;
+ ar->auth_mode = p.auth_mode;
+
+ for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) {
+ switch (info->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ p.prwise_crypto_type |= WEP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ p.prwise_crypto_type |= TKIP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ p.prwise_crypto_type |= AES_CRYPT;
+ break;
+ }
+ }
+ if (p.prwise_crypto_type == 0)
+ p.prwise_crypto_type = NONE_CRYPT;
+
+ switch (info->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ p.grp_crypto_type = WEP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ p.grp_crypto_type = TKIP_CRYPT;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ p.grp_crypto_type = AES_CRYPT;
+ break;
+ default:
+ p.grp_crypto_type = NONE_CRYPT;
+ break;
+ }
+
+ p.nw_type = AP_NETWORK;
+ ar->nw_type = ar->next_mode;
+
+ p.ssid_len = ar->ssid_len;
+ memcpy(p.ssid, ar->ssid, ar->ssid_len);
+ p.dot11_auth_mode = ar->dot11_auth_mode;
+ p.ch = ar->next_chan;
+
+ return ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
+}
+
+static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ return ath6kl_ap_beacon(wiphy, dev, info, true);
+}
+
+static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ return ath6kl_ap_beacon(wiphy, dev, info, false);
+}
+
+static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (ar->nw_type != AP_NETWORK)
+ return -EOPNOTSUPP;
+ if (!test_bit(CONNECTED, &ar->flag))
+ return -ENOTCONN;
+
+ ath6kl_wmi_disconnect_cmd(ar->wmi);
+ clear_bit(CONNECTED, &ar->flag);
+
+ return 0;
+}
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1457,6 +1629,10 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
#ifdef CONFIG_PM
.suspend = ar6k_cfg80211_suspend,
#endif
+ .set_channel = ath6kl_set_channel,
+ .add_beacon = ath6kl_add_beacon,
+ .set_beacon = ath6kl_set_beacon,
+ .del_beacon = ath6kl_del_beacon,
};

struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index c5537b3..00d0add 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -468,6 +468,8 @@ struct ath6kl {

struct ath6kl_node_table scan_table;
struct dentry *debugfs_phy;
+
+ u16 next_chan;
};

static inline void *ath6kl_priv(struct net_device *dev)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index d116d0e..a7a1dcc 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1399,6 +1399,8 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
enum htc_endpoint_id ep_id = wmi->ep_id;
int ret;

+ ath6kl_dbg(ATH6KL_DBG_WMI, "%s: cmd_id=%d\n", __func__, cmd_id);
+
if (WARN_ON(skb == NULL))
return -EINVAL;

@@ -2392,6 +2394,29 @@ static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
}

/* AP mode functions */
+
+int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p)
+{
+ struct sk_buff *skb;
+ struct wmi_connect_cmd *cm;
+ int res;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
+ if (!skb)
+ return -ENOMEM;
+
+ cm = (struct wmi_connect_cmd *) skb->data;
+ memcpy(cm, p, sizeof(*cm));
+
+ res = ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_CONFIG_COMMIT_CMDID,
+ NO_SYNC_WMIFLAG);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u "
+ "ctrl_flags=0x%x-> res=%d\n",
+ __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
+ le32_to_cpu(p->ctrl_flags), res);
+ return res;
+}
+
static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct wmi_pspoll_event *ev;
@@ -2456,6 +2481,27 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
return ret;
}

+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len)
+{
+ struct sk_buff *skb;
+ struct wmi_set_appie_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u "
+ "ie_len=%u\n", mgmt_frm_type, ie_len);
+ p = (struct wmi_set_appie_cmd *) skb->data;
+ p->mgmt_frm_type = mgmt_frm_type;
+ p->ie_len = ie_len;
+ memcpy(p->ie_info, ie, ie_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_APPIE_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+
static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
{
struct wmix_cmd_hdr *cmd;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 8fa5d6e..1d96afd 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -503,6 +503,15 @@ enum wmi_cmd_id {
WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
};

+enum wfi_mgmt_frame_type {
+ WMI_FRAME_BEACON = 0,
+ WMI_FRAME_PROBE_REQ,
+ WMI_FRAME_PROBE_RESP,
+ WMI_FRAME_ASSOC_REQ,
+ WMI_FRAME_ASSOC_RESP,
+ WMI_NUM_MGMT_FRAME
+};
+
/* WMI_CONNECT_CMDID */
enum network_type {
INFRA_NETWORK = 0x01,
@@ -1642,6 +1651,12 @@ struct wmi_get_keepalive_cmd {
u8 keep_alive_intvl;
} __packed;

+struct wmi_set_appie_cmd {
+ u8 mgmt_frm_type; /* enum wfi_mgmt_frame_type */
+ u8 ie_len;
+ u8 ie_info[0];
+} __packed;
+
/* Notify the WSC registration status to the target */
#define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0
@@ -2006,11 +2021,16 @@ struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid,
void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss);

/* AP mode */
+int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p);
+
int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag);

int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
bool rx_dot11_hdr, bool defrag_on_host);

+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len);
+
void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi);

--
1.7.4.1


2011-08-30 09:10:27

by Raja Mani

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On Tuesday 30 August 2011 02:10 PM, Jouni Malinen wrote:
> On Tue, Aug 30, 2011 at 11:17:43AM +0530, Raja Mani wrote:
>> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
>>> +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
>>> + struct beacon_parameters *info, bool add)
>>> +{
>
>>> + if (!test_bit(WMI_READY,&ar->flag))
>>> + return -EIO;
>>> +
>>> + if (!test_bit(WLAN_ENABLED,&ar->flag))
>>> + return -EIO;
>>
>> How about calling ath6kl_cfg80211_ready() function to check
>> WMI_READY and WLAN_ENABLED status ?
>
> Sure, I can do that, but unless something else comes up, I would rather
> do it after the patch series goes in. It looks like I missed addition of
> that helper function since I started working on this before the cleanup
> was complete.

Okay.

>
> By the way.. How did that message lost the space after the commas on
> those test_bit lines? They are included in the patch I sent.
>

When i opened your patch, I saw your complete patch code. Could be
deleted by mistake when i sent reply..

2011-08-29 12:27:46

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 04/20] ath6kl: Use change_station() to authorize/unauthorize STAs

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 20 ++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.c | 18 ++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 17 +++++++++++++++++
3 files changed, 55 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 0bfd5b0..898f394 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1637,6 +1637,25 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev)
return 0;
}

+static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_parameters *params)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (ar->nw_type != AP_NETWORK)
+ return -EOPNOTSUPP;
+
+ /* Use this only for authorizing/unauthorizing a station */
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return -EOPNOTSUPP;
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE,
+ mac, 0);
+ return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac,
+ 0);
+}
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1663,6 +1682,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.add_beacon = ath6kl_add_beacon,
.set_beacon = ath6kl_set_beacon,
.del_beacon = ath6kl_del_beacon,
+ .change_station = ath6kl_change_station,
};

struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index eb8f6b1..5c6688b 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2421,6 +2421,24 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p)
return res;
}

+int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason)
+{
+ struct sk_buff *skb;
+ struct wmi_ap_set_mlme_cmd *cm;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
+ if (!skb)
+ return -ENOMEM;
+
+ cm = (struct wmi_ap_set_mlme_cmd *) skb->data;
+ memcpy(cm->mac, mac, ETH_ALEN);
+ cm->reason = cpu_to_le16(reason);
+ cm->cmd = cmd;
+
+ return ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_SET_MLME_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct wmi_pspoll_event *ev;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 1d96afd..2d22c7f9 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1804,6 +1804,21 @@ struct wmi_tx_complete_event {

/* Used with WMI_AP_SET_NUM_STA_CMDID */

+/*
+ * Used with WMI_AP_SET_MLME_CMDID
+ */
+struct wmi_ap_set_mlme_cmd {
+ u8 mac[ETH_ALEN];
+ u16 reason; /* 802.11 reason code */
+ u8 cmd; /* operation to perform */
+/* MLME Commands */
+#define WMI_AP_MLME_ASSOC 1 /* associate station */
+#define WMI_AP_DISASSOC 2 /* disassociate station */
+#define WMI_AP_DEAUTH 3 /* deauthenticate station */
+#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
+#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
+} __packed;
+
struct wmi_ap_set_pvb_cmd {
__le32 flag;
__le16 aid;
@@ -2023,6 +2038,8 @@ void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss);
/* AP mode */
int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p);

+int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason);
+
int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag);

int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
--
1.7.4.1


2011-08-29 12:24:40

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 02/20] ath6kl: Fix AP mode (Re)AssocReq IE processing

Need to use correct length field for association request frame and
parse the IEs to find WPA/WPS/RSN IE. In addition, copying of the
IE better make sure it fits in into the buffer to avoid buffer
overflows.

In addition, add the (Re)AssocReq IEs to the cfg80211 new station
event for user space.

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/main.c | 57 +++++++++++++++++++++++++++----
1 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index b64b2a3..89e29ea 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -61,7 +61,8 @@ static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie,

sta = &ar->sta_list[free_slot];
memcpy(sta->mac, mac, ETH_ALEN);
- memcpy(sta->wpa_ie, wpaie, ielen);
+ if (ielen <= ATH6KL_MAX_IE)
+ memcpy(sta->wpa_ie, wpaie, ielen);
sta->aid = aid;
sta->keymgmt = keymgmt;
sta->ucipher = ucipher;
@@ -429,9 +430,11 @@ static void ath6kl_install_static_wep_keys(struct ath6kl *ar)

static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid,
u16 listen_int, u16 beacon_int,
- u8 assoc_resp_len, u8 *assoc_info)
+ u8 assoc_req_len, u8 *assoc_info)
{
struct net_device *dev = ar->net_dev;
+ u8 *ies = NULL, *wpa_ie = NULL, *pos;
+ size_t ies_len = 0;
struct station_info sinfo;
struct ath6kl_req_key *ik;
enum crypto_type keyType = NONE_CRYPT;
@@ -473,7 +476,43 @@ skip_key:
ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n",
bssid, channel);

- ath6kl_add_new_sta(ar, bssid, channel, assoc_info, assoc_resp_len,
+ if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *) assoc_info;
+ if (ieee80211_is_assoc_req(mgmt->frame_control) &&
+ assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) +
+ sizeof(mgmt->u.assoc_req)) {
+ ies = mgmt->u.assoc_req.variable;
+ ies_len = assoc_info + assoc_req_len - ies;
+ } else if (ieee80211_is_reassoc_req(mgmt->frame_control) &&
+ assoc_req_len >= sizeof(struct ieee80211_hdr_3addr)
+ + sizeof(mgmt->u.reassoc_req)) {
+ ies = mgmt->u.reassoc_req.variable;
+ ies_len = assoc_info + assoc_req_len - ies;
+ }
+ }
+
+ pos = ies;
+ while (pos && pos + 1 < ies + ies_len) {
+ if (pos + 2 + pos[1] > ies + ies_len)
+ break;
+ if (pos[0] == WLAN_EID_RSN)
+ wpa_ie = pos; /* RSN IE */
+ else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] >= 4 &&
+ pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) {
+ if (pos[5] == 0x01)
+ wpa_ie = pos; /* WPA IE */
+ else if (pos[5] == 0x04) {
+ wpa_ie = pos; /* WPS IE */
+ break; /* overrides WPA/RSN IE */
+ }
+ }
+ pos += 2 + pos[1];
+ }
+
+ ath6kl_add_new_sta(ar, bssid, channel, wpa_ie,
+ wpa_ie ? 2 + wpa_ie[1] : 0,
listen_int & 0xFF, beacon_int,
(listen_int >> 8) & 0xFF);

@@ -481,9 +520,11 @@ skip_key:
memset(&sinfo, 0, sizeof(sinfo));

/* TODO: sinfo.generation */
- /* TODO: need to deliver (Re)AssocReq IEs somehow.. change in
- * cfg80211 needed, e.g., by adding those into sinfo
- */
+
+ sinfo.assoc_req_ies = ies;
+ sinfo.assoc_req_ies_len = ies_len;
+ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+
cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL);

netif_wake_queue(ar->net_dev);
@@ -895,8 +936,8 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid,

if (ar->nw_type == AP_NETWORK) {
ath6kl_connect_ap_mode(ar, channel, bssid, listen_int,
- beacon_int, assoc_resp_len,
- assoc_info);
+ beacon_int, assoc_req_len,
+ assoc_info + beacon_ie_len);
return;
}

--
1.7.4.1


2011-08-30 14:14:30

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 07/20] ath6kl: Implement mgmt_tx

On Tue, Aug 30, 2011 at 12:23:04PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > +static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,

> > + id = ar->send_action_id++;
> > + if (id == 0)
> > + id = ar->send_action_id++;

> > + *cookie = id;
> > + return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
> > + buf, len);

> I don't understand the "if (id == 0)" check. It would be nice to get a
> comment giving some background info about the situation.

0 is a reserved value in the target implementation and shall not be used
in the WMI command. I'll add a comment on this.

--
Jouni Malinen PGP id EFC895FA

2011-08-30 15:54:17

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 00/20] ath6kl: AP mode and P2P

On Tue, Aug 30, 2011 at 12:51:47PM +0300, Kalle Valo wrote:
> I reviewed the patches. Looks good, I only found some minor issues.
> There are also some sparse warnings:

Thanks! Fixed.

--
Jouni Malinen PGP id EFC895FA

2011-08-30 10:30:27

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On 08/30/2011 01:04 PM, Raja Mani wrote:
> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
>
>> if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
>> - false, 0, 0, 0, NULL) != 0) {
>> + false, 0, 0, n_channels, channels) != 0) {
>> ath6kl_err("wmi_startscan_cmd failed\n");
>
> kfree(channels) for failure cases ??

It's freed below as there's no return call for the error case:

>> ret = -EIO;
>> }
>>
>> ar->scan_req = request;
>>
>> + kfree(channels); <-----
>> +
>> return ret;
>> }

I also got fooled by this :)

Kalle

2011-08-30 14:10:30

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 04/20] ath6kl: Use change_station() to authorize/unauthorize STAs

On Tue, Aug 30, 2011 at 12:06:15PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > --- a/drivers/net/wireless/ath/ath6kl/wmi.h
> > +++ b/drivers/net/wireless/ath/ath6kl/wmi.h
> > @@ -1804,6 +1804,21 @@ struct wmi_tx_complete_event {
> > +/*
> > + * Used with WMI_AP_SET_MLME_CMDID
> > + */
> > +struct wmi_ap_set_mlme_cmd {
> > + u8 mac[ETH_ALEN];
> > + u16 reason; /* 802.11 reason code */
> > + u8 cmd; /* operation to perform */
> > +/* MLME Commands */
> > +#define WMI_AP_MLME_ASSOC 1 /* associate station */
> > +#define WMI_AP_DISASSOC 2 /* disassociate station */
> > +#define WMI_AP_DEAUTH 3 /* deauthenticate station */
> > +#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */
> > +#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */
> > +} __packed;
>
> Needs an endian annotation for u16. Also defines inside a struct are
> IMHO a bit awkward.

Thanks, fixed.

--
Jouni Malinen PGP id EFC895FA

2011-08-30 14:30:44

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 08/20] ath6kl: Request P2P capabilities during target init

On Tue, Aug 30, 2011 at 03:21:53PM +0530, Raja Mani wrote:
> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
> >+ ret = ath6kl_wmi_info_req_cmd(ar->wmi, P2P_FLAG_CAPABILITIES_REQ |
> >+ P2P_FLAG_MACADDR_REQ |
> >+ P2P_FLAG_HMODEL_REQ);
> >+ if (ret) {
> >+ printk(KERN_DEBUG "ath6l: Failed to request P2P capabilities "
> >+ "(%d) - assuming P2P not supported\n", ret);
>
> Is it possible to use ath6kl_dbg() instead of printk here ?

Sure.

> Should it be ath6kl_err() ?
>
> Another question is , Don't you have to assign error code (may be
> -EIO) to 'status' variable in case of error ? not sure whether error
> code assignment needed here or not..

No, this is not a fatal error. The driver will just run without P2P
support if the firmware does not support the new P2P commands. I'm not
yet sure what will be the exact mechanism for doing this, i.e., this may
be done either based on the firmware version or the result of this
command. Though, it should be noted that the target returns the
capabilities with a separate event message, so we would need to block
somehow during hardware init to have the information available for
cfg80211 registration. Anyway, the patch to actually start advertising
support for P2P is not included in the patch series.

--
Jouni Malinen PGP id EFC895FA

2011-08-29 12:30:31

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 18/20] ath6kl: Fix default key installation in AP mode

From: Edward Lu <[email protected]>

Signed-off-by: Edward Lu <[email protected]>
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index cfb54db..ee0f8bd 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1025,6 +1025,7 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
struct ath6kl_key *key = NULL;
int status = 0;
u8 key_usage;
+ enum crypto_type key_type = NONE_CRYPT;

ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index);

@@ -1049,12 +1050,16 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
key_usage = GROUP_USAGE;
if (ar->prwise_crypto == WEP_CRYPT)
key_usage |= TX_USAGE;
+ if (unicast)
+ key_type = ar->prwise_crypto;
+ if (multicast)
+ key_type = ar->grp_crypto;

if (ar->nw_type == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
return 0; /* Delay until AP mode has been started */

status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
- ar->prwise_crypto, key_usage,
+ key_type, key_usage,
key->key_len, key->seq, key->key,
KEY_OP_INIT_VAL, NULL,
SYNC_BOTH_WMIFLAG);
@@ -1615,8 +1620,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
break;
}
}
- if (p.prwise_crypto_type == 0)
+ if (p.prwise_crypto_type == 0) {
p.prwise_crypto_type = NONE_CRYPT;
+ ath6kl_set_cipher(ar, 0, true);
+ } else if (info->crypto.n_ciphers_pairwise == 1)
+ ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true);

switch (info->crypto.cipher_group) {
case WLAN_CIPHER_SUITE_WEP40:
@@ -1633,6 +1641,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
p.grp_crypto_type = NONE_CRYPT;
break;
}
+ ath6kl_set_cipher(ar, info->crypto.cipher_group, false);

p.nw_type = AP_NETWORK;
ar->nw_type = ar->next_mode;
--
1.7.4.1


2011-08-29 12:30:24

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 17/20] ath6kl: Fix a typo in ath6k context

From: Edward Lu <[email protected]>

Signed-off-by: Edward Lu <[email protected]>
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 13 +++++++------
drivers/net/wireless/ath/ath6kl/core.h | 2 +-
drivers/net/wireless/ath/ath6kl/init.c | 2 +-
3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 19b6da8..cfb54db 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -168,7 +168,8 @@ static int ath6kl_set_auth_type(struct ath6kl *ar,
static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast)
{
u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto;
- u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : &ar->grp_crpto_len;
+ u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len :
+ &ar->grp_crypto_len;

ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n",
__func__, cipher, ucast);
@@ -371,14 +372,14 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
__func__,
ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
ar->prwise_crypto_len, ar->grp_crypto,
- ar->grp_crpto_len, ar->ch_hint);
+ ar->grp_crypto_len, ar->ch_hint);

ar->reconnect_flag = 0;
status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
ar->dot11_auth_mode, ar->auth_mode,
ar->prwise_crypto,
ar->prwise_crypto_len,
- ar->grp_crypto, ar->grp_crpto_len,
+ ar->grp_crypto, ar->grp_crypto_len,
ar->ssid_len, ar->ssid,
ar->req_bssid, ar->ch_hint,
ar->connect_ctrl_flags);
@@ -688,7 +689,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
ar->prwise_crypto,
ar->prwise_crypto_len,
ar->grp_crypto,
- ar->grp_crpto_len,
+ ar->grp_crypto_len,
ar->ssid_len,
ar->ssid,
ar->req_bssid,
@@ -1277,13 +1278,13 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
__func__,
ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto,
ar->prwise_crypto_len, ar->grp_crypto,
- ar->grp_crpto_len, ar->ch_hint);
+ ar->grp_crypto_len, ar->ch_hint);

status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type,
ar->dot11_auth_mode, ar->auth_mode,
ar->prwise_crypto,
ar->prwise_crypto_len,
- ar->grp_crypto, ar->grp_crpto_len,
+ ar->grp_crypto, ar->grp_crypto_len,
ar->ssid_len, ar->ssid,
ar->req_bssid, ar->ch_hint,
ar->connect_ctrl_flags);
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 99cabd2..60e2291 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -380,7 +380,7 @@ struct ath6kl {
u8 prwise_crypto;
u8 prwise_crypto_len;
u8 grp_crypto;
- u8 grp_crpto_len;
+ u8 grp_crypto_len;
u8 def_txkey_index;
struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
u8 bssid[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 376e576..6f44017 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -85,7 +85,7 @@ void ath6kl_init_profile_info(struct ath6kl *ar)
ar->prwise_crypto = NONE_CRYPT;
ar->prwise_crypto_len = 0;
ar->grp_crypto = NONE_CRYPT;
- ar->grp_crpto_len = 0;
+ ar->grp_crypto_len = 0;
memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list));
memset(ar->req_bssid, 0, sizeof(ar->req_bssid));
memset(ar->bssid, 0, sizeof(ar->bssid));
--
1.7.4.1


2011-08-30 09:51:52

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/20] ath6kl: AP mode and P2P

Hi,

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> This set of patches adds preliminary support for AP mode and P2P
> operations into ath6kl. Since these require a new firmware build
> and more testing, the patches to actually enable either AP or P2P
> modes are not included in the series. These will be submitted
> after some more testing.

I reviewed the patches. Looks good, I only found some minor issues.
There are also some sparse warnings:

drivers/net/wireless/ath/ath6kl/cfg80211.c:1695:14: warning: incorrect
type in assignment (different base types)
drivers/net/wireless/ath/ath6kl/cfg80211.c:1695:14: expected
restricted __le16 [addressable] [assigned] [usertype] ch
drivers/net/wireless/ath/ath6kl/cfg80211.c:1695:14: got unsigned
short [unsigned] [usertype] next_chan
drivers/net/wireless/ath/ath6kl/wmi.c:2632:20: warning: incorrect type
in assignment (different base types)
drivers/net/wireless/ath/ath6kl/wmi.c:2632:20: expected unsigned
short [unsigned] [usertype] reason
drivers/net/wireless/ath/ath6kl/wmi.c:2632:20: got restricted __le16
[usertype] <noident>

If you want, I can fix the issues I found before I merge the patches.

Kalle

2011-08-30 10:04:23

by Raja Mani

[permalink] [raw]
Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
> From: Edward Lu<[email protected]>
>
> Signed-off-by: Edward Lu<[email protected]>
> Signed-off-by: Jouni Malinen<[email protected]>
> ---
> drivers/net/wireless/ath/ath6kl/cfg80211.c | 23 ++++++++++++++++++++++-
> drivers/net/wireless/ath/ath6kl/wmi.c | 8 +++++---
> 2 files changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> index d287f0a..e78d332 100644
> --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> @@ -748,6 +748,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
> struct cfg80211_scan_request *request)
> {
> struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
> + s8 n_channels = 0;
> + u16 *channels = NULL;
> int ret = 0;
>
> if (!ath6kl_cfg80211_ready(ar))
> @@ -785,14 +787,33 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
> }
> }
>
> + if (request->n_channels> 0) {
> + u8 i;
> +
> + n_channels = (request->n_channels> 127) ?
> + 127 : request->n_channels;
> +
> + channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
> + if (channels == NULL) {
> + ath6kl_err("failed to set scan channels, "
> + "scan all channels");
> + n_channels = 0;
> + }
> +
> + for (i = 0; i< n_channels; i++)
> + channels[i] = request->channels[i]->center_freq;
> + }
> +
> if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
> - false, 0, 0, 0, NULL) != 0) {
> + false, 0, 0, n_channels, channels) != 0) {
> ath6kl_err("wmi_startscan_cmd failed\n");

kfree(channels) for failure cases ??

> ret = -EIO;
> }
>
> ar->scan_req = request;
>
> + kfree(channels);
> +
> return ret;
> }
>
> diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
> index 2d80bdb..87e4d65 100644
> --- a/drivers/net/wireless/ath/ath6kl/wmi.c
> +++ b/drivers/net/wireless/ath/ath6kl/wmi.c
> @@ -1709,7 +1709,7 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
> struct sk_buff *skb;
> struct wmi_start_scan_cmd *sc;
> s8 size;
> - int ret;
> + int i, ret;
>
> size = sizeof(struct wmi_start_scan_cmd);
>
> @@ -1734,8 +1734,10 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
> sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
> sc->num_ch = num_chan;
>
> - if (num_chan)
> - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
> + if (num_chan) {
> + for (i = 0; i< num_chan; i++)
> + sc->ch_list[i] = cpu_to_le16(ch_list[i]);
> + }
>
> ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID,
> NO_SYNC_WMIFLAG);

2011-08-29 12:27:38

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 03/20] ath6kl: Delay initial group key setup in AP mode

The target is not ready to accept addkey commands until the connect
event has been delivered, so delay these operations for the initial GTK.
In addition, properly set interface connected and mark netdev ready when
the AP mode setup has been completed.

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 32 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/core.h | 25 ++++--------------
drivers/net/wireless/ath/ath6kl/main.c | 36 +++++++++++++++------------
drivers/net/wireless/ath/ath6kl/wmi.c | 4 +++
4 files changed, 61 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index e486c1c..0bfd5b0 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -888,6 +888,26 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
key_usage, key->seq_len);

ar->def_txkey_index = key_index;
+
+ if (ar->nw_type == AP_NETWORK && !pairwise &&
+ (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) {
+ ar->ap_mode_bkey.valid = true;
+ ar->ap_mode_bkey.key_index = key_index;
+ ar->ap_mode_bkey.key_type = key_type;
+ ar->ap_mode_bkey.key_len = key->key_len;
+ memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
+ if (!test_bit(CONNECTED, &ar->flag)) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
+ "key configuration until AP mode has been "
+ "started\n");
+ /*
+ * The key will be set in ath6kl_connect_ap_mode() once
+ * the connected event is received from the target.
+ */
+ return 0;
+ }
+ }
+
status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
key_type, key_usage, key->key_len,
key->seq, key->key, KEY_OP_INIT_VAL,
@@ -997,6 +1017,9 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy,
if (ar->prwise_crypto == WEP_CRYPT)
key_usage |= TX_USAGE;

+ if (ar->nw_type == AP_NETWORK && !test_bit(CONNECTED, &ar->flag))
+ return 0; /* Delay until AP mode has been started */
+
status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index,
ar->prwise_crypto, key_usage,
key->key_len, key->seq, key->key,
@@ -1461,6 +1484,7 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
u8 *ies;
int ies_len;
struct wmi_connect_cmd p;
+ int res;
int i;

ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
@@ -1492,6 +1516,8 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
if (!add)
return 0;

+ ar->ap_mode_bkey.valid = false;
+
/* TODO:
* info->interval
* info->dtim_period
@@ -1577,7 +1603,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
p.dot11_auth_mode = ar->dot11_auth_mode;
p.ch = ar->next_chan;

- return ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
+ res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p);
+ if (res < 0)
+ return res;
+
+ return 0;
}

static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 00d0add..f0b1dff 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -335,26 +335,13 @@ struct ath6kl_mbox_info {
#define ATH6KL_KEY_RECV 0x02
#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */

-/*
- * WPA/RSN get/set key request. Specify the key/cipher
- * type and whether the key is to be used for sending and/or
- * receiving. The key index should be set only when working
- * with global keys (use IEEE80211_KEYIX_NONE for ``no index'').
- * Otherwise a unicast/pairwise key is specified by the bssid
- * (on a station) or mac address (on an ap). They key length
- * must include any MIC key data; otherwise it should be no
- * more than ATH6KL_KEYBUF_SIZE.
- */
+/* Initial group key for AP mode */
struct ath6kl_req_key {
- u8 ik_type; /* key/cipher type */
- u8 ik_pad;
- u16 ik_keyix; /* key index */
- u8 ik_keylen; /* key length in bytes */
- u8 ik_flags;
- u8 ik_macaddr[ETH_ALEN];
- u64 ik_keyrsc; /* key receive sequence counter */
- u64 ik_keytsc; /* key transmit sequence counter */
- u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE];
+ bool valid;
+ u8 key_index;
+ int key_type;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 key_len;
};

/* Flag info */
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 89e29ea..a19caec 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -437,11 +437,15 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid,
size_t ies_len = 0;
struct station_info sinfo;
struct ath6kl_req_key *ik;
- enum crypto_type keyType = NONE_CRYPT;
+ int res;
+ u8 key_rsc[ATH6KL_KEY_SEQ_LEN];

if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) {
ik = &ar->ap_mode_bkey;

+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n",
+ channel);
+
switch (ar->auth_mode) {
case NONE_AUTH:
if (ar->prwise_crypto == WEP_CRYPT)
@@ -450,26 +454,26 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid,
case WPA_PSK_AUTH:
case WPA2_PSK_AUTH:
case (WPA_PSK_AUTH|WPA2_PSK_AUTH):
- switch (ik->ik_type) {
- case ATH6KL_CIPHER_TKIP:
- keyType = TKIP_CRYPT;
- break;
- case ATH6KL_CIPHER_AES_CCM:
- keyType = AES_CRYPT;
+ if (!ik->valid)
break;
- default:
- goto skip_key;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
+ "the initial group key for AP mode\n");
+ memset(key_rsc, 0, sizeof(key_rsc));
+ res = ath6kl_wmi_addkey_cmd(
+ ar->wmi, ik->key_index, ik->key_type,
+ GROUP_USAGE, ik->key_len, key_rsc, ik->key,
+ KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
+ if (res) {
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
+ "addkey failed: %d\n", res);
}
- ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType,
- GROUP_USAGE, ik->ik_keylen,
- (u8 *)&ik->ik_keyrsc,
- ik->ik_keydata,
- KEY_OP_INIT_VAL, ik->ik_macaddr,
- SYNC_BOTH_WMIFLAG);
break;
}
-skip_key:
+
+ ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &ar->flag);
+ netif_carrier_on(ar->net_dev);
return;
}

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index a7a1dcc..eb8f6b1 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1764,6 +1764,10 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
struct wmi_add_cipher_key_cmd *cmd;
int ret;

+ ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d "
+ "key_usage=%d key_len=%d key_op_ctrl=%d\n",
+ key_index, key_type, key_usage, key_len, key_op_ctrl);
+
if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
(key_material == NULL))
return -EINVAL;
--
1.7.4.1


2011-08-29 12:29:14

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 11/20] ath6kl: Support channel set request for startscan command

From: Edward Lu <[email protected]>

Signed-off-by: Edward Lu <[email protected]>
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 23 ++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/wmi.c | 8 +++++---
2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d287f0a..e78d332 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -748,6 +748,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev);
+ s8 n_channels = 0;
+ u16 *channels = NULL;
int ret = 0;

if (!ath6kl_cfg80211_ready(ar))
@@ -785,14 +787,33 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
}
}

+ if (request->n_channels > 0) {
+ u8 i;
+
+ n_channels = (request->n_channels > 127) ?
+ 127 : request->n_channels;
+
+ channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
+ if (channels == NULL) {
+ ath6kl_err("failed to set scan channels, "
+ "scan all channels");
+ n_channels = 0;
+ }
+
+ for (i = 0; i < n_channels; i++)
+ channels[i] = request->channels[i]->center_freq;
+ }
+
if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
- false, 0, 0, 0, NULL) != 0) {
+ false, 0, 0, n_channels, channels) != 0) {
ath6kl_err("wmi_startscan_cmd failed\n");
ret = -EIO;
}

ar->scan_req = request;

+ kfree(channels);
+
return ret;
}

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 2d80bdb..87e4d65 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1709,7 +1709,7 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
struct sk_buff *skb;
struct wmi_start_scan_cmd *sc;
s8 size;
- int ret;
+ int i, ret;

size = sizeof(struct wmi_start_scan_cmd);

@@ -1734,8 +1734,10 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
sc->num_ch = num_chan;

- if (num_chan)
- memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
+ if (num_chan) {
+ for (i = 0; i < num_chan; i++)
+ sc->ch_list[i] = cpu_to_le16(ch_list[i]);
+ }

ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID,
NO_SYNC_WMIFLAG);
--
1.7.4.1


2011-08-30 09:33:53

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> From: Edward Lu <[email protected]>
>
> @@ -785,14 +787,33 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
> }
> }
>
> + if (request->n_channels > 0) {
> + u8 i;
> +
> + n_channels = (request->n_channels > 127) ?
> + 127 : request->n_channels;

min()

> +
> + channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
> + if (channels == NULL) {
> + ath6kl_err("failed to set scan channels, "
> + "scan all channels");

ath6kl_warn() would be more approriate here as the driver can still
continue.

> + n_channels = 0;
> + }
> +
> + for (i = 0; i < n_channels; i++)
> + channels[i] = request->channels[i]->center_freq;
> + }
> +
> if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
> - false, 0, 0, 0, NULL) != 0) {
> + false, 0, 0, n_channels, channels) != 0) {
> ath6kl_err("wmi_startscan_cmd failed\n");
> ret = -EIO;

Again I would prefer to return the error code from the wmi call.

> @@ -1734,8 +1734,10 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
> sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
> sc->num_ch = num_chan;
>
> - if (num_chan)
> - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
> + if (num_chan) {
> + for (i = 0; i < num_chan; i++)
> + sc->ch_list[i] = cpu_to_le16(ch_list[i]);
> + }

if (num_chan) is not needed, the for loop is enough.

Kalle

2011-08-29 12:28:32

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 08/20] ath6kl: Request P2P capabilities during target init

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/init.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index ad9716c..aa7440d 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -417,6 +417,7 @@ void ath6kl_target_failure(struct ath6kl *ar)
static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
{
int status = 0;
+ int ret;

/*
* Configure the device for rx dot11 header rules. "0,0" are the
@@ -461,6 +462,14 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
status = -EIO;
}

+ ret = ath6kl_wmi_info_req_cmd(ar->wmi, P2P_FLAG_CAPABILITIES_REQ |
+ P2P_FLAG_MACADDR_REQ |
+ P2P_FLAG_HMODEL_REQ);
+ if (ret) {
+ printk(KERN_DEBUG "ath6l: Failed to request P2P capabilities "
+ "(%d) - assuming P2P not supported\n", ret);
+ }
+
return status;
}

--
1.7.4.1


2011-08-29 12:28:13

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 06/20] ath6kl: Implement remain_on_channel and cancel_remain_on_channel

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 33 ++++++++++++++++++++++++++++
1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 898f394..a05036c 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1656,6 +1656,35 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
0);
}

+static int ath6kl_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration,
+ u64 *cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ /* TODO: if already pending or ongoing remain-on-channel,
+ * return -EBUSY */
+ *cookie = 1; /* only a single pending request is supported */
+
+ return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq,
+ duration);
+}
+
+static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
+ struct net_device *dev,
+ u64 cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ if (cookie != 1)
+ return -ENOENT;
+
+ return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
+}
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1683,6 +1712,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.set_beacon = ath6kl_set_beacon,
.del_beacon = ath6kl_del_beacon,
.change_station = ath6kl_change_station,
+ .remain_on_channel = ath6kl_remain_on_channel,
+ .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
};

struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
@@ -1704,6 +1735,8 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
return NULL;
}

+ wdev->wiphy->max_remain_on_channel_duration = 5000;
+
/* set device pointer for wiphy */
set_wiphy_dev(wdev->wiphy, dev);

--
1.7.4.1


2011-08-30 09:02:36

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> Use cfg80211 add/del_beacon callbacks for starting/stopping AP mode and
> set_beacon to update AP configuration (mainly, to update Beacon and
> Probe Response IEs).

[...]

> +enum wfi_mgmt_frame_type {

Typo? Should it be wmi_mgmt_frame_type?


Kalle

2011-08-29 12:30:37

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 19/20] ath6kl: Do not clear CONNECT bit setting in AP mode for STA disconnect

From: Edward Lu <[email protected]>

Signed-off-by: Edward Lu <[email protected]>
Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/main.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index a19caec..69a1b451 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -1284,7 +1284,8 @@ void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid,
cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL);
}

- clear_bit(CONNECTED, &ar->flag);
+ if (memcmp(ar->net_dev->dev_addr, bssid, ETH_ALEN) == 0)
+ clear_bit(CONNECTED, &ar->flag);
return;
}

--
1.7.4.1


Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On Tue, Aug 30, 2011 at 12:33:46PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > From: Edward Lu <[email protected]>
> > - if (num_chan)
> > - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
> > + if (num_chan) {
> > + for (i = 0; i < num_chan; i++)
> > + sc->ch_list[i] = cpu_to_le16(ch_list[i]);
> > + }
>
> if (num_chan) is not needed, the for loop is enough.

It is not that for loop would run once when num_chan is 0,
may be it needs to go from 0 to num_chan -1?.

Vasanth

2011-08-29 12:29:44

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 14/20] ath6kl: Report received Action frames to cfg80211

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 535205c..fae43d4 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -552,17 +552,26 @@ static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
return 0;
}

-static int ath6kl_wmi_rx_action_event_rx(u8 *datap, int len)
+static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct wmi_rx_action_event *ev;
+ u32 freq;
u16 dlen;
+ struct ath6kl *ar = wmi->parent_dev;

if (len < sizeof(*ev))
return -EINVAL;

ev = (struct wmi_rx_action_event *) datap;
+ freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
- ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u\n", dlen);
+ if (datap + len < ev->data + dlen) {
+ ath6kl_err("invalid wmi_rx_action_event: "
+ "len=%d dlen=%u\n", len, dlen);
+ return -EINVAL;
+ }
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
+ cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC);

return 0;
}
@@ -3088,7 +3097,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break;
case WMI_RX_ACTION_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
- ret = ath6kl_wmi_rx_action_event_rx(datap, len);
+ ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len);
break;
case WMI_P2P_INFO_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
--
1.7.4.1


2011-08-30 05:47:51

by Raja Mani

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
> Use cfg80211 add/del_beacon callbacks for starting/stopping AP mode and
> set_beacon to update AP configuration (mainly, to update Beacon and
> Probe Response IEs).
>
> Signed-off-by: Jouni Malinen<[email protected]>
> ---
> drivers/net/wireless/ath/ath6kl/cfg80211.c | 176 ++++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath6kl/core.h | 2 +
> drivers/net/wireless/ath/ath6kl/wmi.c | 46 +++++++
> drivers/net/wireless/ath/ath6kl/wmi.h | 20 +++
> 4 files changed, 244 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> index 9128aa3..e486c1c 100644
> --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> @@ -1435,6 +1435,178 @@ static int ar6k_cfg80211_suspend(struct wiphy *wiphy,
> }
> #endif
>
> +static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
> + struct ieee80211_channel *chan,
> + enum nl80211_channel_type channel_type)
> +{
> + struct ath6kl *ar = ath6kl_priv(dev);
> +
> + if (!test_bit(WLAN_ENABLED,&ar->flag)) {
> + ath6kl_err("%s: wlan disabled\n", __func__);
> + return -EIO;
> + }
> +
> + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
> + __func__, chan->center_freq, chan->hw_value);
> + ar->next_chan = chan->center_freq;
> +
> + return 0;
> +}
> +
> +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
> + struct beacon_parameters *info, bool add)
> +{
> + struct ath6kl *ar = ath6kl_priv(dev);
> + struct ieee80211_mgmt *mgmt;
> + u8 *ies;
> + int ies_len;
> + struct wmi_connect_cmd p;
> + int i;
> +
> + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add);
> +
> + if (!test_bit(WMI_READY,&ar->flag))
> + return -EIO;
> +
> + if (!test_bit(WLAN_ENABLED,&ar->flag))
> + return -EIO;

How about calling ath6kl_cfg80211_ready() function to check WMI_READY
and WLAN_ENABLED status ?

> +
> + if (ar->next_mode != AP_NETWORK)
> + return -EOPNOTSUPP;
> +
> + if (info->beacon_ies&&
> + ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
> + info->beacon_ies, info->beacon_ies_len))
> + return -EIO;
[..]

2011-08-30 08:40:52

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On Tue, Aug 30, 2011 at 11:17:43AM +0530, Raja Mani wrote:
> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
> >+static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
> >+ struct beacon_parameters *info, bool add)
> >+{

> >+ if (!test_bit(WMI_READY,&ar->flag))
> >+ return -EIO;
> >+
> >+ if (!test_bit(WLAN_ENABLED,&ar->flag))
> >+ return -EIO;
>
> How about calling ath6kl_cfg80211_ready() function to check
> WMI_READY and WLAN_ENABLED status ?

Sure, I can do that, but unless something else comes up, I would rather
do it after the patch series goes in. It looks like I missed addition of
that helper function since I started working on this before the cleanup
was complete.

By the way.. How did that message lost the space after the commas on
those test_bit lines? They are included in the patch I sent.

--
Jouni Malinen PGP id EFC895FA

2011-08-30 14:18:02

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 10/20] ath6kl: Use set_appie command to add Probe Request IEs

On Tue, Aug 30, 2011 at 12:26:10PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> > +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> > @@ -776,6 +776,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,

> > + if (request->ie) {
> > + if (ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
> > + request->ie, request->ie_len)) {
> > + ath6kl_err("failed to set Probe Request appie for "
> > + "scan");
> > + return -EIO;
> > + }
> > + }
>
> I would prefer to return the original error code from the wmi call.

I followed the style used in this function with
ath6kl_wmi_startscan_cmd(), but sure, returning the error code from
wmi.c sounds reasonable.

--
Jouni Malinen PGP id EFC895FA

2011-08-29 12:29:23

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 12/20] ath6kl: Report received Probe Request frames to cfg80211

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 +++++++++++++++++++
drivers/net/wireless/ath/ath6kl/core.h | 1 +
drivers/net/wireless/ath/ath6kl/init.c | 7 +++++++
drivers/net/wireless/ath/ath6kl/wmi.c | 20 ++++++++++++++++----
4 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index e78d332..d5f487f 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1733,6 +1733,24 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
buf, len);
}

+static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
+ struct net_device *dev,
+ u16 frame_type, bool reg)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
+ __func__, frame_type, reg);
+ if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
+ /*
+ * Note: This notification callback is not allowed to sleep, so
+ * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
+ * hardcode target to report Probe Request frames all the time.
+ */
+ ar->probe_req_report = reg;
+ }
+}
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1763,6 +1781,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.remain_on_channel = ath6kl_remain_on_channel,
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
.mgmt_tx = ath6kl_mgmt_tx,
+ .mgmt_frame_register = ath6kl_mgmt_frame_register,
};

struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 3872edb..99cabd2 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -457,6 +457,7 @@ struct ath6kl {
struct dentry *debugfs_phy;

u32 send_action_id;
+ bool probe_req_report;
u16 next_chan;
};

diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index aa7440d..376e576 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -470,6 +470,13 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
"(%d) - assuming P2P not supported\n", ret);
}

+ /* Enable Probe Request reporting for P2P */
+ ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true);
+ if (ret) {
+ printk(KERN_DEBUG "ath6l: Failed to enable Probe Request "
+ "reporting (%d)\n", ret);
+ }
+
return status;
}

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 87e4d65..8db53c7 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -499,18 +499,30 @@ static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len)
return 0;
}

-static int ath6kl_wmi_rx_probe_req_event_rx(u8 *datap, int len)
+static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct wmi_p2p_rx_probe_req_event *ev;
+ u32 freq;
u16 dlen;
+ struct ath6kl *ar = wmi->parent_dev;

if (len < sizeof(*ev))
return -EINVAL;

ev = (struct wmi_p2p_rx_probe_req_event *) datap;
+ freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
- ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u\n",
- dlen);
+ if (datap + len < ev->data + dlen) {
+ ath6kl_err("invalid wmi_p2p_rx_probe_req_event: "
+ "len=%d dlen=%u\n", len, dlen);
+ return -EINVAL;
+ }
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u "
+ "probe_req_report=%d\n",
+ dlen, freq, ar->probe_req_report);
+
+ if (ar->probe_req_report || ar->nw_type == AP_NETWORK)
+ cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC);

return 0;
}
@@ -3047,7 +3059,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break;
case WMI_RX_PROBE_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
- ret = ath6kl_wmi_rx_probe_req_event_rx(datap, len);
+ ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len);
break;
case WMI_P2P_CAPABILITIES_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
--
1.7.4.1


2011-08-29 12:30:09

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 16/20] ath6kl: Add support for new P2P iftypes in mode changes

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 2c35fd2..19b6da8 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -451,7 +451,8 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel,
}

if (nw_type & INFRA_NETWORK) {
- if (ar->wdev->iftype != NL80211_IFTYPE_STATION) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
+ ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: ath6k not in station mode\n", __func__);
return;
@@ -612,7 +613,8 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason,
}

if (ar->nw_type & INFRA_NETWORK) {
- if (ar->wdev->iftype != NL80211_IFTYPE_STATION) {
+ if (ar->wdev->iftype != NL80211_IFTYPE_STATION &&
+ ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: ath6k not in station mode\n", __func__);
return;
@@ -1206,6 +1208,12 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
case NL80211_IFTYPE_ADHOC:
ar->next_mode = ADHOC_NETWORK;
break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ ar->next_mode = INFRA_NETWORK;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ ar->next_mode = AP_NETWORK;
+ break;
default:
ath6kl_err("invalid interface type %u\n", type);
return -EOPNOTSUPP;
--
1.7.4.1


2011-08-30 08:49:56

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On 08/30/2011 11:40 AM, Jouni Malinen wrote:
> On Tue, Aug 30, 2011 at 11:17:43AM +0530, Raja Mani wrote:
>> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
>>> +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
>>> + struct beacon_parameters *info, bool add)
>>> +{
>
>>> + if (!test_bit(WMI_READY,&ar->flag))
>>> + return -EIO;
>>> +
>>> + if (!test_bit(WLAN_ENABLED,&ar->flag))
>>> + return -EIO;
>>
>> How about calling ath6kl_cfg80211_ready() function to check
>> WMI_READY and WLAN_ENABLED status ?
>
> Sure, I can do that, but unless something else comes up, I would rather
> do it after the patch series goes in. It looks like I missed addition of
> that helper function since I started working on this before the cleanup
> was complete.

I also prefer that you send a followup patch.

> By the way.. How did that message lost the space after the commas on
> those test_bit lines? They are included in the patch I sent.

Our mail servers seem to be the reason as I see the spaces in the
original patch when I read the patches from my private email.

Kalle

2011-08-29 12:29:05

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 10/20] ath6kl: Use set_appie command to add Probe Request IEs

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 10 ++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 3 +++
2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 924f62f..d287f0a 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -776,6 +776,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
request->ssids[i].ssid);
}

+ if (request->ie) {
+ if (ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
+ request->ie, request->ie_len)) {
+ ath6kl_err("failed to set Probe Request appie for "
+ "scan");
+ return -EIO;
+ }
+ }
+
if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
false, 0, 0, 0, NULL) != 0) {
ath6kl_err("wmi_startscan_cmd failed\n");
@@ -1763,6 +1772,7 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
BIT(NL80211_IFTYPE_ADHOC);
/* max num of ssids that can be probed during scanning */
wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+ wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 9a01d38..a32f91d 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -2216,6 +2216,9 @@ int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags);

int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi);

+int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
+ u8 ie_len);
+
void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi);

--
1.7.4.1


2011-08-30 10:36:18

by Raja Mani

[permalink] [raw]
Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On Tuesday 30 August 2011 04:00 PM, Kalle Valo wrote:
> On 08/30/2011 01:04 PM, Raja Mani wrote:
>> On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
>>
>>> if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
>>> - false, 0, 0, 0, NULL) != 0) {
>>> + false, 0, 0, n_channels, channels) != 0) {
>>> ath6kl_err("wmi_startscan_cmd failed\n");
>>
>> kfree(channels) for failure cases ??
>
> It's freed below as there's no return call for the error case:

Oops.. Sorry for the noise..

>
>>> ret = -EIO;
>>> }
>>>
>>> ar->scan_req = request;
>>>
>>> + kfree(channels);<-----
>>> +
>>> return ret;
>>> }
>
> I also got fooled by this :)
>
> Kalle

2011-08-30 09:54:23

by Raja Mani

[permalink] [raw]
Subject: Re: [PATCH 08/20] ath6kl: Request P2P capabilities during target init

On Monday 29 August 2011 05:53 PM, Jouni Malinen wrote:
> Signed-off-by: Jouni Malinen<[email protected]>
> ---
> drivers/net/wireless/ath/ath6kl/init.c | 9 +++++++++
> 1 files changed, 9 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
> index ad9716c..aa7440d 100644
> --- a/drivers/net/wireless/ath/ath6kl/init.c
> +++ b/drivers/net/wireless/ath/ath6kl/init.c
> @@ -417,6 +417,7 @@ void ath6kl_target_failure(struct ath6kl *ar)
> static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
> {
> int status = 0;
> + int ret;
>
> /*
> * Configure the device for rx dot11 header rules. "0,0" are the
> @@ -461,6 +462,14 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar)
> status = -EIO;
> }
>
> + ret = ath6kl_wmi_info_req_cmd(ar->wmi, P2P_FLAG_CAPABILITIES_REQ |
> + P2P_FLAG_MACADDR_REQ |
> + P2P_FLAG_HMODEL_REQ);
> + if (ret) {
> + printk(KERN_DEBUG "ath6l: Failed to request P2P capabilities "
> + "(%d) - assuming P2P not supported\n", ret);

Is it possible to use ath6kl_dbg() instead of printk here ?
Should it be ath6kl_err() ?

Another question is , Don't you have to assign error code (may be -EIO)
to 'status' variable in case of error ? not sure whether error code
assignment needed here or not..

> + }
> +
> return status;
> }
>

2011-08-29 12:29:39

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 13/20] ath6kl: Notify cfg80211 of TX status of mgmt_tx frames

Use WMI_TX_STATUS_EVENTID event to generate cfg80211_mgmt_tx_frame()
calls. Since we support only a single pending frame for now, use the
hardcoded cookie value 1 and store a copy of the pending frame in
the driver.

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 28 +++++++++++++++++++++++++---
drivers/net/wireless/ath/ath6kl/wmi.h | 3 +++
2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 8db53c7..535205c 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -483,10 +483,11 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
return 0;
}

-static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len)
+static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len)
{
struct wmi_tx_status_event *ev;
u32 id;
+ struct ath6kl *ar = wmi->parent_dev;

if (len < sizeof(*ev))
return -EINVAL;
@@ -495,6 +496,15 @@ static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len)
id = le32_to_cpu(ev->id);
ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
id, ev->ack_status);
+ if (wmi->last_mgmt_tx_frame) {
+ cfg80211_mgmt_tx_status(ar->net_dev, id,
+ wmi->last_mgmt_tx_frame,
+ wmi->last_mgmt_tx_frame_len,
+ !!ev->ack_status, GFP_ATOMIC);
+ kfree(wmi->last_mgmt_tx_frame);
+ wmi->last_mgmt_tx_frame = NULL;
+ wmi->last_mgmt_tx_frame_len = 0;
+ }

return 0;
}
@@ -2742,13 +2752,24 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
{
struct sk_buff *skb;
struct wmi_send_action_cmd *p;
+ u8 *buf;

if (wait)
return -EINVAL; /* Offload for wait not supported */

+ buf = kmalloc(data_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
- if (!skb)
+ if (!skb) {
+ kfree(buf);
return -ENOMEM;
+ }
+
+ kfree(wmi->last_mgmt_tx_frame);
+ wmi->last_mgmt_tx_frame = buf;
+ wmi->last_mgmt_tx_frame_len = data_len;

ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
@@ -3055,7 +3076,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break;
case WMI_TX_STATUS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
- ret = ath6kl_wmi_tx_status_event_rx(datap, len);
+ ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len);
break;
case WMI_RX_PROBE_REQ_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
@@ -3129,5 +3150,6 @@ void ath6kl_wmi_shutdown(struct wmi *wmi)
if (!wmi)
return;

+ kfree(wmi->last_mgmt_tx_frame);
kfree(wmi);
}
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index a32f91d..dfa7fc3 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -129,6 +129,9 @@ struct wmi {
u8 ht_allowed[A_NUM_BANDS];
u8 traffic_class;
bool is_probe_ssid;
+
+ u8 *last_mgmt_tx_frame;
+ size_t last_mgmt_tx_frame_len;
};

struct host_app_area {
--
1.7.4.1


2011-08-29 12:30:47

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 20/20] ath6kl: Include P2P IE(s) in GO Probe Response depending on request

P2P has special rules on when to include P2P IE(s) in Probe Response
frame based on the Probe Request frame. Handle P2P IE(s) separately
to follow these rules.

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 102 ++++++++++++++++++++++++++--
1 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index ee0f8bd..f4c060e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1520,6 +1520,48 @@ static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
return 0;
}

+static bool ath6kl_is_p2p_ie(const u8 *pos)
+{
+ return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ pos[2] == 0x50 && pos[3] == 0x6f &&
+ pos[4] == 0x9a && pos[5] == 0x09;
+}
+
+static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies,
+ size_t ies_len)
+{
+ const u8 *pos;
+ u8 *buf = NULL;
+ size_t len = 0;
+ int ret;
+
+ /*
+ * Filter out P2P IE(s) since they will be included depending on
+ * the Probe Request frame in ath6kl_send_go_probe_resp().
+ */
+
+ if (ies && ies_len) {
+ buf = kmalloc(ies_len, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ pos = ies;
+ while (pos + 1 < ies + ies_len) {
+ if (pos + 2 + pos[1] > ies + ies_len)
+ break;
+ if (!ath6kl_is_p2p_ie(pos)) {
+ memcpy(buf + len, pos, 2 + pos[1]);
+ len += 2 + pos[1];
+ }
+ pos += 2 + pos[1];
+ }
+ }
+
+ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
+ buf, len);
+ kfree(buf);
+ return ret ? -EIO : 0;
+}
+
static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info, bool add)
{
@@ -1546,11 +1588,12 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev,
ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON,
info->beacon_ies, info->beacon_ies_len))
return -EIO;
- if (info->proberesp_ies &&
- ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP,
- info->proberesp_ies,
- info->proberesp_ies_len))
- return -EIO;
+ if (info->proberesp_ies) {
+ res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies,
+ info->proberesp_ies_len);
+ if (res)
+ return res;
+ }
if (info->assocresp_ies &&
ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP,
info->assocresp_ies,
@@ -1733,6 +1776,41 @@ static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
}

+static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf,
+ size_t len, unsigned int freq)
+{
+ const u8 *pos;
+ u8 *p2p;
+ int p2p_len;
+ int ret;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ /* Include P2P IE(s) from the frame generated in user space. */
+
+ p2p = kmalloc(len, GFP_KERNEL);
+ if (p2p == NULL)
+ return -ENOMEM;
+ p2p_len = 0;
+
+ pos = mgmt->u.probe_resp.variable;
+ while (pos + 1 < buf + len) {
+ if (pos + 2 + pos[1] > buf + len)
+ break;
+ if (ath6kl_is_p2p_ie(pos)) {
+ memcpy(p2p + p2p_len, pos, 2 + pos[1]);
+ p2p_len += 2 + pos[1];
+ }
+ pos += 2 + pos[1];
+ }
+
+ ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da,
+ p2p, p2p_len);
+ kfree(p2p);
+ return ret;
+}
+
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
@@ -1741,6 +1819,20 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
{
struct ath6kl *ar = ath6kl_priv(dev);
u32 id;
+ const struct ieee80211_mgmt *mgmt;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ if (buf + len >= mgmt->u.probe_resp.variable &&
+ ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) &&
+ ieee80211_is_probe_resp(mgmt->frame_control)) {
+ /*
+ * Send Probe Response frame in AP mode using a separate WMI
+ * command to allow the target to fill in the generic IEs.
+ */
+ *cookie = 0; /* TX status not supported */
+ return ath6kl_send_go_probe_resp(ar, buf, len,
+ chan->center_freq);
+ }

id = ar->send_action_id++;
if (id == 0)
--
1.7.4.1


2011-08-29 12:29:57

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 15/20] ath6kl: Advertise supported mgmt_stypes

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index d5f487f..2c35fd2 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1751,6 +1751,28 @@ static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
}
}

+static const struct ieee80211_txrx_stypes
+ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_STATION] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+};
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1803,6 +1825,8 @@ struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
return NULL;
}

+ wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
+
wdev->wiphy->max_remain_on_channel_duration = 5000;

/* set device pointer for wiphy */
--
1.7.4.1


2011-08-30 10:39:58

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On Tue, Aug 30, 2011 at 11:49:39AM +0300, Kalle Valo wrote:
> I also prefer that you send a followup patch.

I'll address the comments as separate patches initially, but it is
starting to look like there is sufficient number of changes to justify
merging them into the patches and send v2 to the full set.

--
Jouni Malinen PGP id EFC895FA

2011-08-29 12:28:55

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 09/20] ath6kl: Add cfg80211 calls for remain-on-channel events

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 31 +++++++++++++++++++++++++++----
1 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 261ccff..2d80bdb 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -425,11 +425,14 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
return 0;
}

-static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len)
+static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
+ int len)
{
struct wmi_remain_on_chnl_event *ev;
u32 freq;
u32 dur;
+ struct ieee80211_channel *chan;
+ struct ath6kl *ar = wmi->parent_dev;

if (len < sizeof(*ev))
return -EINVAL;
@@ -439,15 +442,26 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len)
dur = le32_to_cpu(ev->duration);
ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
freq, dur);
+ chan = ieee80211_get_channel(ar->wdev->wiphy, freq);
+ if (!chan) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel "
+ "(freq=%u)\n", freq);
+ return -EINVAL;
+ }
+ cfg80211_ready_on_channel(ar->net_dev, 1, chan, NL80211_CHAN_NO_HT,
+ dur, GFP_ATOMIC);

return 0;
}

-static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len)
+static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
+ u8 *datap, int len)
{
struct wmi_cancel_remain_on_chnl_event *ev;
u32 freq;
u32 dur;
+ struct ieee80211_channel *chan;
+ struct ath6kl *ar = wmi->parent_dev;

if (len < sizeof(*ev))
return -EINVAL;
@@ -457,6 +471,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len)
dur = le32_to_cpu(ev->duration);
ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
"status=%u\n", freq, dur, ev->status);
+ chan = ieee80211_get_channel(ar->wdev->wiphy, freq);
+ if (!chan) {
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown "
+ "channel (freq=%u)\n", freq);
+ return -EINVAL;
+ }
+ cfg80211_remain_on_channel_expired(ar->net_dev, 1, chan,
+ NL80211_CHAN_NO_HT, GFP_ATOMIC);

return 0;
}
@@ -3009,12 +3031,13 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break;
case WMI_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
- ret = ath6kl_wmi_remain_on_chnl_event_rx(datap, len);
+ ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len);
break;
case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI,
"WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
- ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(datap, len);
+ ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
+ len);
break;
case WMI_TX_STATUS_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
--
1.7.4.1


2011-08-30 14:44:31

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 11/20] ath6kl: Support channel set request for startscan command

On Tue, Aug 30, 2011 at 12:33:46PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > @@ -785,14 +787,33 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
> > + n_channels = (request->n_channels > 127) ?
> > + 127 : request->n_channels;
>
> min()

It looks kind of silly to have 127U here, but I can do that if it is the
preferred way, i.e., min(127U, request->n_channels). min(127,
request->n_channels) complains because of the strict type-checking in
the macro (request->n_channels is u32).

> > + channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
> > + if (channels == NULL) {
> > + ath6kl_err("failed to set scan channels, "
> > + "scan all channels");
>
> ath6kl_warn() would be more approriate here as the driver can still
> continue.

OK.

> > if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0,
> > - false, 0, 0, 0, NULL) != 0) {
> > + false, 0, 0, n_channels, channels) != 0) {
> > ath6kl_err("wmi_startscan_cmd failed\n");
> > ret = -EIO;
>
> Again I would prefer to return the error code from the wmi call.

OK.

> > - if (num_chan)
> > - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
> > + if (num_chan) {
> > + for (i = 0; i < num_chan; i++)
> > + sc->ch_list[i] = cpu_to_le16(ch_list[i]);
> > + }
>
> if (num_chan) is not needed, the for loop is enough.

OK.

--
Jouni Malinen PGP id EFC895FA

2011-08-30 09:23:11

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 07/20] ath6kl: Implement mgmt_tx

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> +static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
> + struct ieee80211_channel *chan, bool offchan,
> + enum nl80211_channel_type channel_type,
> + bool channel_type_valid, unsigned int wait,
> + const u8 *buf, size_t len, u64 *cookie)
> +{
> + struct ath6kl *ar = ath6kl_priv(dev);
> + u32 id;
> +
> + id = ar->send_action_id++;
> + if (id == 0)
> + id = ar->send_action_id++;
> +
> + *cookie = id;
> + return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
> + buf, len);
> +}

I don't understand the "if (id == 0)" check. It would be nice to get a
comment giving some background info about the situation.

Kalle

2011-08-30 14:06:30

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 01/20] ath6kl: Add functionality for starting AP mode

On Tue, Aug 30, 2011 at 12:02:27PM +0300, Kalle Valo wrote:
> On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> > +enum wfi_mgmt_frame_type {
>
> Typo? Should it be wmi_mgmt_frame_type?

Yeah, fixed.

--
Jouni Malinen PGP id EFC895FA

2011-08-29 12:28:20

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 07/20] ath6kl: Implement mgmt_tx

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 +++++++++++++++++++
drivers/net/wireless/ath/ath6kl/core.h | 1 +
2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index a05036c..924f62f 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1685,6 +1685,24 @@ static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi);
}

+static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan, bool offchan,
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid, unsigned int wait,
+ const u8 *buf, size_t len, u64 *cookie)
+{
+ struct ath6kl *ar = ath6kl_priv(dev);
+ u32 id;
+
+ id = ar->send_action_id++;
+ if (id == 0)
+ id = ar->send_action_id++;
+
+ *cookie = id;
+ return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait,
+ buf, len);
+}
+
static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_virtual_intf = ath6kl_cfg80211_change_iface,
.scan = ath6kl_cfg80211_scan,
@@ -1714,6 +1732,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.change_station = ath6kl_change_station,
.remain_on_channel = ath6kl_remain_on_channel,
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
+ .mgmt_tx = ath6kl_mgmt_tx,
};

struct wireless_dev *ath6kl_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index f0b1dff..3872edb 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -456,6 +456,7 @@ struct ath6kl {
struct ath6kl_node_table scan_table;
struct dentry *debugfs_phy;

+ u32 send_action_id;
u16 next_chan;
};

--
1.7.4.1


2011-08-29 12:28:01

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 05/20] ath6kl: Add new WMI commands and events for P2P

Signed-off-by: Jouni Malinen <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 293 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 184 ++++++++++++++++++++-
2 files changed, 469 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 5c6688b..261ccff 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -425,6 +425,148 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
return 0;
}

+static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len)
+{
+ struct wmi_remain_on_chnl_event *ev;
+ u32 freq;
+ u32 dur;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_remain_on_chnl_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dur = le32_to_cpu(ev->duration);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
+ freq, dur);
+
+ return 0;
+}
+
+static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len)
+{
+ struct wmi_cancel_remain_on_chnl_event *ev;
+ u32 freq;
+ u32 dur;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
+ freq = le32_to_cpu(ev->freq);
+ dur = le32_to_cpu(ev->duration);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
+ "status=%u\n", freq, dur, ev->status);
+
+ return 0;
+}
+
+static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len)
+{
+ struct wmi_tx_status_event *ev;
+ u32 id;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_tx_status_event *) datap;
+ id = le32_to_cpu(ev->id);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
+ id, ev->ack_status);
+
+ return 0;
+}
+
+static int ath6kl_wmi_rx_probe_req_event_rx(u8 *datap, int len)
+{
+ struct wmi_p2p_rx_probe_req_event *ev;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_rx_probe_req_event *) datap;
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u\n",
+ dlen);
+
+ return 0;
+}
+
+static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
+{
+ struct wmi_p2p_capabilities_event *ev;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_capabilities_event *) datap;
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);
+
+ return 0;
+}
+
+static int ath6kl_wmi_rx_action_event_rx(u8 *datap, int len)
+{
+ struct wmi_rx_action_event *ev;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_rx_action_event *) datap;
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u\n", dlen);
+
+ return 0;
+}
+
+static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)
+{
+ struct wmi_p2p_info_event *ev;
+ u32 flags;
+ u16 dlen;
+
+ if (len < sizeof(*ev))
+ return -EINVAL;
+
+ ev = (struct wmi_p2p_info_event *) datap;
+ flags = le32_to_cpu(ev->info_req_flags);
+ dlen = le16_to_cpu(ev->len);
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);
+
+ if (flags & P2P_FLAG_CAPABILITIES_REQ) {
+ struct wmi_p2p_capabilities *cap;
+ if (dlen < sizeof(*cap))
+ return -EINVAL;
+ cap = (struct wmi_p2p_capabilities *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",
+ cap->go_power_save);
+ }
+
+ if (flags & P2P_FLAG_MACADDR_REQ) {
+ struct wmi_p2p_macaddr *mac;
+ if (dlen < sizeof(*mac))
+ return -EINVAL;
+ mac = (struct wmi_p2p_macaddr *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",
+ mac->mac_addr);
+ }
+
+ if (flags & P2P_FLAG_HMODEL_REQ) {
+ struct wmi_p2p_hmodel *mod;
+ if (dlen < sizeof(*mod))
+ return -EINVAL;
+ mod = (struct wmi_p2p_hmodel *) ev->data;
+ ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",
+ mod->p2p_model,
+ mod->p2p_model ? "host" : "firmware");
+ }
+ return 0;
+}
+
static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
{
struct sk_buff *skb;
@@ -2523,6 +2665,128 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
NO_SYNC_WMIFLAG);
}

+int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
+{
+ struct sk_buff *skb;
+ struct wmi_disable_11b_rates_cmd *cmd;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n",
+ disable);
+ cmd = (struct wmi_disable_11b_rates_cmd *) skb->data;
+ cmd->disable = disable ? 1 : 0;
+
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_DISABLE_11B_RATES_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur)
+{
+ struct sk_buff *skb;
+ struct wmi_remain_on_chnl_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n",
+ freq, dur);
+ p = (struct wmi_remain_on_chnl_cmd *) skb->data;
+ p->freq = cpu_to_le32(freq);
+ p->duration = cpu_to_le32(dur);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_REMAIN_ON_CHNL_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
+ const u8 *data, u16 data_len)
+{
+ struct sk_buff *skb;
+ struct wmi_send_action_cmd *p;
+
+ if (wait)
+ return -EINVAL; /* Offload for wait not supported */
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
+ "len=%u\n", id, freq, wait, data_len);
+ p = (struct wmi_send_action_cmd *) skb->data;
+ p->id = cpu_to_le32(id);
+ p->freq = cpu_to_le32(freq);
+ p->wait = cpu_to_le32(wait);
+ p->len = cpu_to_le16(data_len);
+ memcpy(p->data, data, data_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_ACTION_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq,
+ const u8 *dst,
+ const u8 *data, u16 data_len)
+{
+ struct sk_buff *skb;
+ struct wmi_p2p_probe_response_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM "
+ "len=%u\n", freq, dst, data_len);
+ p = (struct wmi_p2p_probe_response_cmd *) skb->data;
+ p->freq = cpu_to_le32(freq);
+ memcpy(p->destination_addr, dst, ETH_ALEN);
+ p->len = cpu_to_le16(data_len);
+ memcpy(p->data, data, data_len);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_PROBE_RESPONSE_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable)
+{
+ struct sk_buff *skb;
+ struct wmi_probe_req_report_cmd *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n",
+ enable);
+ p = (struct wmi_probe_req_report_cmd *) skb->data;
+ p->enable = enable ? 1 : 0;
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_PROBE_REQ_REPORT_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags)
+{
+ struct sk_buff *skb;
+ struct wmi_get_p2p_info *p;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*p));
+ if (!skb)
+ return -ENOMEM;
+
+ ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n",
+ info_req_flags);
+ p = (struct wmi_get_p2p_info *) skb->data;
+ p->info_req_flags = cpu_to_le32(info_req_flags);
+ return ath6kl_wmi_cmd_send(wmi, skb, WMI_GET_P2P_INFO_CMDID,
+ NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi)
+{
+ ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n");
+ return ath6kl_wmi_simple_cmd(wmi, WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
+}

static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
{
@@ -2743,6 +3007,35 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
break;
+ case WMI_REMAIN_ON_CHNL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
+ ret = ath6kl_wmi_remain_on_chnl_event_rx(datap, len);
+ break;
+ case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
+ ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(datap, len);
+ break;
+ case WMI_TX_STATUS_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
+ ret = ath6kl_wmi_tx_status_event_rx(datap, len);
+ break;
+ case WMI_RX_PROBE_REQ_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
+ ret = ath6kl_wmi_rx_probe_req_event_rx(datap, len);
+ break;
+ case WMI_P2P_CAPABILITIES_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
+ ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
+ break;
+ case WMI_RX_ACTION_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
+ ret = ath6kl_wmi_rx_action_event_rx(datap, len);
+ break;
+ case WMI_P2P_INFO_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
+ ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
+ break;
default:
ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
wmi->stat.cmd_id_err++;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 2d22c7f9..9a01d38 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -490,17 +490,52 @@ enum wmi_cmd_id {
WMI_SET_PASSPHRASE_CMDID,
WMI_SEND_ASSOC_RES_CMDID,
WMI_SET_ASSOC_REQ_RELAY_CMDID,
- WMI_GET_RFKILL_MODE_CMDID,

/* ACS command, consists of sub-commands */
WMI_ACS_CTRL_CMDID,
+ WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
+ WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */
+
+ /* Pktlog cmds */
+ WMI_PKTLOG_ENABLE_CMDID,
+ WMI_PKTLOG_DISABLE_CMDID,
+
+ /* More P2P Cmds */
+ WMI_P2P_GO_NEG_REQ_RSP_CMDID,
+ WMI_P2P_GRP_INIT_CMDID,
+ WMI_P2P_GRP_FORMATION_DONE_CMDID,
+ WMI_P2P_INVITE_CMDID,
+ WMI_P2P_INVITE_REQ_RSP_CMDID,
+ WMI_P2P_PROV_DISC_REQ_CMDID,
+ WMI_P2P_SET_CMDID,

+ WMI_GET_RFKILL_MODE_CMDID,
+ WMI_SET_RFKILL_MODE_CMDID,
+ WMI_AP_SET_APSD_CMDID,
+ WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
+
+ WMI_P2P_SDPD_TX_CMDID, /* F05C */
+ WMI_P2P_STOP_SDPD_CMDID,
+ WMI_P2P_CANCEL_CMDID,
/* Ultra low power store / recall commands */
WMI_STORERECALL_CONFIGURE_CMDID,
WMI_STORERECALL_RECALL_CMDID,
WMI_STORERECALL_HOST_READY_CMDID,
WMI_FORCE_TARGET_ASSERT_CMDID,
- WMI_SET_EXCESS_TX_RETRY_THRES_CMDID,
+
+ WMI_SET_PROBED_SSID_EX_CMDID,
+ WMI_SET_NETWORK_LIST_OFFLOAD_CMDID,
+ WMI_SET_ARP_NS_OFFLOAD_CMDID,
+ WMI_ADD_WOW_EXT_PATTERN_CMDID,
+ WMI_GTK_OFFLOAD_OP_CMDID,
+ WMI_REMAIN_ON_CHNL_CMDID,
+ WMI_CANCEL_REMAIN_ON_CHNL_CMDID,
+ WMI_SEND_ACTION_CMDID,
+ WMI_PROBE_REQ_REPORT_CMDID,
+ WMI_DISABLE_11B_RATES_CMDID,
+ WMI_SEND_PROBE_RESPONSE_CMDID,
+ WMI_GET_P2P_INFO_CMDID,
+ WMI_AP_JOIN_BSS_CMDID,
};

enum wfi_mgmt_frame_type {
@@ -1188,15 +1223,26 @@ enum wmi_event_id {
WMI_WAC_START_WPS_EVENTID,
WMI_WAC_CTRL_REQ_REPLY_EVENTID,

+ WMI_REPORT_WMM_PARAMS_EVENTID,
+ WMI_WAC_REJECT_WPS_EVENTID,
+
+ /* More P2P Events */
+ WMI_P2P_GO_NEG_REQ_EVENTID,
+ WMI_P2P_INVITE_REQ_EVENTID,
+ WMI_P2P_INVITE_RCVD_RESULT_EVENTID,
+ WMI_P2P_INVITE_SENT_RESULT_EVENTID,
+ WMI_P2P_PROV_DISC_RESP_EVENTID,
+ WMI_P2P_PROV_DISC_REQ_EVENTID,
+
/* RFKILL Events */
WMI_RFKILL_STATE_CHANGE_EVENTID,
WMI_RFKILL_GET_MODE_CMD_EVENTID,
- WMI_THIN_RESERVED_START_EVENTID = 0x8000,

- /*
- * Events in this range are reserved for thinmode
- * See wmi_thin.h for actual definitions
- */
+ WMI_P2P_START_SDPD_EVENTID,
+ WMI_P2P_SDPD_RX_EVENTID,
+
+ WMI_THIN_RESERVED_START_EVENTID = 0x8000,
+ /* Events in this range are reserved for thinmode */
WMI_THIN_RESERVED_END_EVENTID = 0x8fff,

WMI_SET_CHANNEL_EVENTID,
@@ -1204,7 +1250,17 @@ enum wmi_event_id {

/* Generic ACS event */
WMI_ACS_EVENTID,
- WMI_REPORT_WMM_PARAMS_EVENTID
+ WMI_STORERECALL_STORE_EVENTID,
+ WMI_WOW_EXT_WAKE_EVENTID,
+ WMI_GTK_OFFLOAD_STATUS_EVENTID,
+ WMI_NETWORK_LIST_OFFLOAD_EVENTID,
+ WMI_REMAIN_ON_CHNL_EVENTID,
+ WMI_CANCEL_REMAIN_ON_CHNL_EVENTID,
+ WMI_TX_STATUS_EVENTID,
+ WMI_RX_PROBE_REQ_EVENTID,
+ WMI_P2P_CAPABILITIES_EVENTID,
+ WMI_RX_ACTION_EVENTID,
+ WMI_P2P_INFO_EVENTID,
};

struct wmi_ready_event_2 {
@@ -1870,6 +1926,100 @@ struct wmi_ap_mode_stat {

/* End of AP mode definitions */

+struct wmi_remain_on_chnl_cmd {
+ __le32 freq;
+ __le32 duration;
+} __packed;
+
+struct wmi_send_action_cmd {
+ __le32 id;
+ __le32 freq;
+ __le32 wait;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_tx_status_event {
+ __le32 id;
+ u8 ack_status;
+} __packed;
+
+struct wmi_probe_req_report_cmd {
+ u8 enable;
+} __packed;
+
+struct wmi_disable_11b_rates_cmd {
+ u8 disable;
+} __packed;
+
+struct wmi_set_appie_extended_cmd {
+ u8 role_id;
+ u8 mgmt_frm_type;
+ u8 ie_len;
+ u8 ie_info[0];
+} __packed;
+
+struct wmi_remain_on_chnl_event {
+ __le32 freq;
+ __le32 duration;
+} __packed;
+
+struct wmi_cancel_remain_on_chnl_event {
+ __le32 freq;
+ __le32 duration;
+ u8 status;
+} __packed;
+
+struct wmi_rx_action_event {
+ __le32 freq;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_capabilities_event {
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_rx_probe_req_event {
+ __le32 freq;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+#define P2P_FLAG_CAPABILITIES_REQ (0x00000001)
+#define P2P_FLAG_MACADDR_REQ (0x00000002)
+#define P2P_FLAG_HMODEL_REQ (0x00000002)
+
+struct wmi_get_p2p_info {
+ __le32 info_req_flags;
+} __packed;
+
+struct wmi_p2p_info_event {
+ __le32 info_req_flags;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+struct wmi_p2p_capabilities {
+ u8 go_power_save;
+} __packed;
+
+struct wmi_p2p_macaddr {
+ u8 mac_addr[ETH_ALEN];
+} __packed;
+
+struct wmi_p2p_hmodel {
+ u8 p2p_model;
+} __packed;
+
+struct wmi_p2p_probe_response_cmd {
+ __le32 freq;
+ u8 destination_addr[ETH_ALEN];
+ __le16 len;
+ u8 data[0];
+} __packed;
+
/* Extended WMI (WMIX)
*
* Extended WMIX commands are encapsulated in a WMI message with
@@ -2048,6 +2198,24 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version,
int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie,
u8 ie_len);

+/* P2P */
+int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable);
+
+int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur);
+
+int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait,
+ const u8 *data, u16 data_len);
+
+int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq,
+ const u8 *dst,
+ const u8 *data, u16 data_len);
+
+int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable);
+
+int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags);
+
+int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi);
+
void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi);

--
1.7.4.1


2011-08-30 09:26:15

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 10/20] ath6kl: Use set_appie command to add Probe Request IEs

On 08/29/2011 03:23 PM, Jouni Malinen wrote:
> --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> @@ -776,6 +776,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
> request->ssids[i].ssid);
> }
>
> + if (request->ie) {
> + if (ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ,
> + request->ie, request->ie_len)) {
> + ath6kl_err("failed to set Probe Request appie for "
> + "scan");
> + return -EIO;
> + }
> + }

I would prefer to return the original error code from the wmi call.

Kalle