LCOV - code coverage report
Current view: top level - src/drivers - driver_nl80211_capa.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 664 812 81.8 %
Date: 2016-10-02 Functions: 37 38 97.4 %

          Line data    Source code
       1             : /*
       2             :  * Driver interaction with Linux nl80211/cfg80211 - Capabilities
       3             :  * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
       4             :  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
       5             :  * Copyright (c) 2009-2010, Atheros Communications
       6             :  *
       7             :  * This software may be distributed under the terms of the BSD license.
       8             :  * See README for more details.
       9             :  */
      10             : 
      11             : #include "includes.h"
      12             : #include <netlink/genl/genl.h>
      13             : 
      14             : #include "utils/common.h"
      15             : #include "common/ieee802_11_defs.h"
      16             : #include "common/ieee802_11_common.h"
      17             : #include "common/qca-vendor.h"
      18             : #include "common/qca-vendor-attr.h"
      19             : #include "driver_nl80211.h"
      20             : 
      21             : 
      22       20627 : static int protocol_feature_handler(struct nl_msg *msg, void *arg)
      23             : {
      24       20627 :         u32 *feat = arg;
      25             :         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
      26       20627 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
      27             : 
      28       20627 :         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
      29             :                   genlmsg_attrlen(gnlh, 0), NULL);
      30             : 
      31       20627 :         if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
      32       20627 :                 *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
      33             : 
      34       20627 :         return NL_SKIP;
      35             : }
      36             : 
      37             : 
      38       20627 : static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
      39             : {
      40       20627 :         u32 feat = 0;
      41             :         struct nl_msg *msg;
      42             : 
      43       20627 :         msg = nlmsg_alloc();
      44       20627 :         if (!msg)
      45           0 :                 return 0;
      46             : 
      47       20627 :         if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) {
      48           0 :                 nlmsg_free(msg);
      49           0 :                 return 0;
      50             :         }
      51             : 
      52       20627 :         if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
      53       20627 :                 return feat;
      54             : 
      55           0 :         return 0;
      56             : }
      57             : 
      58             : 
      59             : struct wiphy_info_data {
      60             :         struct wpa_driver_nl80211_data *drv;
      61             :         struct wpa_driver_capa *capa;
      62             : 
      63             :         unsigned int num_multichan_concurrent;
      64             : 
      65             :         unsigned int error:1;
      66             :         unsigned int device_ap_sme:1;
      67             :         unsigned int poll_command_supported:1;
      68             :         unsigned int data_tx_status:1;
      69             :         unsigned int auth_supported:1;
      70             :         unsigned int connect_supported:1;
      71             :         unsigned int p2p_go_supported:1;
      72             :         unsigned int p2p_client_supported:1;
      73             :         unsigned int p2p_go_ctwindow_supported:1;
      74             :         unsigned int p2p_concurrent:1;
      75             :         unsigned int channel_switch_supported:1;
      76             :         unsigned int set_qos_map_supported:1;
      77             :         unsigned int have_low_prio_scan:1;
      78             :         unsigned int wmm_ac_supported:1;
      79             :         unsigned int mac_addr_rand_scan_supported:1;
      80             :         unsigned int mac_addr_rand_sched_scan_supported:1;
      81             : };
      82             : 
      83             : 
      84           0 : static unsigned int probe_resp_offload_support(int supp_protocols)
      85             : {
      86           0 :         unsigned int prot = 0;
      87             : 
      88           0 :         if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
      89           0 :                 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
      90           0 :         if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
      91           0 :                 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
      92           0 :         if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
      93           0 :                 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
      94           0 :         if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
      95           0 :                 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
      96             : 
      97           0 :         return prot;
      98             : }
      99             : 
     100             : 
     101      145970 : static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
     102             :                                          struct nlattr *tb)
     103             : {
     104             :         struct nlattr *nl_mode;
     105             :         int i;
     106             : 
     107      145970 :         if (tb == NULL)
     108      289286 :                 return;
     109             : 
     110       23960 :         nla_for_each_nested(nl_mode, tb, i) {
     111       21306 :                 switch (nla_type(nl_mode)) {
     112             :                 case NL80211_IFTYPE_AP:
     113        2654 :                         info->capa->flags |= WPA_DRIVER_FLAGS_AP;
     114        2654 :                         break;
     115             :                 case NL80211_IFTYPE_MESH_POINT:
     116        2654 :                         info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
     117        2654 :                         break;
     118             :                 case NL80211_IFTYPE_ADHOC:
     119        2654 :                         info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
     120        2654 :                         break;
     121             :                 case NL80211_IFTYPE_P2P_DEVICE:
     122          74 :                         info->capa->flags |=
     123             :                                 WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
     124          74 :                         break;
     125             :                 case NL80211_IFTYPE_P2P_GO:
     126        2654 :                         info->p2p_go_supported = 1;
     127        2654 :                         break;
     128             :                 case NL80211_IFTYPE_P2P_CLIENT:
     129        2654 :                         info->p2p_client_supported = 1;
     130        2654 :                         break;
     131             :                 }
     132             :         }
     133             : }
     134             : 
     135             : 
     136        2654 : static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
     137             :                                          struct nlattr *nl_combi)
     138             : {
     139             :         struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
     140             :         struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
     141             :         struct nlattr *nl_limit, *nl_mode;
     142             :         int err, rem_limit, rem_mode;
     143        2654 :         int combination_has_p2p = 0, combination_has_mgd = 0;
     144             :         static struct nla_policy
     145             :         iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
     146             :                 [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
     147             :                 [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
     148             :                 [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
     149             :                 [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
     150             :                 [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
     151             :         },
     152             :         iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
     153             :                 [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
     154             :                 [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
     155             :         };
     156             : 
     157        2654 :         err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
     158             :                                nl_combi, iface_combination_policy);
     159        5308 :         if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
     160        5308 :             !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
     161        2654 :             !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
     162           0 :                 return 0; /* broken combination */
     163             : 
     164        2654 :         if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
     165        2654 :                 info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
     166             : 
     167        5308 :         nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
     168             :                             rem_limit) {
     169        5308 :                 err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
     170             :                                        nl_limit, iface_limit_policy);
     171        5308 :                 if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
     172           0 :                         return 0; /* broken combination */
     173             : 
     174       21232 :                 nla_for_each_nested(nl_mode,
     175             :                                     tb_limit[NL80211_IFACE_LIMIT_TYPES],
     176             :                                     rem_mode) {
     177       15924 :                         int ift = nla_type(nl_mode);
     178       15924 :                         if (ift == NL80211_IFTYPE_P2P_GO ||
     179             :                             ift == NL80211_IFTYPE_P2P_CLIENT)
     180        5308 :                                 combination_has_p2p = 1;
     181       15924 :                         if (ift == NL80211_IFTYPE_STATION)
     182        2654 :                                 combination_has_mgd = 1;
     183             :                 }
     184        5308 :                 if (combination_has_p2p && combination_has_mgd)
     185        2654 :                         break;
     186             :         }
     187             : 
     188        2654 :         if (combination_has_p2p && combination_has_mgd) {
     189        2654 :                 unsigned int num_channels =
     190        2654 :                         nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
     191             : 
     192        2654 :                 info->p2p_concurrent = 1;
     193        2654 :                 if (info->num_multichan_concurrent < num_channels)
     194        2654 :                         info->num_multichan_concurrent = num_channels;
     195             :         }
     196             : 
     197        2654 :         return 0;
     198             : }
     199             : 
     200             : 
     201      145970 : static void wiphy_info_iface_comb(struct wiphy_info_data *info,
     202             :                                   struct nlattr *tb)
     203             : {
     204             :         struct nlattr *nl_combi;
     205             :         int rem_combi;
     206             : 
     207      145970 :         if (tb == NULL)
     208      289286 :                 return;
     209             : 
     210        5308 :         nla_for_each_nested(nl_combi, tb, rem_combi) {
     211        2654 :                 if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
     212           0 :                         break;
     213             :         }
     214             : }
     215             : 
     216             : 
     217      145970 : static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
     218             :                                  struct nlattr *tb)
     219             : {
     220             :         struct nlattr *nl_cmd;
     221             :         int i;
     222             : 
     223      145970 :         if (tb == NULL)
     224      289286 :                 return;
     225             : 
     226       87582 :         nla_for_each_nested(nl_cmd, tb, i) {
     227       84928 :                 switch (nla_get_u32(nl_cmd)) {
     228             :                 case NL80211_CMD_AUTHENTICATE:
     229        2654 :                         info->auth_supported = 1;
     230        2654 :                         break;
     231             :                 case NL80211_CMD_CONNECT:
     232        2654 :                         info->connect_supported = 1;
     233        2654 :                         break;
     234             :                 case NL80211_CMD_START_SCHED_SCAN:
     235           0 :                         info->capa->sched_scan_supported = 1;
     236           0 :                         break;
     237             :                 case NL80211_CMD_PROBE_CLIENT:
     238        2654 :                         info->poll_command_supported = 1;
     239        2654 :                         break;
     240             :                 case NL80211_CMD_CHANNEL_SWITCH:
     241        2654 :                         info->channel_switch_supported = 1;
     242        2654 :                         break;
     243             :                 case NL80211_CMD_SET_QOS_MAP:
     244        2654 :                         info->set_qos_map_supported = 1;
     245        2654 :                         break;
     246             :                 }
     247             :         }
     248             : }
     249             : 
     250             : 
     251      145970 : static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
     252             :                                      struct nlattr *tb)
     253             : {
     254             :         int i, num;
     255             :         u32 *ciphers;
     256             : 
     257      145970 :         if (tb == NULL)
     258      289286 :                 return;
     259             : 
     260        2654 :         num = nla_len(tb) / sizeof(u32);
     261        2654 :         ciphers = nla_data(tb);
     262       31848 :         for (i = 0; i < num; i++) {
     263       29194 :                 u32 c = ciphers[i];
     264             : 
     265       87582 :                 wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
     266       29194 :                            c >> 24, (c >> 16) & 0xff,
     267       29194 :                            (c >> 8) & 0xff, c & 0xff);
     268       29194 :                 switch (c) {
     269             :                 case WLAN_CIPHER_SUITE_CCMP_256:
     270        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
     271        2654 :                         break;
     272             :                 case WLAN_CIPHER_SUITE_GCMP_256:
     273        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
     274        2654 :                         break;
     275             :                 case WLAN_CIPHER_SUITE_CCMP:
     276        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
     277        2654 :                         break;
     278             :                 case WLAN_CIPHER_SUITE_GCMP:
     279        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
     280        2654 :                         break;
     281             :                 case WLAN_CIPHER_SUITE_TKIP:
     282        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
     283        2654 :                         break;
     284             :                 case WLAN_CIPHER_SUITE_WEP104:
     285        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
     286        2654 :                         break;
     287             :                 case WLAN_CIPHER_SUITE_WEP40:
     288        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
     289        2654 :                         break;
     290             :                 case WLAN_CIPHER_SUITE_AES_CMAC:
     291        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
     292        2654 :                         break;
     293             :                 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
     294        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
     295        2654 :                         break;
     296             :                 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
     297        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
     298        2654 :                         break;
     299             :                 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
     300        2654 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
     301        2654 :                         break;
     302             :                 case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
     303           0 :                         info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
     304           0 :                         break;
     305             :                 }
     306             :         }
     307             : }
     308             : 
     309             : 
     310      145970 : static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
     311             :                                struct nlattr *tb)
     312             : {
     313      145970 :         if (tb)
     314        2654 :                 capa->max_remain_on_chan = nla_get_u32(tb);
     315      145970 : }
     316             : 
     317             : 
     318      145970 : static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
     319             :                             struct nlattr *ext_setup)
     320             : {
     321      145970 :         if (tdls == NULL)
     322      289286 :                 return;
     323             : 
     324        2654 :         wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
     325        2654 :         capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
     326             : 
     327        2654 :         if (ext_setup) {
     328        2654 :                 wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
     329        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
     330             :         }
     331             : }
     332             : 
     333             : 
     334        5308 : static int ext_feature_isset(const u8 *ext_features, int ext_features_len,
     335             :                              enum nl80211_ext_feature_index ftidx)
     336             : {
     337             :         u8 ft_byte;
     338             : 
     339        5308 :         if ((int) ftidx / 8 >= ext_features_len)
     340           0 :                 return 0;
     341             : 
     342        5308 :         ft_byte = ext_features[ftidx / 8];
     343        5308 :         return (ft_byte & BIT(ftidx % 8)) != 0;
     344             : }
     345             : 
     346             : 
     347      145970 : static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
     348             :                                          struct nlattr *tb)
     349             : {
     350      145970 :         struct wpa_driver_capa *capa = info->capa;
     351             :         u8 *ext_features;
     352             :         int len;
     353             : 
     354      145970 :         if (tb == NULL)
     355      289286 :                 return;
     356             : 
     357        2654 :         ext_features = nla_data(tb);
     358        2654 :         len = nla_len(tb);
     359             : 
     360        2654 :         if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_VHT_IBSS))
     361        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
     362             : 
     363        2654 :         if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_RRM))
     364        2654 :                 capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM;
     365             : }
     366             : 
     367             : 
     368      145970 : static void wiphy_info_feature_flags(struct wiphy_info_data *info,
     369             :                                      struct nlattr *tb)
     370             : {
     371             :         u32 flags;
     372      145970 :         struct wpa_driver_capa *capa = info->capa;
     373             : 
     374      145970 :         if (tb == NULL)
     375      289286 :                 return;
     376             : 
     377        2654 :         flags = nla_get_u32(tb);
     378             : 
     379        2654 :         if (flags & NL80211_FEATURE_SK_TX_STATUS)
     380        2654 :                 info->data_tx_status = 1;
     381             : 
     382        2654 :         if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
     383           0 :                 capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
     384             : 
     385        2654 :         if (flags & NL80211_FEATURE_SAE)
     386        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_SAE;
     387             : 
     388        2654 :         if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
     389           0 :                 capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
     390             : 
     391        2654 :         if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
     392        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
     393             : 
     394        2654 :         if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
     395        2654 :                 wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
     396        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
     397             :         }
     398             : 
     399        2654 :         if (flags & NL80211_FEATURE_P2P_GO_CTWIN)
     400           0 :                 info->p2p_go_ctwindow_supported = 1;
     401             : 
     402        2654 :         if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
     403        2624 :                 info->have_low_prio_scan = 1;
     404             : 
     405        2654 :         if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
     406        2654 :                 info->mac_addr_rand_scan_supported = 1;
     407             : 
     408        2654 :         if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
     409           0 :                 info->mac_addr_rand_sched_scan_supported = 1;
     410             : 
     411        2654 :         if (flags & NL80211_FEATURE_STATIC_SMPS)
     412        2654 :                 capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
     413             : 
     414        2654 :         if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
     415        2654 :                 capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
     416             : 
     417        2654 :         if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
     418           0 :                 info->wmm_ac_supported = 1;
     419             : 
     420        2654 :         if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES)
     421        2654 :                 capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES;
     422             : 
     423        2654 :         if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES)
     424           0 :                 capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES;
     425             : 
     426        2654 :         if (flags & NL80211_FEATURE_QUIET)
     427        2654 :                 capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET;
     428             : 
     429        2654 :         if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
     430           0 :                 capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
     431             : 
     432        2654 :         if (flags & NL80211_FEATURE_HT_IBSS)
     433        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
     434             : 
     435        2654 :         if (flags & NL80211_FEATURE_FULL_AP_CLIENT_STATE)
     436        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
     437             : }
     438             : 
     439             : 
     440      145970 : static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
     441             :                                           struct nlattr *tb)
     442             : {
     443             :         u32 protocols;
     444             : 
     445      145970 :         if (tb == NULL)
     446      291940 :                 return;
     447             : 
     448           0 :         protocols = nla_get_u32(tb);
     449           0 :         wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
     450             :                    "mode");
     451           0 :         capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
     452           0 :         capa->probe_resp_offloads = probe_resp_offload_support(protocols);
     453             : }
     454             : 
     455             : 
     456      145970 : static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
     457             :                                        struct nlattr *tb)
     458             : {
     459             :         struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
     460             : 
     461      145970 :         if (tb == NULL)
     462      291940 :                 return;
     463             : 
     464           0 :         if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
     465             :                              tb, NULL))
     466           0 :                 return;
     467             : 
     468           0 :         if (triggers[NL80211_WOWLAN_TRIG_ANY])
     469           0 :                 capa->wowlan_triggers.any = 1;
     470           0 :         if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
     471           0 :                 capa->wowlan_triggers.disconnect = 1;
     472           0 :         if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
     473           0 :                 capa->wowlan_triggers.magic_pkt = 1;
     474           0 :         if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
     475           0 :                 capa->wowlan_triggers.gtk_rekey_failure = 1;
     476           0 :         if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
     477           0 :                 capa->wowlan_triggers.eap_identity_req = 1;
     478           0 :         if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
     479           0 :                 capa->wowlan_triggers.four_way_handshake = 1;
     480           0 :         if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
     481           0 :                 capa->wowlan_triggers.rfkill_release = 1;
     482             : }
     483             : 
     484             : 
     485      145970 : static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
     486             :                                       struct nlattr *tb)
     487             : {
     488      145970 :         int rem = 0, i;
     489             :         struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
     490             : 
     491      145970 :         if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
     492      291940 :                 return;
     493             : 
     494           0 :         nla_for_each_nested(attr, tb, rem) {
     495             :                 unsigned int len;
     496             :                 struct drv_nl80211_ext_capa *capa;
     497             : 
     498           0 :                 nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
     499             :                           nla_len(attr), NULL);
     500             : 
     501           0 :                 if (!tb1[NL80211_ATTR_IFTYPE] ||
     502           0 :                     !tb1[NL80211_ATTR_EXT_CAPA] ||
     503           0 :                     !tb1[NL80211_ATTR_EXT_CAPA_MASK])
     504           0 :                         continue;
     505             : 
     506           0 :                 capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
     507           0 :                 capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
     508           0 :                 wpa_printf(MSG_DEBUG,
     509             :                            "nl80211: Driver-advertised extended capabilities for interface type %s",
     510             :                            nl80211_iftype_str(capa->iftype));
     511             : 
     512           0 :                 len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
     513           0 :                 capa->ext_capa = os_malloc(len);
     514           0 :                 if (!capa->ext_capa)
     515           0 :                         goto err;
     516             : 
     517           0 :                 os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
     518             :                           len);
     519           0 :                 capa->ext_capa_len = len;
     520           0 :                 wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
     521           0 :                             capa->ext_capa, capa->ext_capa_len);
     522             : 
     523           0 :                 len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
     524           0 :                 capa->ext_capa_mask = os_malloc(len);
     525           0 :                 if (!capa->ext_capa_mask)
     526           0 :                         goto err;
     527             : 
     528           0 :                 os_memcpy(capa->ext_capa_mask,
     529             :                           nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len);
     530           0 :                 wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
     531           0 :                             capa->ext_capa_mask, capa->ext_capa_len);
     532             : 
     533           0 :                 drv->num_iface_ext_capa++;
     534           0 :                 if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
     535           0 :                         break;
     536             :         }
     537             : 
     538           0 :         return;
     539             : 
     540             : err:
     541             :         /* Cleanup allocated memory on error */
     542           0 :         for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
     543           0 :                 os_free(drv->iface_ext_capa[i].ext_capa);
     544           0 :                 drv->iface_ext_capa[i].ext_capa = NULL;
     545           0 :                 os_free(drv->iface_ext_capa[i].ext_capa_mask);
     546           0 :                 drv->iface_ext_capa[i].ext_capa_mask = NULL;
     547           0 :                 drv->iface_ext_capa[i].ext_capa_len = 0;
     548             :         }
     549           0 :         drv->num_iface_ext_capa = 0;
     550             : }
     551             : 
     552             : 
     553      145970 : static int wiphy_info_handler(struct nl_msg *msg, void *arg)
     554             : {
     555             :         struct nlattr *tb[NL80211_ATTR_MAX + 1];
     556      145970 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
     557      145970 :         struct wiphy_info_data *info = arg;
     558      145970 :         struct wpa_driver_capa *capa = info->capa;
     559      145970 :         struct wpa_driver_nl80211_data *drv = info->drv;
     560             : 
     561      145970 :         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
     562             :                   genlmsg_attrlen(gnlh, 0), NULL);
     563             : 
     564      145970 :         if (tb[NL80211_ATTR_WIPHY])
     565      145970 :                 drv->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
     566             : 
     567      145970 :         if (tb[NL80211_ATTR_WIPHY_NAME])
     568      145970 :                 os_strlcpy(drv->phyname,
     569      145970 :                            nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
     570             :                            sizeof(drv->phyname));
     571      145970 :         if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
     572        2654 :                 capa->max_scan_ssids =
     573        2654 :                         nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
     574             : 
     575      145970 :         if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
     576        2654 :                 capa->max_sched_scan_ssids =
     577        2654 :                         nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
     578             : 
     579      148624 :         if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS] &&
     580        5308 :             tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL] &&
     581        2654 :             tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) {
     582        2654 :                 capa->max_sched_scan_plans =
     583        2654 :                         nla_get_u32(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]);
     584             : 
     585        2654 :                 capa->max_sched_scan_plan_interval =
     586        2654 :                         nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]);
     587             : 
     588        2654 :                 capa->max_sched_scan_plan_iterations =
     589        2654 :                         nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]);
     590             :         }
     591             : 
     592      145970 :         if (tb[NL80211_ATTR_MAX_MATCH_SETS])
     593        2654 :                 capa->max_match_sets =
     594        2654 :                         nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
     595             : 
     596      145970 :         if (tb[NL80211_ATTR_MAC_ACL_MAX])
     597           0 :                 capa->max_acl_mac_addrs =
     598           0 :                         nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
     599             : 
     600      145970 :         wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
     601      145970 :         wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
     602      145970 :         wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
     603      145970 :         wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
     604             : 
     605      145970 :         if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
     606        2654 :                 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
     607             :                            "off-channel TX");
     608        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
     609             :         }
     610             : 
     611      145970 :         if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
     612           0 :                 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
     613           0 :                 capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
     614             :         }
     615             : 
     616      145970 :         wiphy_info_max_roc(capa,
     617             :                            tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
     618             : 
     619      145970 :         if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
     620        2654 :                 capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
     621             : 
     622      145970 :         wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
     623             :                         tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
     624             : 
     625      145970 :         if (tb[NL80211_ATTR_DEVICE_AP_SME])
     626           0 :                 info->device_ap_sme = 1;
     627             : 
     628      145970 :         wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
     629      145970 :         wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
     630      145970 :         wiphy_info_probe_resp_offload(capa,
     631             :                                       tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
     632             : 
     633      148624 :         if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
     634        2654 :             drv->extended_capa == NULL) {
     635        2654 :                 drv->extended_capa =
     636        2654 :                         os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
     637        2654 :                 if (drv->extended_capa) {
     638        2654 :                         os_memcpy(drv->extended_capa,
     639             :                                   nla_data(tb[NL80211_ATTR_EXT_CAPA]),
     640             :                                   nla_len(tb[NL80211_ATTR_EXT_CAPA]));
     641        2654 :                         drv->extended_capa_len =
     642        2654 :                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]);
     643        5308 :                         wpa_hexdump(MSG_DEBUG,
     644             :                                     "nl80211: Driver-advertised extended capabilities (default)",
     645        5308 :                                     drv->extended_capa, drv->extended_capa_len);
     646             :                 }
     647        2654 :                 drv->extended_capa_mask =
     648        2654 :                         os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
     649        2654 :                 if (drv->extended_capa_mask) {
     650        2654 :                         os_memcpy(drv->extended_capa_mask,
     651             :                                   nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
     652             :                                   nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
     653        5308 :                         wpa_hexdump(MSG_DEBUG,
     654             :                                     "nl80211: Driver-advertised extended capabilities mask (default)",
     655        2654 :                                     drv->extended_capa_mask,
     656        2654 :                                     drv->extended_capa_len);
     657             :                 } else {
     658           0 :                         os_free(drv->extended_capa);
     659           0 :                         drv->extended_capa = NULL;
     660           0 :                         drv->extended_capa_len = 0;
     661             :                 }
     662             :         }
     663             : 
     664      145970 :         wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
     665             : 
     666      145970 :         if (tb[NL80211_ATTR_VENDOR_DATA]) {
     667             :                 struct nlattr *nl;
     668             :                 int rem;
     669             : 
     670        5308 :                 nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
     671             :                         struct nl80211_vendor_cmd_info *vinfo;
     672        2654 :                         if (nla_len(nl) != sizeof(*vinfo)) {
     673           0 :                                 wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
     674           0 :                                 continue;
     675             :                         }
     676        2654 :                         vinfo = nla_data(nl);
     677        2654 :                         if (vinfo->vendor_id == OUI_QCA) {
     678        2654 :                                 switch (vinfo->subcmd) {
     679             :                                 case QCA_NL80211_VENDOR_SUBCMD_TEST:
     680        2654 :                                         drv->vendor_cmd_test_avail = 1;
     681        2654 :                                         break;
     682             : #ifdef CONFIG_DRIVER_NL80211_QCA
     683             :                                 case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
     684             :                                         drv->roaming_vendor_cmd_avail = 1;
     685             :                                         break;
     686             :                                 case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
     687             :                                         drv->dfs_vendor_cmd_avail = 1;
     688             :                                         break;
     689             :                                 case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
     690             :                                         drv->get_features_vendor_cmd_avail = 1;
     691             :                                         break;
     692             :                                 case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST:
     693             :                                         drv->get_pref_freq_list = 1;
     694             :                                         break;
     695             :                                 case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL:
     696             :                                         drv->set_prob_oper_freq = 1;
     697             :                                         break;
     698             :                                 case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
     699             :                                         drv->capa.flags |=
     700             :                                                 WPA_DRIVER_FLAGS_ACS_OFFLOAD;
     701             :                                         break;
     702             :                                 case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
     703             :                                         drv->setband_vendor_cmd_avail = 1;
     704             :                                         break;
     705             :                                 case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
     706             :                                         drv->scan_vendor_cmd_avail = 1;
     707             :                                         break;
     708             :                                 case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
     709             :                                         drv->set_wifi_conf_vendor_cmd_avail = 1;
     710             :                                         break;
     711             : #endif /* CONFIG_DRIVER_NL80211_QCA */
     712             :                                 }
     713             :                         }
     714             : 
     715        2654 :                         wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
     716             :                                    vinfo->vendor_id, vinfo->subcmd);
     717             :                 }
     718             :         }
     719             : 
     720      145970 :         if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
     721             :                 struct nlattr *nl;
     722             :                 int rem;
     723             : 
     724        5308 :                 nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
     725             :                         struct nl80211_vendor_cmd_info *vinfo;
     726        2654 :                         if (nla_len(nl) != sizeof(*vinfo)) {
     727           0 :                                 wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
     728           0 :                                 continue;
     729             :                         }
     730        2654 :                         vinfo = nla_data(nl);
     731        2654 :                         wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
     732             :                                    vinfo->vendor_id, vinfo->subcmd);
     733             :                 }
     734             :         }
     735             : 
     736      145970 :         wiphy_info_wowlan_triggers(capa,
     737             :                                    tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
     738             : 
     739      145970 :         if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
     740           0 :                 capa->max_stations =
     741           0 :                         nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
     742             : 
     743      145970 :         if (tb[NL80211_ATTR_MAX_CSA_COUNTERS])
     744        2654 :                 capa->max_csa_counters =
     745        2654 :                         nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]);
     746             : 
     747      145970 :         return NL_SKIP;
     748             : }
     749             : 
     750             : 
     751        2657 : static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
     752             :                                        struct wiphy_info_data *info)
     753             : {
     754             :         u32 feat;
     755             :         struct nl_msg *msg;
     756        2657 :         int flags = 0;
     757             : 
     758        2657 :         os_memset(info, 0, sizeof(*info));
     759        2657 :         info->capa = &drv->capa;
     760        2657 :         info->drv = drv;
     761             : 
     762        2657 :         feat = get_nl80211_protocol_features(drv);
     763        2657 :         if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
     764        2657 :                 flags = NLM_F_DUMP;
     765        2657 :         msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY);
     766        2657 :         if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
     767           0 :                 nlmsg_free(msg);
     768           0 :                 return -1;
     769             :         }
     770             : 
     771        2657 :         if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
     772           0 :                 return -1;
     773             : 
     774        2657 :         if (info->auth_supported)
     775        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
     776           3 :         else if (!info->connect_supported) {
     777           3 :                 wpa_printf(MSG_INFO, "nl80211: Driver does not support "
     778             :                            "authentication/association or connect commands");
     779           3 :                 info->error = 1;
     780             :         }
     781             : 
     782        2657 :         if (info->p2p_go_supported && info->p2p_client_supported)
     783        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
     784        2657 :         if (info->p2p_concurrent) {
     785        2654 :                 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
     786             :                            "interface (driver advertised support)");
     787        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
     788        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
     789             :         }
     790        2657 :         if (info->num_multichan_concurrent > 1) {
     791          30 :                 wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
     792             :                            "concurrent (driver advertised support)");
     793          30 :                 drv->capa.num_multichan_concurrent =
     794          30 :                         info->num_multichan_concurrent;
     795             :         }
     796        2657 :         if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
     797          74 :                 wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support");
     798             : 
     799             :         /* default to 5000 since early versions of mac80211 don't set it */
     800        2657 :         if (!drv->capa.max_remain_on_chan)
     801           3 :                 drv->capa.max_remain_on_chan = 5000;
     802             : 
     803        2657 :         drv->capa.wmm_ac_supported = info->wmm_ac_supported;
     804             : 
     805        2657 :         drv->capa.mac_addr_rand_sched_scan_supported =
     806        2657 :                 info->mac_addr_rand_sched_scan_supported;
     807        2657 :         drv->capa.mac_addr_rand_scan_supported =
     808        2657 :                 info->mac_addr_rand_scan_supported;
     809             : 
     810        2657 :         if (info->channel_switch_supported) {
     811        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
     812        2654 :                 if (!drv->capa.max_csa_counters)
     813           0 :                         drv->capa.max_csa_counters = 1;
     814             :         }
     815             : 
     816        2657 :         if (!drv->capa.max_sched_scan_plans) {
     817           3 :                 drv->capa.max_sched_scan_plans = 1;
     818           3 :                 drv->capa.max_sched_scan_plan_interval = UINT32_MAX;
     819           3 :                 drv->capa.max_sched_scan_plan_iterations = 0;
     820             :         }
     821             : 
     822        2657 :         return 0;
     823             : }
     824             : 
     825             : 
     826             : #ifdef CONFIG_DRIVER_NL80211_QCA
     827             : 
     828             : static int dfs_info_handler(struct nl_msg *msg, void *arg)
     829             : {
     830             :         struct nlattr *tb[NL80211_ATTR_MAX + 1];
     831             :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
     832             :         int *dfs_capability_ptr = arg;
     833             : 
     834             :         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
     835             :                   genlmsg_attrlen(gnlh, 0), NULL);
     836             : 
     837             :         if (tb[NL80211_ATTR_VENDOR_DATA]) {
     838             :                 struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
     839             :                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
     840             : 
     841             :                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
     842             :                           nla_data(nl_vend), nla_len(nl_vend), NULL);
     843             : 
     844             :                 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
     845             :                         u32 val;
     846             :                         val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
     847             :                         wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
     848             :                                    val);
     849             :                         *dfs_capability_ptr = val;
     850             :                 }
     851             :         }
     852             : 
     853             :         return NL_SKIP;
     854             : }
     855             : 
     856             : 
     857             : static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
     858             : {
     859             :         struct nl_msg *msg;
     860             :         int dfs_capability = 0;
     861             :         int ret;
     862             : 
     863             :         if (!drv->dfs_vendor_cmd_avail)
     864             :                 return;
     865             : 
     866             :         if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
     867             :             nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
     868             :             nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
     869             :                         QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)) {
     870             :                 nlmsg_free(msg);
     871             :                 return;
     872             :         }
     873             : 
     874             :         ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
     875             :         if (!ret && dfs_capability)
     876             :                 drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
     877             : }
     878             : 
     879             : 
     880             : struct features_info {
     881             :         u8 *flags;
     882             :         size_t flags_len;
     883             :         struct wpa_driver_capa *capa;
     884             : };
     885             : 
     886             : 
     887             : static int features_info_handler(struct nl_msg *msg, void *arg)
     888             : {
     889             :         struct nlattr *tb[NL80211_ATTR_MAX + 1];
     890             :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
     891             :         struct features_info *info = arg;
     892             :         struct nlattr *nl_vend, *attr;
     893             : 
     894             :         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
     895             :                   genlmsg_attrlen(gnlh, 0), NULL);
     896             : 
     897             :         nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
     898             :         if (nl_vend) {
     899             :                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
     900             : 
     901             :                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
     902             :                           nla_data(nl_vend), nla_len(nl_vend), NULL);
     903             : 
     904             :                 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
     905             :                 if (attr) {
     906             :                         int len = nla_len(attr);
     907             :                         info->flags = os_malloc(len);
     908             :                         if (info->flags != NULL) {
     909             :                                 os_memcpy(info->flags, nla_data(attr), len);
     910             :                                 info->flags_len = len;
     911             :                         }
     912             :                 }
     913             :                 attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
     914             :                 if (attr)
     915             :                         info->capa->conc_capab = nla_get_u32(attr);
     916             : 
     917             :                 attr = tb_vendor[
     918             :                         QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND];
     919             :                 if (attr)
     920             :                         info->capa->max_conc_chan_2_4 = nla_get_u32(attr);
     921             : 
     922             :                 attr = tb_vendor[
     923             :                         QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND];
     924             :                 if (attr)
     925             :                         info->capa->max_conc_chan_5_0 = nla_get_u32(attr);
     926             :         }
     927             : 
     928             :         return NL_SKIP;
     929             : }
     930             : 
     931             : 
     932             : static int check_feature(enum qca_wlan_vendor_features feature,
     933             :                          struct features_info *info)
     934             : {
     935             :         size_t idx = feature / 8;
     936             : 
     937             :         return (idx < info->flags_len) &&
     938             :                 (info->flags[idx] & BIT(feature % 8));
     939             : }
     940             : 
     941             : 
     942             : static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
     943             : {
     944             :         struct nl_msg *msg;
     945             :         struct features_info info;
     946             :         int ret;
     947             : 
     948             :         if (!drv->get_features_vendor_cmd_avail)
     949             :                 return;
     950             : 
     951             :         if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
     952             :             nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
     953             :             nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
     954             :                         QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) {
     955             :                 nlmsg_free(msg);
     956             :                 return;
     957             :         }
     958             : 
     959             :         os_memset(&info, 0, sizeof(info));
     960             :         info.capa = &drv->capa;
     961             :         ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
     962             :         if (ret || !info.flags)
     963             :                 return;
     964             : 
     965             :         if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
     966             :                 drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
     967             : 
     968             :         if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
     969             :                 drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
     970             : 
     971             :         if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
     972             :                           &info))
     973             :                 drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
     974             :         if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
     975             :                 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
     976             :         os_free(info.flags);
     977             : }
     978             : 
     979             : #endif /* CONFIG_DRIVER_NL80211_QCA */
     980             : 
     981             : 
     982        2657 : int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
     983             : {
     984             :         struct wiphy_info_data info;
     985        2657 :         if (wpa_driver_nl80211_get_info(drv, &info))
     986           0 :                 return -1;
     987             : 
     988        2657 :         if (info.error)
     989           3 :                 return -1;
     990             : 
     991        2654 :         drv->has_capability = 1;
     992        2654 :         drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
     993             :                 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
     994             :                 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
     995             :                 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
     996             :                 WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
     997             :                 WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
     998        2654 :         drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
     999             :                 WPA_DRIVER_AUTH_SHARED |
    1000             :                 WPA_DRIVER_AUTH_LEAP;
    1001             : 
    1002        2654 :         drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
    1003        2654 :         drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
    1004        2654 :         drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
    1005             : 
    1006             :         /*
    1007             :          * As all cfg80211 drivers must support cases where the AP interface is
    1008             :          * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
    1009             :          * case that the user space daemon has crashed, they must be able to
    1010             :          * cleanup all stations and key entries in the AP tear down flow. Thus,
    1011             :          * this flag can/should always be set for cfg80211 drivers.
    1012             :          */
    1013        2654 :         drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
    1014             : 
    1015        2654 :         if (!info.device_ap_sme) {
    1016        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
    1017             : 
    1018             :                 /*
    1019             :                  * No AP SME is currently assumed to also indicate no AP MLME
    1020             :                  * in the driver/firmware.
    1021             :                  */
    1022        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
    1023             :         }
    1024             : 
    1025        2654 :         drv->device_ap_sme = info.device_ap_sme;
    1026        2654 :         drv->poll_command_supported = info.poll_command_supported;
    1027        2654 :         drv->data_tx_status = info.data_tx_status;
    1028        2654 :         drv->p2p_go_ctwindow_supported = info.p2p_go_ctwindow_supported;
    1029        2654 :         if (info.set_qos_map_supported)
    1030        2654 :                 drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
    1031        2654 :         drv->have_low_prio_scan = info.have_low_prio_scan;
    1032             : 
    1033             :         /*
    1034             :          * If poll command and tx status are supported, mac80211 is new enough
    1035             :          * to have everything we need to not need monitor interfaces.
    1036             :          */
    1037        5308 :         drv->use_monitor = !info.device_ap_sme &&
    1038        5308 :                 (!info.poll_command_supported || !info.data_tx_status);
    1039             : 
    1040             :         /*
    1041             :          * If we aren't going to use monitor interfaces, but the
    1042             :          * driver doesn't support data TX status, we won't get TX
    1043             :          * status for EAPOL frames.
    1044             :          */
    1045        2654 :         if (!drv->use_monitor && !info.data_tx_status)
    1046           0 :                 drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
    1047             : 
    1048             : #ifdef CONFIG_DRIVER_NL80211_QCA
    1049             :         qca_nl80211_check_dfs_capa(drv);
    1050             :         qca_nl80211_get_features(drv);
    1051             : 
    1052             :         /*
    1053             :          * To enable offchannel simultaneous support in wpa_supplicant, the
    1054             :          * underlying driver needs to support the same along with offchannel TX.
    1055             :          * Offchannel TX support is needed since remain_on_channel and
    1056             :          * action_tx use some common data structures and hence cannot be
    1057             :          * scheduled simultaneously.
    1058             :          */
    1059             :         if (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
    1060             :                 drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
    1061             : #endif /* CONFIG_DRIVER_NL80211_QCA */
    1062             : 
    1063        2654 :         return 0;
    1064             : }
    1065             : 
    1066             : 
    1067             : struct phy_info_arg {
    1068             :         u16 *num_modes;
    1069             :         struct hostapd_hw_modes *modes;
    1070             :         int last_mode, last_chan_idx;
    1071             :         int failed;
    1072             : };
    1073             : 
    1074      754270 : static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
    1075             :                              struct nlattr *ampdu_factor,
    1076             :                              struct nlattr *ampdu_density,
    1077             :                              struct nlattr *mcs_set)
    1078             : {
    1079      754270 :         if (capa)
    1080       35918 :                 mode->ht_capab = nla_get_u16(capa);
    1081             : 
    1082      754270 :         if (ampdu_factor)
    1083       35918 :                 mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
    1084             : 
    1085      754270 :         if (ampdu_density)
    1086       35918 :                 mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
    1087             : 
    1088      754270 :         if (mcs_set && nla_len(mcs_set) >= 16) {
    1089             :                 u8 *mcs;
    1090       35918 :                 mcs = nla_data(mcs_set);
    1091       35918 :                 os_memcpy(mode->mcs_set, mcs, 16);
    1092             :         }
    1093      754270 : }
    1094             : 
    1095             : 
    1096      754270 : static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
    1097             :                               struct nlattr *capa,
    1098             :                               struct nlattr *mcs_set)
    1099             : {
    1100      754270 :         if (capa)
    1101       17959 :                 mode->vht_capab = nla_get_u32(capa);
    1102             : 
    1103      754270 :         if (mcs_set && nla_len(mcs_set) >= 8) {
    1104             :                 u8 *mcs;
    1105       17959 :                 mcs = nla_data(mcs_set);
    1106       17959 :                 os_memcpy(mode->vht_mcs_set, mcs, 8);
    1107             :         }
    1108      754270 : }
    1109             : 
    1110             : 
    1111      682435 : static void phy_info_freq(struct hostapd_hw_modes *mode,
    1112             :                           struct hostapd_channel_data *chan,
    1113             :                           struct nlattr *tb_freq[])
    1114             : {
    1115             :         u8 channel;
    1116      682435 :         chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
    1117      682435 :         chan->flag = 0;
    1118      682435 :         chan->dfs_cac_ms = 0;
    1119      682435 :         if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
    1120      682435 :                 chan->chan = channel;
    1121             : 
    1122      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
    1123        9126 :                 chan->flag |= HOSTAPD_CHAN_DISABLED;
    1124      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
    1125      426341 :                 chan->flag |= HOSTAPD_CHAN_NO_IR;
    1126      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
    1127      269020 :                 chan->flag |= HOSTAPD_CHAN_RADAR;
    1128      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
    1129         200 :                 chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY;
    1130      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
    1131           0 :                 chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
    1132             : 
    1133      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
    1134      269020 :                 enum nl80211_dfs_state state =
    1135      269020 :                         nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
    1136             : 
    1137      269020 :                 switch (state) {
    1138             :                 case NL80211_DFS_USABLE:
    1139      269020 :                         chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
    1140      269020 :                         break;
    1141             :                 case NL80211_DFS_AVAILABLE:
    1142           0 :                         chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
    1143           0 :                         break;
    1144             :                 case NL80211_DFS_UNAVAILABLE:
    1145           0 :                         chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
    1146           0 :                         break;
    1147             :                 }
    1148             :         }
    1149             : 
    1150      682435 :         if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
    1151      269020 :                 chan->dfs_cac_ms = nla_get_u32(
    1152      269020 :                         tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
    1153             :         }
    1154      682435 : }
    1155             : 
    1156             : 
    1157      754270 : static int phy_info_freqs(struct phy_info_arg *phy_info,
    1158             :                           struct hostapd_hw_modes *mode, struct nlattr *tb)
    1159             : {
    1160             :         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
    1161             :                 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
    1162             :                 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
    1163             :                 [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
    1164             :                 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
    1165             :                 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
    1166             :                 [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
    1167             :         };
    1168      754270 :         int new_channels = 0;
    1169             :         struct hostapd_channel_data *channel;
    1170             :         struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
    1171             :         struct nlattr *nl_freq;
    1172             :         int rem_freq, idx;
    1173             : 
    1174      754270 :         if (tb == NULL)
    1175       35918 :                 return NL_OK;
    1176             : 
    1177     1400787 :         nla_for_each_nested(nl_freq, tb, rem_freq) {
    1178     1364870 :                 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
    1179      682435 :                           nla_data(nl_freq), nla_len(nl_freq), freq_policy);
    1180      682435 :                 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
    1181           0 :                         continue;
    1182      682435 :                 new_channels++;
    1183             :         }
    1184             : 
    1185      718352 :         channel = os_realloc_array(mode->channels,
    1186      718352 :                                    mode->num_channels + new_channels,
    1187             :                                    sizeof(struct hostapd_channel_data));
    1188      718352 :         if (!channel)
    1189           0 :                 return NL_STOP;
    1190             : 
    1191      718352 :         mode->channels = channel;
    1192      718352 :         mode->num_channels += new_channels;
    1193             : 
    1194      718352 :         idx = phy_info->last_chan_idx;
    1195             : 
    1196     1400787 :         nla_for_each_nested(nl_freq, tb, rem_freq) {
    1197     1364870 :                 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
    1198      682435 :                           nla_data(nl_freq), nla_len(nl_freq), freq_policy);
    1199      682435 :                 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
    1200           0 :                         continue;
    1201      682435 :                 phy_info_freq(mode, &mode->channels[idx], tb_freq);
    1202      682435 :                 idx++;
    1203             :         }
    1204      718352 :         phy_info->last_chan_idx = idx;
    1205             : 
    1206      718352 :         return NL_OK;
    1207             : }
    1208             : 
    1209             : 
    1210      754270 : static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
    1211             : {
    1212             :         static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
    1213             :                 [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
    1214             :                 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
    1215             :                 { .type = NLA_FLAG },
    1216             :         };
    1217             :         struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
    1218             :         struct nlattr *nl_rate;
    1219             :         int rem_rate, idx;
    1220             : 
    1221      754270 :         if (tb == NULL)
    1222      718352 :                 return NL_OK;
    1223             : 
    1224      395098 :         nla_for_each_nested(nl_rate, tb, rem_rate) {
    1225      718360 :                 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
    1226      359180 :                           nla_data(nl_rate), nla_len(nl_rate),
    1227             :                           rate_policy);
    1228      359180 :                 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
    1229           0 :                         continue;
    1230      359180 :                 mode->num_rates++;
    1231             :         }
    1232             : 
    1233       35918 :         mode->rates = os_calloc(mode->num_rates, sizeof(int));
    1234       35918 :         if (!mode->rates)
    1235           0 :                 return NL_STOP;
    1236             : 
    1237       35918 :         idx = 0;
    1238             : 
    1239      395098 :         nla_for_each_nested(nl_rate, tb, rem_rate) {
    1240      718360 :                 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
    1241      359180 :                           nla_data(nl_rate), nla_len(nl_rate),
    1242             :                           rate_policy);
    1243      359180 :                 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
    1244           0 :                         continue;
    1245      359180 :                 mode->rates[idx] = nla_get_u32(
    1246             :                         tb_rate[NL80211_BITRATE_ATTR_RATE]);
    1247      359180 :                 idx++;
    1248             :         }
    1249             : 
    1250       35918 :         return NL_OK;
    1251             : }
    1252             : 
    1253             : 
    1254      754270 : static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
    1255             : {
    1256             :         struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
    1257             :         struct hostapd_hw_modes *mode;
    1258             :         int ret;
    1259             : 
    1260      754270 :         if (phy_info->last_mode != nl_band->nla_type) {
    1261       35918 :                 mode = os_realloc_array(phy_info->modes,
    1262       35918 :                                         *phy_info->num_modes + 1,
    1263             :                                         sizeof(*mode));
    1264       35918 :                 if (!mode) {
    1265           0 :                         phy_info->failed = 1;
    1266           0 :                         return NL_STOP;
    1267             :                 }
    1268       35918 :                 phy_info->modes = mode;
    1269             : 
    1270       35918 :                 mode = &phy_info->modes[*(phy_info->num_modes)];
    1271       35918 :                 os_memset(mode, 0, sizeof(*mode));
    1272       35918 :                 mode->mode = NUM_HOSTAPD_MODES;
    1273       35918 :                 mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
    1274             :                         HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
    1275             : 
    1276             :                 /*
    1277             :                  * Unsupported VHT MCS stream is defined as value 3, so the VHT
    1278             :                  * MCS RX/TX map must be initialized with 0xffff to mark all 8
    1279             :                  * possible streams as unsupported. This will be overridden if
    1280             :                  * driver advertises VHT support.
    1281             :                  */
    1282       35918 :                 mode->vht_mcs_set[0] = 0xff;
    1283       35918 :                 mode->vht_mcs_set[1] = 0xff;
    1284       35918 :                 mode->vht_mcs_set[4] = 0xff;
    1285       35918 :                 mode->vht_mcs_set[5] = 0xff;
    1286             : 
    1287       35918 :                 *(phy_info->num_modes) += 1;
    1288       35918 :                 phy_info->last_mode = nl_band->nla_type;
    1289       35918 :                 phy_info->last_chan_idx = 0;
    1290             :         } else
    1291      718352 :                 mode = &phy_info->modes[*(phy_info->num_modes) - 1];
    1292             : 
    1293      754270 :         nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
    1294             :                   nla_len(nl_band), NULL);
    1295             : 
    1296      754270 :         phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
    1297             :                          tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
    1298             :                          tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
    1299             :                          tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
    1300      754270 :         phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
    1301             :                           tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
    1302      754270 :         ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
    1303      754270 :         if (ret == NL_OK)
    1304      754270 :                 ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
    1305      754270 :         if (ret != NL_OK) {
    1306           0 :                 phy_info->failed = 1;
    1307           0 :                 return ret;
    1308             :         }
    1309             : 
    1310      754270 :         return NL_OK;
    1311             : }
    1312             : 
    1313             : 
    1314      987727 : static int phy_info_handler(struct nl_msg *msg, void *arg)
    1315             : {
    1316             :         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
    1317      987727 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    1318      987727 :         struct phy_info_arg *phy_info = arg;
    1319             :         struct nlattr *nl_band;
    1320             :         int rem_band;
    1321             : 
    1322      987727 :         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
    1323             :                   genlmsg_attrlen(gnlh, 0), NULL);
    1324             : 
    1325      987727 :         if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
    1326      215499 :                 return NL_SKIP;
    1327             : 
    1328     1526498 :         nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
    1329             :         {
    1330      754270 :                 int res = phy_info_band(phy_info, nl_band);
    1331      754270 :                 if (res != NL_OK)
    1332           0 :                         return res;
    1333             :         }
    1334             : 
    1335      772228 :         return NL_SKIP;
    1336             : }
    1337             : 
    1338             : 
    1339             : static struct hostapd_hw_modes *
    1340       17970 : wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
    1341             :                                      u16 *num_modes)
    1342             : {
    1343             :         u16 m;
    1344       17970 :         struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
    1345       17970 :         int i, mode11g_idx = -1;
    1346             : 
    1347             :         /* heuristic to set up modes */
    1348       53888 :         for (m = 0; m < *num_modes; m++) {
    1349       35918 :                 if (!modes[m].num_channels)
    1350           0 :                         continue;
    1351       35918 :                 if (modes[m].channels[0].freq < 4000) {
    1352       17959 :                         modes[m].mode = HOSTAPD_MODE_IEEE80211B;
    1353      161631 :                         for (i = 0; i < modes[m].num_rates; i++) {
    1354      161631 :                                 if (modes[m].rates[i] > 200) {
    1355       17959 :                                         modes[m].mode = HOSTAPD_MODE_IEEE80211G;
    1356       17959 :                                         break;
    1357             :                                 }
    1358             :                         }
    1359       17959 :                 } else if (modes[m].channels[0].freq > 50000)
    1360           0 :                         modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
    1361             :                 else
    1362       17959 :                         modes[m].mode = HOSTAPD_MODE_IEEE80211A;
    1363             :         }
    1364             : 
    1365             :         /* If only 802.11g mode is included, use it to construct matching
    1366             :          * 802.11b mode data. */
    1367             : 
    1368       53888 :         for (m = 0; m < *num_modes; m++) {
    1369       35918 :                 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
    1370           0 :                         return modes; /* 802.11b already included */
    1371       35918 :                 if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
    1372       17959 :                         mode11g_idx = m;
    1373             :         }
    1374             : 
    1375       17970 :         if (mode11g_idx < 0)
    1376          11 :                 return modes; /* 2.4 GHz band not supported at all */
    1377             : 
    1378       17959 :         nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
    1379       17959 :         if (nmodes == NULL)
    1380           1 :                 return modes; /* Could not add 802.11b mode */
    1381             : 
    1382       17958 :         mode = &nmodes[*num_modes];
    1383       17958 :         os_memset(mode, 0, sizeof(*mode));
    1384       17958 :         (*num_modes)++;
    1385       17958 :         modes = nmodes;
    1386             : 
    1387       17958 :         mode->mode = HOSTAPD_MODE_IEEE80211B;
    1388             : 
    1389       17958 :         mode11g = &modes[mode11g_idx];
    1390       17958 :         mode->num_channels = mode11g->num_channels;
    1391       17958 :         mode->channels = os_malloc(mode11g->num_channels *
    1392             :                                    sizeof(struct hostapd_channel_data));
    1393       17958 :         if (mode->channels == NULL) {
    1394           1 :                 (*num_modes)--;
    1395           1 :                 return modes; /* Could not add 802.11b mode */
    1396             :         }
    1397       17957 :         os_memcpy(mode->channels, mode11g->channels,
    1398             :                   mode11g->num_channels * sizeof(struct hostapd_channel_data));
    1399             : 
    1400       17957 :         mode->num_rates = 0;
    1401       17957 :         mode->rates = os_malloc(4 * sizeof(int));
    1402       17957 :         if (mode->rates == NULL) {
    1403           1 :                 os_free(mode->channels);
    1404           1 :                 (*num_modes)--;
    1405           1 :                 return modes; /* Could not add 802.11b mode */
    1406             :         }
    1407             : 
    1408       71824 :         for (i = 0; i < mode11g->num_rates; i++) {
    1409      107736 :                 if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
    1410       53868 :                     mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
    1411           0 :                         continue;
    1412       71824 :                 mode->rates[mode->num_rates] = mode11g->rates[i];
    1413       71824 :                 mode->num_rates++;
    1414       71824 :                 if (mode->num_rates == 4)
    1415       17956 :                         break;
    1416             :         }
    1417             : 
    1418       17956 :         if (mode->num_rates == 0) {
    1419           0 :                 os_free(mode->channels);
    1420           0 :                 os_free(mode->rates);
    1421           0 :                 (*num_modes)--;
    1422           0 :                 return modes; /* No 802.11b rates */
    1423             :         }
    1424             : 
    1425       17956 :         wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
    1426             :                    "information");
    1427             : 
    1428       17956 :         return modes;
    1429             : }
    1430             : 
    1431             : 
    1432      214674 : static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
    1433             :                                   int end)
    1434             : {
    1435             :         int c;
    1436             : 
    1437     4293438 :         for (c = 0; c < mode->num_channels; c++) {
    1438     4078764 :                 struct hostapd_channel_data *chan = &mode->channels[c];
    1439     4078764 :                 if (chan->freq - 10 >= start && chan->freq + 10 <= end)
    1440      626896 :                         chan->flag |= HOSTAPD_CHAN_HT40;
    1441             :         }
    1442      214674 : }
    1443             : 
    1444             : 
    1445      276632 : static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
    1446             :                                       int end)
    1447             : {
    1448             :         int c;
    1449             : 
    1450     5532584 :         for (c = 0; c < mode->num_channels; c++) {
    1451     5255952 :                 struct hostapd_channel_data *chan = &mode->channels[c];
    1452     5255952 :                 if (!(chan->flag & HOSTAPD_CHAN_HT40))
    1453      422825 :                         continue;
    1454     4833127 :                 if (chan->freq - 30 >= start && chan->freq - 10 <= end)
    1455      501712 :                         chan->flag |= HOSTAPD_CHAN_HT40MINUS;
    1456     4833127 :                 if (chan->freq + 10 >= start && chan->freq + 30 <= end)
    1457      550117 :                         chan->flag |= HOSTAPD_CHAN_HT40PLUS;
    1458             :         }
    1459      276632 : }
    1460             : 
    1461             : 
    1462      138407 : static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
    1463             :                                       struct phy_info_arg *results)
    1464             : {
    1465             :         u16 m;
    1466             : 
    1467      415045 :         for (m = 0; m < *results->num_modes; m++) {
    1468             :                 int c;
    1469      276638 :                 struct hostapd_hw_modes *mode = &results->modes[m];
    1470             : 
    1471     5532704 :                 for (c = 0; c < mode->num_channels; c++) {
    1472     5256066 :                         struct hostapd_channel_data *chan = &mode->channels[c];
    1473     7910528 :                         if ((u32) chan->freq - 10 >= start &&
    1474     2654462 :                             (u32) chan->freq + 10 <= end)
    1475      673339 :                                 chan->max_tx_power = max_eirp;
    1476             :                 }
    1477             :         }
    1478      138407 : }
    1479             : 
    1480             : 
    1481      107403 : static void nl80211_reg_rule_ht40(u32 start, u32 end,
    1482             :                                   struct phy_info_arg *results)
    1483             : {
    1484             :         u16 m;
    1485             : 
    1486      322077 :         for (m = 0; m < *results->num_modes; m++) {
    1487      214674 :                 if (!(results->modes[m].ht_capab &
    1488             :                       HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
    1489           0 :                         continue;
    1490      214674 :                 nl80211_set_ht40_mode(&results->modes[m], start, end);
    1491             :         }
    1492      107403 : }
    1493             : 
    1494             : 
    1495      138407 : static void nl80211_reg_rule_sec(struct nlattr *tb[],
    1496             :                                  struct phy_info_arg *results)
    1497             : {
    1498             :         u32 start, end, max_bw;
    1499             :         u16 m;
    1500             : 
    1501      276814 :         if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
    1502      276814 :             tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
    1503      138407 :             tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
    1504           0 :                 return;
    1505             : 
    1506      138407 :         start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
    1507      138407 :         end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
    1508      138407 :         max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
    1509             : 
    1510      138407 :         if (max_bw < 20)
    1511           3 :                 return;
    1512             : 
    1513      415036 :         for (m = 0; m < *results->num_modes; m++) {
    1514      276632 :                 if (!(results->modes[m].ht_capab &
    1515             :                       HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
    1516           0 :                         continue;
    1517      276632 :                 nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
    1518             :         }
    1519             : }
    1520             : 
    1521             : 
    1522       89276 : static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
    1523             :                                  int end, int max_bw)
    1524             : {
    1525             :         int c;
    1526             : 
    1527     2231865 :         for (c = 0; c < mode->num_channels; c++) {
    1528     2142589 :                 struct hostapd_channel_data *chan = &mode->channels[c];
    1529     2142589 :                 if (chan->freq - 10 >= start && chan->freq + 70 <= end)
    1530      231933 :                         chan->flag |= HOSTAPD_CHAN_VHT_10_70;
    1531             : 
    1532     2142589 :                 if (chan->freq - 30 >= start && chan->freq + 50 <= end)
    1533      231982 :                         chan->flag |= HOSTAPD_CHAN_VHT_30_50;
    1534             : 
    1535     2142589 :                 if (chan->freq - 50 >= start && chan->freq + 30 <= end)
    1536      231981 :                         chan->flag |= HOSTAPD_CHAN_VHT_50_30;
    1537             : 
    1538     2142589 :                 if (chan->freq - 70 >= start && chan->freq + 10 <= end)
    1539      214454 :                         chan->flag |= HOSTAPD_CHAN_VHT_70_10;
    1540             : 
    1541     2142589 :                 if (max_bw >= 160) {
    1542      860794 :                         if (chan->freq - 10 >= start && chan->freq + 150 <= end)
    1543       89242 :                                 chan->flag |= HOSTAPD_CHAN_VHT_10_150;
    1544             : 
    1545      860794 :                         if (chan->freq - 30 >= start && chan->freq + 130 <= end)
    1546       89267 :                                 chan->flag |= HOSTAPD_CHAN_VHT_30_130;
    1547             : 
    1548      860794 :                         if (chan->freq - 50 >= start && chan->freq + 110 <= end)
    1549       89267 :                                 chan->flag |= HOSTAPD_CHAN_VHT_50_110;
    1550             : 
    1551      860794 :                         if (chan->freq - 70 >= start && chan->freq + 90 <= end)
    1552       89267 :                                 chan->flag |= HOSTAPD_CHAN_VHT_70_90;
    1553             : 
    1554      860794 :                         if (chan->freq - 90 >= start && chan->freq + 70 <= end)
    1555       89267 :                                 chan->flag |= HOSTAPD_CHAN_VHT_90_70;
    1556             : 
    1557      860794 :                         if (chan->freq - 110 >= start && chan->freq + 50 <= end)
    1558       89266 :                                 chan->flag |= HOSTAPD_CHAN_VHT_110_50;
    1559             : 
    1560      860794 :                         if (chan->freq - 130 >= start && chan->freq + 30 <= end)
    1561       89265 :                                 chan->flag |= HOSTAPD_CHAN_VHT_130_30;
    1562             : 
    1563      860794 :                         if (chan->freq - 150 >= start && chan->freq + 10 <= end)
    1564       71763 :                                 chan->flag |= HOSTAPD_CHAN_VHT_150_10;
    1565             :                 }
    1566             :         }
    1567       89276 : }
    1568             : 
    1569             : 
    1570      138407 : static void nl80211_reg_rule_vht(struct nlattr *tb[],
    1571             :                                  struct phy_info_arg *results)
    1572             : {
    1573             :         u32 start, end, max_bw;
    1574             :         u16 m;
    1575             : 
    1576      276814 :         if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
    1577      276814 :             tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
    1578      138407 :             tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
    1579           0 :                 return;
    1580             : 
    1581      138407 :         start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
    1582      138407 :         end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
    1583      138407 :         max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
    1584             : 
    1585      138407 :         if (max_bw < 80)
    1586       49076 :                 return;
    1587             : 
    1588      267883 :         for (m = 0; m < *results->num_modes; m++) {
    1589      178552 :                 if (!(results->modes[m].ht_capab &
    1590             :                       HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
    1591           0 :                         continue;
    1592             :                 /* TODO: use a real VHT support indication */
    1593      178552 :                 if (!results->modes[m].vht_capab)
    1594       89276 :                         continue;
    1595             : 
    1596       89276 :                 nl80211_set_vht_mode(&results->modes[m], start, end, max_bw);
    1597             :         }
    1598             : }
    1599             : 
    1600             : 
    1601        2485 : static const char * dfs_domain_name(enum nl80211_dfs_regions region)
    1602             : {
    1603        2485 :         switch (region) {
    1604             :         case NL80211_DFS_UNSET:
    1605           0 :                 return "DFS-UNSET";
    1606             :         case NL80211_DFS_FCC:
    1607        2045 :                 return "DFS-FCC";
    1608             :         case NL80211_DFS_ETSI:
    1609         382 :                 return "DFS-ETSI";
    1610             :         case NL80211_DFS_JP:
    1611          58 :                 return "DFS-JP";
    1612             :         default:
    1613           0 :                 return "DFS-invalid";
    1614             :         }
    1615             : }
    1616             : 
    1617             : 
    1618       17970 : static int nl80211_get_reg(struct nl_msg *msg, void *arg)
    1619             : {
    1620       17970 :         struct phy_info_arg *results = arg;
    1621             :         struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
    1622       17970 :         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    1623             :         struct nlattr *nl_rule;
    1624             :         struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
    1625             :         int rem_rule;
    1626             :         static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
    1627             :                 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
    1628             :                 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
    1629             :                 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
    1630             :                 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
    1631             :                 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
    1632             :                 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
    1633             :         };
    1634             : 
    1635       17970 :         nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
    1636             :                   genlmsg_attrlen(gnlh, 0), NULL);
    1637       35940 :         if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
    1638       17970 :             !tb_msg[NL80211_ATTR_REG_RULES]) {
    1639           0 :                 wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
    1640             :                            "available");
    1641           0 :                 return NL_SKIP;
    1642             :         }
    1643             : 
    1644       17970 :         if (tb_msg[NL80211_ATTR_DFS_REGION]) {
    1645             :                 enum nl80211_dfs_regions dfs_domain;
    1646        2485 :                 dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
    1647        4970 :                 wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
    1648        2485 :                            (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
    1649             :                            dfs_domain_name(dfs_domain));
    1650             :         } else {
    1651       15485 :                 wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
    1652       15485 :                            (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
    1653             :         }
    1654             : 
    1655      156377 :         nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
    1656             :         {
    1657      138407 :                 u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
    1658      276814 :                 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
    1659      138407 :                           nla_data(nl_rule), nla_len(nl_rule), reg_policy);
    1660      276814 :                 if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
    1661      138407 :                     tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
    1662           0 :                         continue;
    1663      138407 :                 start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
    1664      138407 :                 end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
    1665      138407 :                 if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
    1666      138407 :                         max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
    1667      138407 :                 if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
    1668      138407 :                         max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
    1669      138407 :                 if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
    1670      138407 :                         flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
    1671             : 
    1672     1107256 :                 wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
    1673             :                            start, end, max_bw, max_eirp,
    1674      138407 :                            flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
    1675      138407 :                            flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
    1676      138407 :                            flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
    1677      138407 :                            flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
    1678             :                            "",
    1679      138407 :                            flags & NL80211_RRF_DFS ? " (DFS)" : "",
    1680      138407 :                            flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
    1681      138407 :                            flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
    1682      138407 :                            flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
    1683      138407 :                 if (max_bw >= 40)
    1684      107403 :                         nl80211_reg_rule_ht40(start, end, results);
    1685      138407 :                 if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
    1686      138407 :                         nl80211_reg_rule_max_eirp(start, end, max_eirp,
    1687             :                                                   results);
    1688             :         }
    1689             : 
    1690      156377 :         nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
    1691             :         {
    1692      276814 :                 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
    1693      138407 :                           nla_data(nl_rule), nla_len(nl_rule), reg_policy);
    1694      138407 :                 nl80211_reg_rule_sec(tb_rule, results);
    1695             :         }
    1696             : 
    1697      156377 :         nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
    1698             :         {
    1699      276814 :                 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
    1700      138407 :                           nla_data(nl_rule), nla_len(nl_rule), reg_policy);
    1701      138407 :                 nl80211_reg_rule_vht(tb_rule, results);
    1702             :         }
    1703             : 
    1704       17970 :         return NL_SKIP;
    1705             : }
    1706             : 
    1707             : 
    1708       17970 : static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
    1709             :                                         struct phy_info_arg *results)
    1710             : {
    1711             :         struct nl_msg *msg;
    1712             : 
    1713       17970 :         msg = nlmsg_alloc();
    1714       17970 :         if (!msg)
    1715           0 :                 return -ENOMEM;
    1716             : 
    1717       17970 :         nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
    1718       17970 :         return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
    1719             : }
    1720             : 
    1721             : 
    1722             : struct hostapd_hw_modes *
    1723       17970 : nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
    1724             : {
    1725             :         u32 feat;
    1726       17970 :         struct i802_bss *bss = priv;
    1727       17970 :         struct wpa_driver_nl80211_data *drv = bss->drv;
    1728       17970 :         int nl_flags = 0;
    1729             :         struct nl_msg *msg;
    1730       17970 :         struct phy_info_arg result = {
    1731             :                 .num_modes = num_modes,
    1732             :                 .modes = NULL,
    1733             :                 .last_mode = -1,
    1734             :                 .failed = 0,
    1735             :         };
    1736             : 
    1737       17970 :         *num_modes = 0;
    1738       17970 :         *flags = 0;
    1739             : 
    1740       17970 :         feat = get_nl80211_protocol_features(drv);
    1741       17970 :         if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
    1742       17970 :                 nl_flags = NLM_F_DUMP;
    1743       35940 :         if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
    1744       17970 :             nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
    1745           0 :                 nlmsg_free(msg);
    1746           0 :                 return NULL;
    1747             :         }
    1748             : 
    1749       17970 :         if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
    1750       17970 :                 nl80211_set_regulatory_flags(drv, &result);
    1751       17970 :                 if (result.failed) {
    1752             :                         int i;
    1753             : 
    1754           0 :                         for (i = 0; result.modes && i < *num_modes; i++) {
    1755           0 :                                 os_free(result.modes[i].channels);
    1756           0 :                                 os_free(result.modes[i].rates);
    1757             :                         }
    1758           0 :                         os_free(result.modes);
    1759           0 :                         return NULL;
    1760             :                 }
    1761       17970 :                 return wpa_driver_nl80211_postprocess_modes(result.modes,
    1762             :                                                             num_modes);
    1763             :         }
    1764             : 
    1765           0 :         return NULL;
    1766             : }

Generated by: LCOV version 1.10