aboutsummaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
authorAhmad Kholaif <akholaif@qca.qualcomm.com>2015-07-23 23:32:58 +0000
committerAnjaneedevi Kapparapu <akappa@codeaurora.org>2016-04-01 16:44:27 +0530
commit7f91572ad497ebcd2c9b337fd1e27279cda83cf9 (patch)
tree4d6269d49feb8cd2248f17dc8d96df8d4f4fc417 /src/drivers
parent1e08971278e3865ed55b5ae13d0a990f234ebf98 (diff)
downloadandroid_external_wpa_supplicant_8-7f91572ad497ebcd2c9b337fd1e27279cda83cf9.tar.gz
android_external_wpa_supplicant_8-7f91572ad497ebcd2c9b337fd1e27279cda83cf9.tar.bz2
android_external_wpa_supplicant_8-7f91572ad497ebcd2c9b337fd1e27279cda83cf9.zip
nl80211: Add means to query preferred channels
Extend the QCA vendor specific nl80211 interface to query the preferred frequency list from driver and add a new wpa_cli command to query this information. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Git-commit: 983422088f0066068fd364013623d1e475031e6b Git-repo : git://w1.fi/srv/git/hostap.git Change-Id: I71de761d267f9d46ab6ae9cd35cc08daf5d2bd99 CRs-Fixed: 842468
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/driver.h24
-rw-r--r--src/drivers/driver_nl80211.c145
-rw-r--r--src/drivers/driver_nl80211.h1
-rw-r--r--src/drivers/driver_nl80211_capa.c3
4 files changed, 172 insertions, 1 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0c4e4f2d..5f3c6ffd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1404,6 +1404,16 @@ enum wpa_driver_if_type {
* WPA_IF_MESH - Mesh interface
*/
WPA_IF_MESH,
+
+ /*
+ * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only)
+ */
+ WPA_IF_TDLS,
+
+ /*
+ * WPA_IF_IBSS - IBSS interface (used for pref freq only)
+ */
+ WPA_IF_IBSS,
};
struct wpa_init_params {
@@ -3411,6 +3421,20 @@ struct wpa_driver_ops {
int (*abort_scan)(void *priv);
/**
+ * get_pref_freq_list - Get preferred frequency list for an interface
+ * @priv: Private driver interface data
+ * @if_type: Interface type
+ * @num: Number of channels
+ * @freq_list: Preferred channel frequency list encoded in MHz values
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to query the preferred frequency list from
+ * the driver specific to a particular interface type.
+ */
+ int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
+ unsigned int *num, unsigned int *freq_list);
+
+ /**
* set_prob_oper_freq - Indicate probable P2P operating channel
* @priv: Private driver interface data
* @freq: Channel frequency in MHz
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 6aa4e3d5..9d7d7e57 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5806,8 +5806,9 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
return NL80211_IFTYPE_P2P_DEVICE;
case WPA_IF_MESH:
return NL80211_IFTYPE_MESH_POINT;
+ default:
+ return -1;
}
- return -1;
}
@@ -8501,6 +8502,147 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
}
+struct nl80211_pcl {
+ unsigned int num;
+ unsigned int *freq_list;
+};
+
+static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nl80211_pcl *param = arg;
+ struct nlattr *nl_vend, *attr;
+ enum qca_iface_type iface_type;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ unsigned int num, max_num;
+ u32 *freqs;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (!nl_vend)
+ return NL_SKIP;
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
+ if (!attr) {
+ wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ iface_type = (enum qca_iface_type) nla_get_u32(attr);
+ wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
+ iface_type);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: preferred_freq_list couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ /*
+ * param->num has the maximum number of entries for which there
+ * is room in the freq_list provided by the caller.
+ */
+ freqs = nla_data(attr);
+ max_num = nla_len(attr) / sizeof(u32);
+ if (max_num > param->num)
+ max_num = param->num;
+ for (num = 0; num < max_num; num++)
+ param->freq_list[num] = freqs[num];
+ param->num = num;
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_pref_freq_list(void *priv,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ unsigned int i;
+ struct nlattr *params;
+ struct nl80211_pcl param;
+ enum qca_iface_type iface_type;
+
+ if (!drv->get_pref_freq_list)
+ return -1;
+
+ switch (if_type) {
+ case WPA_IF_STATION:
+ iface_type = QCA_IFACE_TYPE_STA;
+ break;
+ case WPA_IF_AP_BSS:
+ iface_type = QCA_IFACE_TYPE_AP;
+ break;
+ case WPA_IF_P2P_GO:
+ iface_type = QCA_IFACE_TYPE_P2P_GO;
+ break;
+ case WPA_IF_P2P_CLIENT:
+ iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
+ break;
+ case WPA_IF_IBSS:
+ iface_type = QCA_IFACE_TYPE_IBSS;
+ break;
+ case WPA_IF_TDLS:
+ iface_type = QCA_IFACE_TYPE_TDLS;
+ break;
+ default:
+ return -1;
+ }
+
+ param.num = *num;
+ param.freq_list = freq_list;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
+ iface_type)) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in send_and_recv_msgs", __func__);
+ return ret;
+ }
+
+ *num = param.num;
+
+ for (i = 0; i < *num; i++) {
+ wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
+ i, freq_list[i]);
+ }
+
+ return 0;
+}
+
+
static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
{
struct i802_bss *bss = priv;
@@ -8703,5 +8845,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.del_tx_ts = nl80211_del_ts,
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
+ .get_pref_freq_list = nl80211_get_pref_freq_list,
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index d7ec0b94..33bcc0e2 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -146,6 +146,7 @@ struct wpa_driver_nl80211_data {
unsigned int set_rekey_offload:1;
unsigned int p2p_go_ctwindow_supported:1;
unsigned int setband_vendor_cmd_avail:1;
+ unsigned int get_pref_freq_list:1;
unsigned int set_prob_oper_freq:1;
u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index e56f1113..4cf31238 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -589,6 +589,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
drv->get_features_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST:
+ drv->get_pref_freq_list = 1;
+ break;
case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL:
drv->set_prob_oper_freq = 1;
break;