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 1443382998 Lines: 615 806 76.3 %
Date: 2015-09-27 Functions: 38 42 90.5 %

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

Generated by: LCOV version 1.10