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 1422976643 Lines: 589 770 76.5 %
Date: 2015-02-03 Functions: 36 40 90.0 %

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

Generated by: LCOV version 1.10