diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index ec1be863d..6a5243cf8 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -134,6 +134,7 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6, /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */ QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7, + QCA_WLAN_VENDOR_ATTR_TEST = 8, /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 7785fbcaf..9d93cc936 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2065,6 +2065,60 @@ static int i802_set_iface_flags(struct i802_bss *bss, int up) } +#ifdef CONFIG_TESTING_OPTIONS +static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg) +{ + /* struct wpa_driver_nl80211_data *drv = arg; */ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + + wpa_printf(MSG_DEBUG, + "nl80211: QCA vendor test command response received"); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_VENDOR_DATA]) { + wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute"); + return NL_SKIP; + } + + wpa_hexdump(MSG_DEBUG, + "nl80211: Received QCA vendor test command response", + nla_data(tb[NL80211_ATTR_VENDOR_DATA]), + nla_len(tb[NL80211_ATTR_VENDOR_DATA])); + + return NL_SKIP; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + +static void qca_vendor_test(struct wpa_driver_nl80211_data *drv) +{ +#ifdef CONFIG_TESTING_OPTIONS + struct nl_msg *msg; + struct nlattr *params; + int ret; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_TEST) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) { + nlmsg_free(msg); + return; + } + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv); + wpa_printf(MSG_DEBUG, + "nl80211: QCA vendor test command returned %d (%s)", + ret, strerror(-ret)); +#endif /* CONFIG_TESTING_OPTIONS */ +} + + static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, const u8 *set_addr, int first, @@ -2151,6 +2205,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, drv, drv->ctx); } + if (drv->vendor_cmd_test_avail) + qca_vendor_test(drv); + return 0; } diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 4567f422b..f19ac2921 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -136,6 +136,7 @@ struct wpa_driver_nl80211_data { unsigned int start_iface_up:1; unsigned int test_use_roc_tx:1; unsigned int ignore_deauth_event:1; + unsigned int vendor_cmd_test_avail:1; unsigned int roaming_vendor_cmd_avail:1; unsigned int dfs_vendor_cmd_avail:1; unsigned int have_low_prio_scan:1; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 36c8ce2b1..e86743961 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -544,6 +544,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) } vinfo = nla_data(nl); switch (vinfo->subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_TEST: + drv->vendor_cmd_test_avail = 1; + break; case QCA_NL80211_VENDOR_SUBCMD_ROAMING: drv->roaming_vendor_cmd_avail = 1; break; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index d5550339b..6a7b509e1 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -1535,6 +1535,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *data, size_t len) { switch (subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_TEST: + wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len); + break; case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: qca_nl80211_avoid_freq(drv, data, len); break;