16c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* 26c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - Capabilities 3807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> 46c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> 56c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications 66c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * 76c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This software may be distributed under the terms of the BSD license. 86c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * See README for more details. 96c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "includes.h" 126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include <netlink/genl/genl.h> 136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/common.h" 156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/ieee802_11_common.h" 16092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart#include "common/wpa_common.h" 176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/qca-vendor.h" 186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "common/qca-vendor-attr.h" 196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "driver_nl80211.h" 206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int protocol_feature_handler(struct nl_msg *msg, void *arg) 236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 *feat = arg; 256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; 266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]) 326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]); 336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv) 396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 feat = 0; 416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt msg = nlmsg_alloc(); 446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!msg) 456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) { 486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nlmsg_free(msg); 496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0) 536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return feat; 546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct wiphy_info_data { 606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_nl80211_data *drv; 616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_capa *capa; 626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int num_multichan_concurrent; 646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int error:1; 666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int device_ap_sme:1; 676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int poll_command_supported:1; 686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int data_tx_status:1; 696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int auth_supported:1; 706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int connect_supported:1; 716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int p2p_go_supported:1; 726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int p2p_client_supported:1; 737f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt unsigned int p2p_go_ctwindow_supported:1; 746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int p2p_concurrent:1; 756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int channel_switch_supported:1; 766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int set_qos_map_supported:1; 776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int have_low_prio_scan:1; 786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int wmm_ac_supported:1; 796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int mac_addr_rand_scan_supported:1; 806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int mac_addr_rand_sched_scan_supported:1; 816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic unsigned int probe_resp_offload_support(int supp_protocols) 856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int prot = 0; 876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS) 896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS; 906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2) 916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2; 926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P) 936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P; 946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U) 956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING; 966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return prot; 986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_supported_iftypes(struct wiphy_info_data *info, 1026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 1036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_mode; 1056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int i; 1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_mode, tb, i) { 1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (nla_type(nl_mode)) { 1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_AP: 1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->flags |= WPA_DRIVER_FLAGS_AP; 1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_MESH_POINT: 1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->flags |= WPA_DRIVER_FLAGS_MESH; 1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_ADHOC: 1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->flags |= WPA_DRIVER_FLAGS_IBSS; 1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_P2P_DEVICE: 1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->flags |= 1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE; 1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_P2P_GO: 1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->p2p_go_supported = 1; 1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_IFTYPE_P2P_CLIENT: 1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->p2p_client_supported = 1; 1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wiphy_info_iface_comb_process(struct wiphy_info_data *info, 1376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_combi) 1386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 1396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB]; 1406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT]; 1416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_limit, *nl_mode; 1426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int err, rem_limit, rem_mode; 1436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int combination_has_p2p = 0, combination_has_mgd = 0; 1446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt static struct nla_policy 1456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt iface_combination_policy[NUM_NL80211_IFACE_COMB] = { 1466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED }, 1476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 }, 1486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG }, 1496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 }, 1506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 }, 1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }, 1526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = { 1536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED }, 1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 }, 1556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }; 1566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB, 1586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl_combi, iface_combination_policy); 1596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] || 1606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !tb_comb[NL80211_IFACE_COMB_MAXNUM] || 1616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) 1626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; /* broken combination */ 1636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS]) 1656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->flags |= WPA_DRIVER_FLAGS_RADAR; 1666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS], 1686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt rem_limit) { 1696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT, 1706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl_limit, iface_limit_policy); 1716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES]) 1726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; /* broken combination */ 1736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_mode, 1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_limit[NL80211_IFACE_LIMIT_TYPES], 1766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt rem_mode) { 1776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ift = nla_type(nl_mode); 1786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ift == NL80211_IFTYPE_P2P_GO || 1796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ift == NL80211_IFTYPE_P2P_CLIENT) 1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt combination_has_p2p = 1; 1816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ift == NL80211_IFTYPE_STATION) 1826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt combination_has_mgd = 1; 1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (combination_has_p2p && combination_has_mgd) 1856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 1866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (combination_has_p2p && combination_has_mgd) { 1896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int num_channels = 1906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]); 1916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->p2p_concurrent = 1; 1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info->num_multichan_concurrent < num_channels) 1946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->num_multichan_concurrent = num_channels; 1956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 1986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_iface_comb(struct wiphy_info_data *info, 2026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 2036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 2046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_combi; 2056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem_combi; 2066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 2086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_combi, tb, rem_combi) { 2116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (wiphy_info_iface_comb_process(info, nl_combi) > 0) 2126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 2156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_supp_cmds(struct wiphy_info_data *info, 2186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 2196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_cmd; 2216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int i; 2226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 2246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_cmd, tb, i) { 2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (nla_get_u32(nl_cmd)) { 2286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_AUTHENTICATE: 2296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->auth_supported = 1; 2306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_CONNECT: 2326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->connect_supported = 1; 2336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_START_SCHED_SCAN: 2356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->sched_scan_supported = 1; 2366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_PROBE_CLIENT: 2386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->poll_command_supported = 1; 2396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_CHANNEL_SWITCH: 2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->channel_switch_supported = 1; 2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_CMD_SET_QOS_MAP: 2446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->set_qos_map_supported = 1; 2456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 2466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 2486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 2496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_cipher_suites(struct wiphy_info_data *info, 2526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 2536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int i, num; 2556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 *ciphers; 2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt num = nla_len(tb) / sizeof(u32); 2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ciphers = nla_data(tb); 2626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (i = 0; i < num; i++) { 2636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 c = ciphers[i]; 2646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d", 2666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt c >> 24, (c >> 16) & 0xff, 2676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (c >> 8) & 0xff, c & 0xff); 2686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (c) { 269092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_CCMP_256: 2706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256; 2716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 272092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_GCMP_256: 2736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256; 2746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 275092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_CCMP: 2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP; 2776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 278092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_GCMP: 2796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP; 2806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 281092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_TKIP: 2826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP; 2836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 284092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_WEP104: 2856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104; 2866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 287092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_WEP40: 2886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40; 2896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 290092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_AES_128_CMAC: 2916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP; 2926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 293092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_BIP_GMAC_128: 2946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128; 2956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 296092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_BIP_GMAC_256: 2976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256; 2986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 299092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_BIP_CMAC_256: 3006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256; 3016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 302092955c7394ee96d6c8c9724ff46a3c038b36143Paul Stewart case RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED: 3036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED; 3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_max_roc(struct wpa_driver_capa *capa, 3116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 3126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 3136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb) 3146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_remain_on_chan = nla_get_u32(tb); 3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls, 3196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *ext_setup) 3206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 3216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tdls == NULL) 3226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 3236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: TDLS supported"); 3256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT; 3266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ext_setup) { 3286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup"); 3296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP; 3306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 3316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 3326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 3336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 334f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidtstatic int ext_feature_isset(const u8 *ext_features, int ext_features_len, 335f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt enum nl80211_ext_feature_index ftidx) 336f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt{ 337f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt u8 ft_byte; 338f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 339f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt if ((int) ftidx / 8 >= ext_features_len) 340f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt return 0; 341f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 342f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt ft_byte = ext_features[ftidx / 8]; 343f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt return (ft_byte & BIT(ftidx % 8)) != 0; 344f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt} 345f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 346f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 347f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidtstatic void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, 348f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt struct nlattr *tb) 349f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt{ 350f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt struct wpa_driver_capa *capa = info->capa; 351849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt u8 *ext_features; 352849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt int len; 353f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 354f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt if (tb == NULL) 355f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt return; 356f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 357849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt ext_features = nla_data(tb); 358849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt len = nla_len(tb); 359849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 360849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_VHT_IBSS)) 361f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS; 362849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt 363849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_RRM)) 364849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM; 3659839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 3669839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA)) 3679839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS; 368abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt 369abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt if (ext_feature_isset(ext_features, len, 370abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) 371abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY; 372abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt 373abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt if (ext_feature_isset(ext_features, len, 374abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt NL80211_EXT_FEATURE_BEACON_RATE_HT)) 375abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_HT; 376abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt 377abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt if (ext_feature_isset(ext_features, len, 378abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt NL80211_EXT_FEATURE_BEACON_RATE_VHT)) 379abb90a3fc1917e628167827cb14e742000605332Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT; 380293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 381293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ext_feature_isset(ext_features, len, 382293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NL80211_EXT_FEATURE_SET_SCAN_DWELL)) 383293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL; 384293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt 385293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt if (ext_feature_isset(ext_features, len, 386293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NL80211_EXT_FEATURE_SCAN_START_TIME) && 387293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ext_feature_isset(ext_features, len, 388293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NL80211_EXT_FEATURE_BSS_PARENT_TSF) && 389293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt ext_feature_isset(ext_features, len, 390293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt NL80211_EXT_FEATURE_SET_SCAN_DWELL)) 391293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT; 392ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (ext_feature_isset(ext_features, len, 393ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA)) 394ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA; 395ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (ext_feature_isset(ext_features, len, 396ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED)) 397ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED; 398ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (ext_feature_isset(ext_features, len, 399ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI)) 400ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI; 401f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt} 402f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 403f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt 4046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_feature_flags(struct wiphy_info_data *info, 4056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 4066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 flags; 4086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_capa *capa = info->capa; 4096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 4116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 4126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags = nla_get_u32(tb); 4146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_SK_TX_STATUS) 4166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->data_tx_status = 1; 4176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_INACTIVITY_TIMER) 4196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER; 4206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_SAE) 4226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_SAE; 4236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_NEED_OBSS_SCAN) 4256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN; 4266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE) 4286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX; 4296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) { 4316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch"); 4326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH; 4336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 4346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4357f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt if (flags & NL80211_FEATURE_P2P_GO_CTWIN) 4367f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt info->p2p_go_ctwindow_supported = 1; 4377f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt 4386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN) 4396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->have_low_prio_scan = 1; 4406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) 4426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->mac_addr_rand_scan_supported = 1; 4436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR) 4456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->mac_addr_rand_sched_scan_supported = 1; 4466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_STATIC_SMPS) 4486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC; 4496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_DYNAMIC_SMPS) 4516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC; 4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) 4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->wmm_ac_supported = 1; 4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) 4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES; 4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES) 4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES; 4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_QUIET) 4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET; 4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (flags & NL80211_FEATURE_TX_POWER_INSERTION) 4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION; 467ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt 468ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt if (flags & NL80211_FEATURE_HT_IBSS) 469ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS; 47057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 47157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (flags & NL80211_FEATURE_FULL_AP_CLIENT_STATE) 47257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE; 4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa, 4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 protocols; 4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 4836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt protocols = nla_get_u32(tb); 4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP " 4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "mode"); 4876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD; 4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->probe_resp_offloads = probe_resp_offload_support(protocols); 4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa, 4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb) 4946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 4956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1]; 4966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 4986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 4996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG, 5016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb, NULL)) 5026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 5036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_ANY]) 5056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.any = 1; 5066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT]) 5076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.disconnect = 1; 5086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT]) 5096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.magic_pkt = 1; 5106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) 5116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.gtk_rekey_failure = 1; 5126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) 5136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.eap_identity_req = 1; 5146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) 5156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.four_way_handshake = 1; 5166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) 5176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->wowlan_triggers.rfkill_release = 1; 5186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 5196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 521d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidtstatic void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv, 522d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt struct nlattr *tb) 523d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt{ 524d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt int rem = 0, i; 525d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr; 526d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 527d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX) 528d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt return; 529d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 530d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt nla_for_each_nested(attr, tb, rem) { 531d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt unsigned int len; 532d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt struct drv_nl80211_ext_capa *capa; 533d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 534d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr), 535d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt nla_len(attr), NULL); 536d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 537d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt if (!tb1[NL80211_ATTR_IFTYPE] || 538d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt !tb1[NL80211_ATTR_EXT_CAPA] || 539d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt !tb1[NL80211_ATTR_EXT_CAPA_MASK]) 540d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt continue; 541d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 542d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa = &drv->iface_ext_capa[drv->num_iface_ext_capa]; 543d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]); 544d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wpa_printf(MSG_DEBUG, 545d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt "nl80211: Driver-advertised extended capabilities for interface type %s", 546d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt nl80211_iftype_str(capa->iftype)); 547d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 548d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]); 549d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->ext_capa = os_malloc(len); 550d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt if (!capa->ext_capa) 551d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt goto err; 552d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 553d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]), 554d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt len); 555d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->ext_capa_len = len; 556d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities", 557d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->ext_capa, capa->ext_capa_len); 558d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 559d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]); 560d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->ext_capa_mask = os_malloc(len); 561d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt if (!capa->ext_capa_mask) 562d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt goto err; 563d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 564d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt os_memcpy(capa->ext_capa_mask, 565d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len); 566d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask", 567d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt capa->ext_capa_mask, capa->ext_capa_len); 568d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 569d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->num_iface_ext_capa++; 570d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX) 571d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt break; 572d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt } 573d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 574d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt return; 575d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 576d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidterr: 577d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt /* Cleanup allocated memory on error */ 578d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt for (i = 0; i < NL80211_IFTYPE_MAX; i++) { 579d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt os_free(drv->iface_ext_capa[i].ext_capa); 580d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->iface_ext_capa[i].ext_capa = NULL; 581d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt os_free(drv->iface_ext_capa[i].ext_capa_mask); 582d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->iface_ext_capa[i].ext_capa_mask = NULL; 583d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->iface_ext_capa[i].ext_capa_len = 0; 584d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt } 585d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->num_iface_ext_capa = 0; 586d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt} 587d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 588d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 5896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wiphy_info_handler(struct nl_msg *msg, void *arg) 5906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 5916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb[NL80211_ATTR_MAX + 1]; 5926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 5936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wiphy_info_data *info = arg; 5946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_capa *capa = info->capa; 5956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_nl80211_data *drv = info->drv; 5966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 5976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 5986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 5996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6007d56b75791f317618c9c3ff08a4cfc36c91c9611Dmitry Shmidt if (tb[NL80211_ATTR_WIPHY]) 6017d56b75791f317618c9c3ff08a4cfc36c91c9611Dmitry Shmidt drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); 6027d56b75791f317618c9c3ff08a4cfc36c91c9611Dmitry Shmidt 6036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_WIPHY_NAME]) 6046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_strlcpy(drv->phyname, 6056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]), 6066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sizeof(drv->phyname)); 6076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) 6086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_scan_ssids = 6096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); 6106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) 6126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_sched_scan_ssids = 6136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); 6146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 615d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS] && 616d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL] && 617d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) { 618d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt capa->max_sched_scan_plans = 619d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt nla_get_u32(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]); 620d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 621d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt capa->max_sched_scan_plan_interval = 622d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]); 623d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 624d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt capa->max_sched_scan_plan_iterations = 625d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]); 626d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 627d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 6286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_MAX_MATCH_SETS]) 6296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_match_sets = 6306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); 6316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_MAC_ACL_MAX]) 6336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_acl_mac_addrs = 6346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]); 6356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]); 6376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); 6386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); 6396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]); 6406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) { 6426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " 6436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "off-channel TX"); 6446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; 6456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_ROAM_SUPPORT]) { 6486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming"); 6496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION; 6506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_max_roc(capa, 6536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); 6546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD]) 6566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD; 6576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT], 6596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]); 6606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_DEVICE_AP_SME]) 6626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->device_ap_sme = 1; 6636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]); 665f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]); 6666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_probe_resp_offload(capa, 6676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); 6686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 6696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] && 6706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa == NULL) { 6716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa = 6726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA])); 6736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (drv->extended_capa) { 6746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcpy(drv->extended_capa, 6756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(tb[NL80211_ATTR_EXT_CAPA]), 6766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_len(tb[NL80211_ATTR_EXT_CAPA])); 6776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa_len = 6786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_len(tb[NL80211_ATTR_EXT_CAPA]); 679d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 680d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt "nl80211: Driver-advertised extended capabilities (default)", 681d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->extended_capa, drv->extended_capa_len); 6826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa_mask = 6842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK])); 6856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (drv->extended_capa_mask) { 6866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcpy(drv->extended_capa_mask, 6872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]), 6882f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK])); 689d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 690d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt "nl80211: Driver-advertised extended capabilities mask (default)", 691d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->extended_capa_mask, 692d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt drv->extended_capa_len); 6936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { 6946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(drv->extended_capa); 6956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa = NULL; 6966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->extended_capa_len = 0; 6976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 6996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 700d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]); 701d5ab1b53af720d05586ccc0addabe93459f1f388Dmitry Shmidt 7026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_VENDOR_DATA]) { 7036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl; 7046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem; 7056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) { 7076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl80211_vendor_cmd_info *vinfo; 7086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (nla_len(nl) != sizeof(*vinfo)) { 7096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); 7106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 7116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt vinfo = nla_data(nl); 713dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt if (vinfo->vendor_id == OUI_QCA) { 714dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt switch (vinfo->subcmd) { 715dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_TEST: 716dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt drv->vendor_cmd_test_avail = 1; 717dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt break; 718d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifdef CONFIG_DRIVER_NL80211_QCA 719dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_ROAMING: 720dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt drv->roaming_vendor_cmd_avail = 1; 721dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt break; 722dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: 723dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt drv->dfs_vendor_cmd_avail = 1; 724dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt break; 725dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: 726dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt drv->get_features_vendor_cmd_avail = 1; 727dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt break; 728d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST: 729d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->get_pref_freq_list = 1; 730d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt break; 731d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL: 732d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->set_prob_oper_freq = 1; 733d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt break; 734dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_DO_ACS: 735dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt drv->capa.flags |= 736dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt WPA_DRIVER_FLAGS_ACS_OFFLOAD; 737dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt break; 738e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi case QCA_NL80211_VENDOR_SUBCMD_SETBAND: 739e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi drv->setband_vendor_cmd_avail = 1; 740e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi break; 741d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: 742d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->scan_vendor_cmd_avail = 1; 743d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt break; 7447f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: 7457f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt drv->set_wifi_conf_vendor_cmd_avail = 1; 7467f2c753f60025528366b5f19b8b490a47bf5080bDmitry Shmidt break; 747ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES: 748ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt drv->he_capab_vendor_cmd_avail = 1; 749ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt break; 750d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_DRIVER_NL80211_QCA */ 751dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt } 7526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", 7556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt vinfo->vendor_id, vinfo->subcmd); 7566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_VENDOR_EVENTS]) { 7606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl; 7616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem; 7626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) { 7646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl80211_vendor_cmd_info *vinfo; 7656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (nla_len(nl) != sizeof(*vinfo)) { 7666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); 7676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 7686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt vinfo = nla_data(nl); 7706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u", 7716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt vinfo->vendor_id, vinfo->subcmd); 7726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 7746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wiphy_info_wowlan_triggers(capa, 7766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]); 7776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA]) 7796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt capa->max_stations = 7806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]); 7816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 782d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (tb[NL80211_ATTR_MAX_CSA_COUNTERS]) 783d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt capa->max_csa_counters = 784d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]); 785d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 7866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 7876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 7886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, 7916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wiphy_info_data *info) 7926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 7936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 feat; 7946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 7956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int flags = 0; 7966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 7976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(info, 0, sizeof(*info)); 7986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->capa = &drv->capa; 7996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->drv = drv; 8006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt feat = get_nl80211_protocol_features(drv); 8026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) 8036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags = NLM_F_DUMP; 8046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY); 8056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) { 8066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nlmsg_free(msg); 8076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 8086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info)) 8116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 8126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info->auth_supported) 8146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_SME; 8156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else if (!info->connect_supported) { 8166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_INFO, "nl80211: Driver does not support " 8176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "authentication/association or connect commands"); 8186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->error = 1; 8196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info->p2p_go_supported && info->p2p_client_supported) 8226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; 8236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info->p2p_concurrent) { 8246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " 8256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "interface (driver advertised support)"); 8266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; 8276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; 8286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info->num_multichan_concurrent > 1) { 8306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel " 8316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "concurrent (driver advertised support)"); 8326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.num_multichan_concurrent = 8336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->num_multichan_concurrent; 8346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) 8366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support"); 8376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* default to 5000 since early versions of mac80211 don't set it */ 8396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!drv->capa.max_remain_on_chan) 8406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.max_remain_on_chan = 5000; 8416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.wmm_ac_supported = info->wmm_ac_supported; 8436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.mac_addr_rand_sched_scan_supported = 8456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->mac_addr_rand_sched_scan_supported; 8466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.mac_addr_rand_scan_supported = 8476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt info->mac_addr_rand_scan_supported; 8486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 849d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (info->channel_switch_supported) { 850d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA; 851d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (!drv->capa.max_csa_counters) 852d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->capa.max_csa_counters = 1; 853d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt } 854d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 855d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (!drv->capa.max_sched_scan_plans) { 856d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt drv->capa.max_sched_scan_plans = 1; 857d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt drv->capa.max_sched_scan_plan_interval = UINT32_MAX; 858d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt drv->capa.max_sched_scan_plan_iterations = 0; 859d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 860d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 8616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 8626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 8636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 865d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifdef CONFIG_DRIVER_NL80211_QCA 866d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 8676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int dfs_info_handler(struct nl_msg *msg, void *arg) 8686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 8696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb[NL80211_ATTR_MAX + 1]; 8706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 8716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int *dfs_capability_ptr = arg; 8726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 8746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 8756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_VENDOR_DATA]) { 8776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA]; 8786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; 8796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX, 8816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_vend), nla_len(nl_vend), NULL); 8826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) { 8846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 val; 8856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]); 8866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u", 8876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt val); 8886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *dfs_capability_ptr = val; 8896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 8916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 8936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 8946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 8966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv) 8976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 8986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 8996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int dfs_capability = 0; 9006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 9016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!drv->dfs_vendor_cmd_avail) 9036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || 9066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 9076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 9086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)) { 9096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nlmsg_free(msg); 9106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 9116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 9126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability); 9146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!ret && dfs_capability) 9156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD; 9166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 9176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 9186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 919ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidtstatic int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg) 920ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt{ 921ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct nlattr *tb[NL80211_ATTR_MAX + 1]; 922ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 923ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct he_capabilities *he_capab = arg; 924ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct nlattr *nl_vend; 925ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1]; 926ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt size_t len; 927ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 928ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 929ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 930ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 931ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!tb[NL80211_ATTR_VENDOR_DATA]) 932ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return NL_SKIP; 933ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 934ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nl_vend = tb[NL80211_ATTR_VENDOR_DATA]; 935ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX, 936ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_data(nl_vend), nla_len(nl_vend), NULL); 937ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 938ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) { 939ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt u8 he_supported; 940ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 941ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_supported = nla_get_u8( 942ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]); 943ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u", 944ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_supported); 945ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_capab->he_supported = he_supported; 946ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!he_supported) 947ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return NL_SKIP; 948ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 949ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 950ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) { 951ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]); 952ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 953ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (len > sizeof(he_capab->phy_cap)) 954ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len = sizeof(he_capab->phy_cap); 955ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt os_memcpy(he_capab->phy_cap, 956ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]), 957ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len); 958ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 959ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 960ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]) 961ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_capab->mac_cap = 962ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]); 963ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 964ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]) 965ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_capab->mcs = 966ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]); 967ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 968ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]) 969ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_capab->ppet.numss_m1 = 970ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]); 971ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 972ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]) 973ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt he_capab->ppet.ru_count = 974ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]); 975ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 976ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) { 977ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]); 978ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 979ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0)) 980ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0); 981ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0, 982ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]), 983ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt len); 984ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 985ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 986ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return NL_SKIP; 987ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt} 988ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 989ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 990ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidtstatic void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv) 991ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt{ 992ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt struct nl_msg *msg; 993ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt int ret; 994ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 995ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!drv->he_capab_vendor_cmd_avail) 996ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return; 997ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 998ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || 999ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 1000ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 1001ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES)) { 1002ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt nlmsg_free(msg); 1003ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt return; 1004ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt } 1005ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 1006ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler, 1007ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt &drv->he_capab); 1008ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (!ret && drv->he_capab.he_supported) 1009ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES; 1010ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt} 1011ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 1012ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt 10136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct features_info { 10146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 *flags; 10156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt size_t flags_len; 1016d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt struct wpa_driver_capa *capa; 10176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 10186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int features_info_handler(struct nl_msg *msg, void *arg) 10216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 10226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb[NL80211_ATTR_MAX + 1]; 10236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 10246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct features_info *info = arg; 10256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_vend, *attr; 10266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 10286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 10296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl_vend = tb[NL80211_ATTR_VENDOR_DATA]; 10316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (nl_vend) { 10326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; 10336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX, 10356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_vend), nla_len(nl_vend), NULL); 10366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS]; 10386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (attr) { 1039748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart int len = nla_len(attr); 1040748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart info->flags = os_malloc(len); 1041748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart if (info->flags != NULL) { 1042748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart os_memcpy(info->flags, nla_data(attr), len); 1043748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart info->flags_len = len; 1044748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart } 10456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 1046d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA]; 1047d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (attr) 1048d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt info->capa->conc_capab = nla_get_u32(attr); 1049d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 1050d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt attr = tb_vendor[ 1051d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND]; 1052d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (attr) 1053d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt info->capa->max_conc_chan_2_4 = nla_get_u32(attr); 1054d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 1055d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt attr = tb_vendor[ 1056d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND]; 1057d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (attr) 1058d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt info->capa->max_conc_chan_5_0 = nla_get_u32(attr); 10596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 10606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 10626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 10636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int check_feature(enum qca_wlan_vendor_features feature, 10666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct features_info *info) 10676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 10686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt size_t idx = feature / 8; 10696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return (idx < info->flags_len) && 10716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (info->flags[idx] & BIT(feature % 8)); 10726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 10736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv) 10766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 10776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 10786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct features_info info; 10796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 10806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!drv->get_features_vendor_cmd_avail) 10826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 10836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || 10856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || 10866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, 10876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) { 10886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nlmsg_free(msg); 10896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 10906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 10916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(&info, 0, sizeof(info)); 1093d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt info.capa = &drv->capa; 10946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = send_and_recv_msgs(drv, msg, features_info_handler, &info); 10956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ret || !info.flags) 10966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 10976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 10986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info)) 10996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD; 1100b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt 1101b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info)) 1102b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY; 1103d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 1104d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS, 1105d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt &info)) 1106d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS; 110758d12adcdf693a076f719cef9b9f2ccf81892045Dmitry Shmidt if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info)) 110858d12adcdf693a076f719cef9b9f2ccf81892045Dmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD; 1109748cf248afe1d09a4c6973615343fd1192084ea3Paul Stewart os_free(info.flags); 11106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 11116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1112d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_DRIVER_NL80211_QCA */ 1113d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 11146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) 11166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 11176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wiphy_info_data info; 11186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (wpa_driver_nl80211_get_info(drv, &info)) 11196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 11206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info.error) 11226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 11236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->has_capability = 1; 11256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | 11266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 11276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1128807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | 1129807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B | 1130807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192; 11316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.auth = WPA_DRIVER_AUTH_OPEN | 11326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_DRIVER_AUTH_SHARED | 11336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt WPA_DRIVER_AUTH_LEAP; 11346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; 11366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; 11376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; 11386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 11406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * As all cfg80211 drivers must support cases where the AP interface is 11416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * removed without the knowledge of wpa_supplicant/hostapd, e.g., in 11426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * case that the user space daemon has crashed, they must be able to 11436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * cleanup all stations and key entries in the AP tear down flow. Thus, 11446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * this flag can/should always be set for cfg80211 drivers. 11456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 11466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT; 11476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!info.device_ap_sme) { 11496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS; 11506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 11526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * No AP SME is currently assumed to also indicate no AP MLME 11536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * in the driver/firmware. 11546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 11556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME; 11566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 11576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->device_ap_sme = info.device_ap_sme; 11596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->poll_command_supported = info.poll_command_supported; 11606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->data_tx_status = info.data_tx_status; 11617f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt drv->p2p_go_ctwindow_supported = info.p2p_go_ctwindow_supported; 11626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (info.set_qos_map_supported) 11636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; 11646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->have_low_prio_scan = info.have_low_prio_scan; 11656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 11676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * If poll command and tx status are supported, mac80211 is new enough 11686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * to have everything we need to not need monitor interfaces. 11696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 1170aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt drv->use_monitor = !info.device_ap_sme && 1171aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt (!info.poll_command_supported || !info.data_tx_status); 11726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 11736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 11746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * If we aren't going to use monitor interfaces, but the 11756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * driver doesn't support data TX status, we won't get TX 11766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * status for EAPOL frames. 11776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 11786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!drv->use_monitor && !info.data_tx_status) 11796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; 11806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1181d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifdef CONFIG_DRIVER_NL80211_QCA 11826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt qca_nl80211_check_dfs_capa(drv); 11836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt qca_nl80211_get_features(drv); 1184ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt qca_nl80211_check_he_capab(drv); 11856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1186d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt /* 1187d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * To enable offchannel simultaneous support in wpa_supplicant, the 1188d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * underlying driver needs to support the same along with offchannel TX. 1189d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * Offchannel TX support is needed since remain_on_channel and 1190d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * action_tx use some common data structures and hence cannot be 1191d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt * scheduled simultaneously. 1192d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt */ 1193d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) 1194d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS; 1195d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_DRIVER_NL80211_QCA */ 1196d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt 11976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return 0; 11986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 11996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct phy_info_arg { 12026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 *num_modes; 12036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_hw_modes *modes; 12046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int last_mode, last_chan_idx; 1205d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt int failed; 12066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}; 12076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa, 12096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *ampdu_factor, 12106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *ampdu_density, 12116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *mcs_set) 12126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 12136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (capa) 12146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->ht_capab = nla_get_u16(capa); 12156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampdu_factor) 12176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03; 12186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ampdu_density) 12206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2; 12216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mcs_set && nla_len(mcs_set) >= 16) { 12236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 *mcs; 12246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mcs = nla_data(mcs_set); 12256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcpy(mode->mcs_set, mcs, 16); 12266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 12276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 12286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void phy_info_vht_capa(struct hostapd_hw_modes *mode, 12316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *capa, 12326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *mcs_set) 12336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 12346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (capa) 12356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->vht_capab = nla_get_u32(capa); 12366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mcs_set && nla_len(mcs_set) >= 8) { 12386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 *mcs; 12396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mcs = nla_data(mcs_set); 12406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcpy(mode->vht_mcs_set, mcs, 8); 12416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 12426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 12436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void phy_info_freq(struct hostapd_hw_modes *mode, 12466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *chan, 12476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_freq[]) 12486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 12496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u8 channel; 12506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); 12516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag = 0; 12526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->dfs_cac_ms = 0; 12536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES) 12546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->chan = channel; 12556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) 12576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_DISABLED; 12586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) 12596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_NO_IR; 12606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) 12616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_RADAR; 12626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY]) 12636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY; 12646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT]) 12656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT; 12666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { 12686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum nl80211_dfs_state state = 12696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); 12706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (state) { 12726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_USABLE: 12736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_DFS_USABLE; 12746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 12756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_AVAILABLE: 12766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE; 12776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 12786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_UNAVAILABLE: 12796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE; 12806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 12816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 12826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 12836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) { 12856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->dfs_cac_ms = nla_get_u32( 12866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]); 12876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 12886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 12896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 12916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int phy_info_freqs(struct phy_info_arg *phy_info, 12926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_hw_modes *mode, struct nlattr *tb) 12936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 12946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { 12956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, 12966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, 12976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, 12986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, 12996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, 13006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 }, 13016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }; 13026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int new_channels = 0; 13036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *channel; 13046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; 13056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_freq; 13066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem_freq, idx; 13076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 13096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_OK; 13106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_freq, tb, rem_freq) { 13126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, 13136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_freq), nla_len(nl_freq), freq_policy); 13146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) 13156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 13166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt new_channels++; 13176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 13186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt channel = os_realloc_array(mode->channels, 13206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_channels + new_channels, 13216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sizeof(struct hostapd_channel_data)); 13226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!channel) 1323d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt return NL_STOP; 13246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->channels = channel; 13266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_channels += new_channels; 13276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt idx = phy_info->last_chan_idx; 13296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_freq, tb, rem_freq) { 13316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, 13326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_freq), nla_len(nl_freq), freq_policy); 13336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) 13346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 13356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info_freq(mode, &mode->channels[idx], tb_freq); 13366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt idx++; 13376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 13386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info->last_chan_idx = idx; 13396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_OK; 13416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 13426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) 13456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 13466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { 13476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, 13486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = 13496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { .type = NLA_FLAG }, 13506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }; 13516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; 13526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_rate; 13536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem_rate, idx; 13546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb == NULL) 13566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_OK; 13576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_rate, tb, rem_rate) { 13596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, 13606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_rate), nla_len(nl_rate), 13616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt rate_policy); 13626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) 13636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 13646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_rates++; 13656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 13666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->rates = os_calloc(mode->num_rates, sizeof(int)); 13686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!mode->rates) 1369d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt return NL_STOP; 13706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt idx = 0; 13726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_rate, tb, rem_rate) { 13746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, 13756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_rate), nla_len(nl_rate), 13766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt rate_policy); 13776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) 13786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 13796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->rates[idx] = nla_get_u32( 13806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_rate[NL80211_BITRATE_ATTR_RATE]); 13816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt idx++; 13826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 13836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_OK; 13856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 13866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) 13896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 13906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; 13916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_hw_modes *mode; 13926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int ret; 13936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 13946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (phy_info->last_mode != nl_band->nla_type) { 13956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode = os_realloc_array(phy_info->modes, 13966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *phy_info->num_modes + 1, 13976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sizeof(*mode)); 1398d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (!mode) { 1399d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt phy_info->failed = 1; 1400d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt return NL_STOP; 1401d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 14026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info->modes = mode; 14036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode = &phy_info->modes[*(phy_info->num_modes)]; 14056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(mode, 0, sizeof(*mode)); 14066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->mode = NUM_HOSTAPD_MODES; 14076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN | 14086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN; 14096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* 14116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Unsupported VHT MCS stream is defined as value 3, so the VHT 14126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * MCS RX/TX map must be initialized with 0xffff to mark all 8 14136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * possible streams as unsupported. This will be overridden if 14146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * driver advertises VHT support. 14156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */ 14166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->vht_mcs_set[0] = 0xff; 14176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->vht_mcs_set[1] = 0xff; 14186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->vht_mcs_set[4] = 0xff; 14196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->vht_mcs_set[5] = 0xff; 14206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *(phy_info->num_modes) += 1; 14226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info->last_mode = nl_band->nla_type; 14236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info->last_chan_idx = 0; 14246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else 14256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode = &phy_info->modes[*(phy_info->num_modes) - 1]; 14266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), 14286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_len(nl_band), NULL); 14296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA], 14316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR], 14326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY], 14336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); 14346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA], 14356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]); 14366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]); 1437d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (ret == NL_OK) 1438d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]); 1439d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (ret != NL_OK) { 1440d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt phy_info->failed = 1; 14416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return ret; 1442d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 14436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_OK; 14456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 14466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int phy_info_handler(struct nl_msg *msg, void *arg) 14496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 14506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; 14516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 14526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *phy_info = arg; 14536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_band; 14546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem_band; 14556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 14576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 14586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) 14606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 14616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) 14636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 14646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int res = phy_info_band(phy_info, nl_band); 14656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (res != NL_OK) 14666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return res; 14676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 14686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 14706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 14716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct hostapd_hw_modes * 14746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtwpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, 14756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 *num_modes) 14766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 14776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 m; 14786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; 14796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int i, mode11g_idx = -1; 14806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* heuristic to set up modes */ 14826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *num_modes; m++) { 14836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!modes[m].num_channels) 14846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 14856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (modes[m].channels[0].freq < 4000) { 14866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt modes[m].mode = HOSTAPD_MODE_IEEE80211B; 14876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (i = 0; i < modes[m].num_rates; i++) { 14886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (modes[m].rates[i] > 200) { 14896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt modes[m].mode = HOSTAPD_MODE_IEEE80211G; 14906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 14916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 14926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 14936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else if (modes[m].channels[0].freq > 50000) 14946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt modes[m].mode = HOSTAPD_MODE_IEEE80211AD; 14956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt else 14966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt modes[m].mode = HOSTAPD_MODE_IEEE80211A; 14976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 14986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 14996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* If only 802.11g mode is included, use it to construct matching 15006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * 802.11b mode data. */ 15016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *num_modes; m++) { 15036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) 15046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* 802.11b already included */ 15056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) 15066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode11g_idx = m; 15076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode11g_idx < 0) 15106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* 2.4 GHz band not supported at all */ 15116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes)); 15136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (nmodes == NULL) 15146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* Could not add 802.11b mode */ 15156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode = &nmodes[*num_modes]; 15176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memset(mode, 0, sizeof(*mode)); 15186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (*num_modes)++; 15196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt modes = nmodes; 15206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->mode = HOSTAPD_MODE_IEEE80211B; 15226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode11g = &modes[mode11g_idx]; 15246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_channels = mode11g->num_channels; 15256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->channels = os_malloc(mode11g->num_channels * 15266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt sizeof(struct hostapd_channel_data)); 15276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode->channels == NULL) { 15286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (*num_modes)--; 15296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* Could not add 802.11b mode */ 15306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_memcpy(mode->channels, mode11g->channels, 15326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode11g->num_channels * sizeof(struct hostapd_channel_data)); 15336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_rates = 0; 15356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->rates = os_malloc(4 * sizeof(int)); 15366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode->rates == NULL) { 15376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(mode->channels); 15386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (*num_modes)--; 15396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* Could not add 802.11b mode */ 15406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (i = 0; i < mode11g->num_rates; i++) { 15436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && 15446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode11g->rates[i] != 55 && mode11g->rates[i] != 110) 15456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 15466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->rates[mode->num_rates] = mode11g->rates[i]; 15476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt mode->num_rates++; 15486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode->num_rates == 4) 15496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt break; 15506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (mode->num_rates == 0) { 15536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(mode->channels); 15546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt os_free(mode->rates); 15556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (*num_modes)--; 15566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; /* No 802.11b rates */ 15576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g " 15606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "information"); 15616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return modes; 15636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 15646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start, 15676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int end) 15686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 15696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int c; 15706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (c = 0; c < mode->num_channels; c++) { 15726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[c]; 15736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 10 >= start && chan->freq + 10 <= end) 15746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_HT40; 15756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 15776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, 15806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int end) 15816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 15826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int c; 15836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (c = 0; c < mode->num_channels; c++) { 15856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[c]; 15866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(chan->flag & HOSTAPD_CHAN_HT40)) 15876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 15886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 30 >= start && chan->freq - 10 <= end) 15896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_HT40MINUS; 15906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq + 10 >= start && chan->freq + 30 <= end) 15916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_HT40PLUS; 15926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 15936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 15946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 15966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp, 15976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results) 15986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 15996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 m; 16006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *results->num_modes; m++) { 16026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int c; 16036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_hw_modes *mode = &results->modes[m]; 16046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (c = 0; c < mode->num_channels; c++) { 16066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[c]; 16076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if ((u32) chan->freq - 10 >= start && 16086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (u32) chan->freq + 10 <= end) 16096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->max_tx_power = max_eirp; 16106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 16116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 16126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 16136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_reg_rule_ht40(u32 start, u32 end, 16166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results) 16176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 16186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 m; 16196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *results->num_modes; m++) { 16216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(results->modes[m].ht_capab & 16226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) 16236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 16246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_set_ht40_mode(&results->modes[m], start, end); 16256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 16266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 16276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_reg_rule_sec(struct nlattr *tb[], 16306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results) 16316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 16326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 start, end, max_bw; 16336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 m; 16346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || 16366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || 16376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) 16386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 16396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; 16416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; 16426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; 16436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (max_bw < 20) 16456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 16466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *results->num_modes; m++) { 16486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(results->modes[m].ht_capab & 16496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) 16506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 16516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_set_ht40_mode_sec(&results->modes[m], start, end); 16526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 16536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 16546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start, 1657d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt int end, int max_bw) 16586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 16596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int c; 16606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (c = 0; c < mode->num_channels; c++) { 16626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct hostapd_channel_data *chan = &mode->channels[c]; 16636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 10 >= start && chan->freq + 70 <= end) 16646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_10_70; 16656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 30 >= start && chan->freq + 50 <= end) 16676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_30_50; 16686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 50 >= start && chan->freq + 30 <= end) 16706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_50_30; 16716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 16726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (chan->freq - 70 >= start && chan->freq + 10 <= end) 16736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_70_10; 1674d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1675d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (max_bw >= 160) { 1676d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 10 >= start && chan->freq + 150 <= end) 1677d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_10_150; 1678d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1679d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 30 >= start && chan->freq + 130 <= end) 1680d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_30_130; 1681d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1682d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 50 >= start && chan->freq + 110 <= end) 1683d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_50_110; 1684d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1685d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 70 >= start && chan->freq + 90 <= end) 1686d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_70_90; 1687d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1688d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 90 >= start && chan->freq + 70 <= end) 1689d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_90_70; 1690d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1691d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 110 >= start && chan->freq + 50 <= end) 1692d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_110_50; 1693d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1694d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 130 >= start && chan->freq + 30 <= end) 1695d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_130_30; 1696d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1697d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (chan->freq - 150 >= start && chan->freq + 10 <= end) 1698d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt chan->flag |= HOSTAPD_CHAN_VHT_150_10; 1699d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 17006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 17016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 17026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_reg_rule_vht(struct nlattr *tb[], 17056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results) 17066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 17076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 start, end, max_bw; 17086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u16 m; 17096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || 17116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || 17126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) 17136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 17146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; 17166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; 17176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; 17186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (max_bw < 80) 17206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return; 17216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt for (m = 0; m < *results->num_modes; m++) { 17236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(results->modes[m].ht_capab & 17246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) 17256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 17266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt /* TODO: use a real VHT support indication */ 17276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!results->modes[m].vht_capab) 17286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 17296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 1730d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt nl80211_set_vht_mode(&results->modes[m], start, end, max_bw); 17316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 17326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 17336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * dfs_domain_name(enum nl80211_dfs_regions region) 17366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 17376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt switch (region) { 17386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_UNSET: 17396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return "DFS-UNSET"; 17406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_FCC: 17416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return "DFS-FCC"; 17426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_ETSI: 17436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return "DFS-ETSI"; 17446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt case NL80211_DFS_JP: 17456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return "DFS-JP"; 17466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt default: 17476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return "DFS-invalid"; 17486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 17496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 17506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_get_reg(struct nl_msg *msg, void *arg) 17536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 17546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results = arg; 17556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; 17566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 17576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *nl_rule; 17586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; 17596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int rem_rule; 17606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { 17616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, 17626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, 17636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, 17646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, 17656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, 17666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, 17676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }; 17686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 17706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 17716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || 17726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt !tb_msg[NL80211_ATTR_REG_RULES]) { 17736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: No regulatory information " 17746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "available"); 17756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 17766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 17776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_msg[NL80211_ATTR_DFS_REGION]) { 17796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt enum nl80211_dfs_regions dfs_domain; 17806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]); 17816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)", 17826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 17836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt dfs_domain_name(dfs_domain)); 17846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } else { 17856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s", 17866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); 17876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 17886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 17896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) 17906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 17916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 start, end, max_eirp = 0, max_bw = 0, flags = 0; 17926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, 17936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_rule), nla_len(nl_rule), reg_policy); 17946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL || 17956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL) 17966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt continue; 17976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000; 17986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000; 17996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) 18006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100; 18016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) 18026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; 18036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS]) 18046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]); 18056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s", 18076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt start, end, max_bw, max_eirp, 18086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "", 18096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "", 18106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "", 18116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" : 18126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt "", 18136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_DFS ? " (DFS)" : "", 18146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "", 18156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "", 18166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt flags & NL80211_RRF_NO_IR ? " (no IR)" : ""); 18176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (max_bw >= 40) 18186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_reg_rule_ht40(start, end, results); 18196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) 18206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_reg_rule_max_eirp(start, end, max_eirp, 18216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt results); 18226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 18236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) 18256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 18266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, 18276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_rule), nla_len(nl_rule), reg_policy); 18286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_reg_rule_sec(tb_rule, results); 18296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 18306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) 18326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt { 18336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, 18346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_data(nl_rule), nla_len(nl_rule), reg_policy); 18356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_reg_rule_vht(tb_rule, results); 18366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 18376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NL_SKIP; 18396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 18406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv, 18436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg *results) 18446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 18456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 18466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt msg = nlmsg_alloc(); 18486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!msg) 18496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -ENOMEM; 18506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); 18526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); 18536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 18546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct hostapd_hw_modes * 18576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) 18586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{ 18596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt u32 feat; 18606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct i802_bss *bss = priv; 18616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 18626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt int nl_flags = 0; 18636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct nl_msg *msg; 18646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt struct phy_info_arg result = { 18656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .num_modes = num_modes, 18666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .modes = NULL, 18676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt .last_mode = -1, 1868d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt .failed = 0, 18696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt }; 18706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *num_modes = 0; 18726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *flags = 0; 18736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt feat = get_nl80211_protocol_features(drv); 18756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP) 18766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl_flags = NLM_F_DUMP; 18776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) || 18786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) { 18796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nlmsg_free(msg); 18806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NULL; 18816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 18826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 18836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) { 18846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt nl80211_set_regulatory_flags(drv, &result); 1885d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt if (result.failed) { 1886d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt int i; 1887d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt 1888d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt for (i = 0; result.modes && i < *num_modes; i++) { 1889d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt os_free(result.modes[i].channels); 1890d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt os_free(result.modes[i].rates); 1891d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 1892d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt os_free(result.modes); 1893293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt *num_modes = 0; 1894d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt return NULL; 1895d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt } 18966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return wpa_driver_nl80211_postprocess_modes(result.modes, 18976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt num_modes); 18986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt } 18996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt 19006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return NULL; 19016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt} 1902