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
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
12 #include <netlink/genl/genl.h>
14 #include "utils/common.h"
15 #include "common/ieee802_11_common.h"
16 #include "common/wpa_common.h"
17 #include "common/qca-vendor.h"
18 #include "common/qca-vendor-attr.h"
19 #include "driver_nl80211.h"
22 static int protocol_feature_handler(struct nl_msg
*msg
, void *arg
)
25 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
26 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
28 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
29 genlmsg_attrlen(gnlh
, 0), NULL
);
31 if (tb_msg
[NL80211_ATTR_PROTOCOL_FEATURES
])
32 *feat
= nla_get_u32(tb_msg
[NL80211_ATTR_PROTOCOL_FEATURES
]);
38 static u32
get_nl80211_protocol_features(struct wpa_driver_nl80211_data
*drv
)
47 if (!nl80211_cmd(drv
, msg
, 0, NL80211_CMD_GET_PROTOCOL_FEATURES
)) {
52 if (send_and_recv_msgs(drv
, msg
, protocol_feature_handler
, &feat
) == 0)
59 struct wiphy_info_data
{
60 struct wpa_driver_nl80211_data
*drv
;
61 struct wpa_driver_capa
*capa
;
63 unsigned int num_multichan_concurrent
;
66 unsigned int device_ap_sme
:1;
67 unsigned int poll_command_supported
:1;
68 unsigned int data_tx_status
:1;
69 unsigned int auth_supported
:1;
70 unsigned int connect_supported
:1;
71 unsigned int p2p_go_supported
:1;
72 unsigned int p2p_client_supported
:1;
73 unsigned int p2p_go_ctwindow_supported
:1;
74 unsigned int p2p_concurrent
:1;
75 unsigned int channel_switch_supported
:1;
76 unsigned int set_qos_map_supported
:1;
77 unsigned int have_low_prio_scan
:1;
78 unsigned int wmm_ac_supported
:1;
79 unsigned int mac_addr_rand_scan_supported
:1;
80 unsigned int mac_addr_rand_sched_scan_supported
:1;
81 unsigned int update_ft_ies_supported
:1;
85 static unsigned int probe_resp_offload_support(int supp_protocols
)
87 unsigned int prot
= 0;
89 if (supp_protocols
& NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS
)
90 prot
|= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS
;
91 if (supp_protocols
& NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2
)
92 prot
|= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2
;
93 if (supp_protocols
& NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P
)
94 prot
|= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P
;
95 if (supp_protocols
& NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U
)
96 prot
|= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING
;
102 static void wiphy_info_supported_iftypes(struct wiphy_info_data
*info
,
105 struct nlattr
*nl_mode
;
111 nla_for_each_nested(nl_mode
, tb
, i
) {
112 switch (nla_type(nl_mode
)) {
113 case NL80211_IFTYPE_AP
:
114 info
->capa
->flags
|= WPA_DRIVER_FLAGS_AP
;
116 case NL80211_IFTYPE_MESH_POINT
:
117 info
->capa
->flags
|= WPA_DRIVER_FLAGS_MESH
;
119 case NL80211_IFTYPE_ADHOC
:
120 info
->capa
->flags
|= WPA_DRIVER_FLAGS_IBSS
;
122 case NL80211_IFTYPE_P2P_DEVICE
:
124 WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE
;
126 case NL80211_IFTYPE_P2P_GO
:
127 info
->p2p_go_supported
= 1;
129 case NL80211_IFTYPE_P2P_CLIENT
:
130 info
->p2p_client_supported
= 1;
137 static int wiphy_info_iface_comb_process(struct wiphy_info_data
*info
,
138 struct nlattr
*nl_combi
)
140 struct nlattr
*tb_comb
[NUM_NL80211_IFACE_COMB
];
141 struct nlattr
*tb_limit
[NUM_NL80211_IFACE_LIMIT
];
142 struct nlattr
*nl_limit
, *nl_mode
;
143 int err
, rem_limit
, rem_mode
;
144 int combination_has_p2p
= 0, combination_has_mgd
= 0;
145 static struct nla_policy
146 iface_combination_policy
[NUM_NL80211_IFACE_COMB
] = {
147 [NL80211_IFACE_COMB_LIMITS
] = { .type
= NLA_NESTED
},
148 [NL80211_IFACE_COMB_MAXNUM
] = { .type
= NLA_U32
},
149 [NL80211_IFACE_COMB_STA_AP_BI_MATCH
] = { .type
= NLA_FLAG
},
150 [NL80211_IFACE_COMB_NUM_CHANNELS
] = { .type
= NLA_U32
},
151 [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS
] = { .type
= NLA_U32
},
153 iface_limit_policy
[NUM_NL80211_IFACE_LIMIT
] = {
154 [NL80211_IFACE_LIMIT_TYPES
] = { .type
= NLA_NESTED
},
155 [NL80211_IFACE_LIMIT_MAX
] = { .type
= NLA_U32
},
158 err
= nla_parse_nested(tb_comb
, MAX_NL80211_IFACE_COMB
,
159 nl_combi
, iface_combination_policy
);
160 if (err
|| !tb_comb
[NL80211_IFACE_COMB_LIMITS
] ||
161 !tb_comb
[NL80211_IFACE_COMB_MAXNUM
] ||
162 !tb_comb
[NL80211_IFACE_COMB_NUM_CHANNELS
])
163 return 0; /* broken combination */
165 if (tb_comb
[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS
])
166 info
->capa
->flags
|= WPA_DRIVER_FLAGS_RADAR
;
168 nla_for_each_nested(nl_limit
, tb_comb
[NL80211_IFACE_COMB_LIMITS
],
170 err
= nla_parse_nested(tb_limit
, MAX_NL80211_IFACE_LIMIT
,
171 nl_limit
, iface_limit_policy
);
172 if (err
|| !tb_limit
[NL80211_IFACE_LIMIT_TYPES
])
173 return 0; /* broken combination */
175 nla_for_each_nested(nl_mode
,
176 tb_limit
[NL80211_IFACE_LIMIT_TYPES
],
178 int ift
= nla_type(nl_mode
);
179 if (ift
== NL80211_IFTYPE_P2P_GO
||
180 ift
== NL80211_IFTYPE_P2P_CLIENT
)
181 combination_has_p2p
= 1;
182 if (ift
== NL80211_IFTYPE_STATION
)
183 combination_has_mgd
= 1;
185 if (combination_has_p2p
&& combination_has_mgd
)
189 if (combination_has_p2p
&& combination_has_mgd
) {
190 unsigned int num_channels
=
191 nla_get_u32(tb_comb
[NL80211_IFACE_COMB_NUM_CHANNELS
]);
193 info
->p2p_concurrent
= 1;
194 if (info
->num_multichan_concurrent
< num_channels
)
195 info
->num_multichan_concurrent
= num_channels
;
202 static void wiphy_info_iface_comb(struct wiphy_info_data
*info
,
205 struct nlattr
*nl_combi
;
211 nla_for_each_nested(nl_combi
, tb
, rem_combi
) {
212 if (wiphy_info_iface_comb_process(info
, nl_combi
) > 0)
218 static void wiphy_info_supp_cmds(struct wiphy_info_data
*info
,
221 struct nlattr
*nl_cmd
;
227 nla_for_each_nested(nl_cmd
, tb
, i
) {
228 switch (nla_get_u32(nl_cmd
)) {
229 case NL80211_CMD_AUTHENTICATE
:
230 info
->auth_supported
= 1;
232 case NL80211_CMD_CONNECT
:
233 info
->connect_supported
= 1;
235 case NL80211_CMD_START_SCHED_SCAN
:
236 info
->capa
->sched_scan_supported
= 1;
238 case NL80211_CMD_PROBE_CLIENT
:
239 info
->poll_command_supported
= 1;
241 case NL80211_CMD_CHANNEL_SWITCH
:
242 info
->channel_switch_supported
= 1;
244 case NL80211_CMD_SET_QOS_MAP
:
245 info
->set_qos_map_supported
= 1;
247 case NL80211_CMD_UPDATE_FT_IES
:
248 info
->update_ft_ies_supported
= 1;
255 static void wiphy_info_cipher_suites(struct wiphy_info_data
*info
,
264 num
= nla_len(tb
) / sizeof(u32
);
265 ciphers
= nla_data(tb
);
266 for (i
= 0; i
< num
; i
++) {
269 wpa_printf(MSG_DEBUG
, "nl80211: Supported cipher %02x-%02x-%02x:%d",
270 c
>> 24, (c
>> 16) & 0xff,
271 (c
>> 8) & 0xff, c
& 0xff);
273 case RSN_CIPHER_SUITE_CCMP_256
:
274 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_CCMP_256
;
276 case RSN_CIPHER_SUITE_GCMP_256
:
277 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_GCMP_256
;
279 case RSN_CIPHER_SUITE_CCMP
:
280 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_CCMP
;
282 case RSN_CIPHER_SUITE_GCMP
:
283 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_GCMP
;
285 case RSN_CIPHER_SUITE_TKIP
:
286 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_TKIP
;
288 case RSN_CIPHER_SUITE_WEP104
:
289 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_WEP104
;
291 case RSN_CIPHER_SUITE_WEP40
:
292 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_WEP40
;
294 case RSN_CIPHER_SUITE_AES_128_CMAC
:
295 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_BIP
;
297 case RSN_CIPHER_SUITE_BIP_GMAC_128
:
298 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128
;
300 case RSN_CIPHER_SUITE_BIP_GMAC_256
:
301 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256
;
303 case RSN_CIPHER_SUITE_BIP_CMAC_256
:
304 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256
;
306 case RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED
:
307 info
->capa
->enc
|= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED
;
314 static void wiphy_info_max_roc(struct wpa_driver_capa
*capa
,
318 capa
->max_remain_on_chan
= nla_get_u32(tb
);
322 static void wiphy_info_tdls(struct wpa_driver_capa
*capa
, struct nlattr
*tdls
,
323 struct nlattr
*ext_setup
)
328 wpa_printf(MSG_DEBUG
, "nl80211: TDLS supported");
329 capa
->flags
|= WPA_DRIVER_FLAGS_TDLS_SUPPORT
;
332 wpa_printf(MSG_DEBUG
, "nl80211: TDLS external setup");
333 capa
->flags
|= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP
;
338 static int ext_feature_isset(const u8
*ext_features
, int ext_features_len
,
339 enum nl80211_ext_feature_index ftidx
)
343 if ((int) ftidx
/ 8 >= ext_features_len
)
346 ft_byte
= ext_features
[ftidx
/ 8];
347 return (ft_byte
& BIT(ftidx
% 8)) != 0;
351 static void wiphy_info_ext_feature_flags(struct wiphy_info_data
*info
,
354 struct wpa_driver_capa
*capa
= info
->capa
;
361 ext_features
= nla_data(tb
);
364 if (ext_feature_isset(ext_features
, len
, NL80211_EXT_FEATURE_VHT_IBSS
))
365 capa
->flags
|= WPA_DRIVER_FLAGS_VHT_IBSS
;
367 if (ext_feature_isset(ext_features
, len
, NL80211_EXT_FEATURE_RRM
))
368 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_SUPPORT_RRM
;
370 if (ext_feature_isset(ext_features
, len
, NL80211_EXT_FEATURE_FILS_STA
))
371 capa
->flags
|= WPA_DRIVER_FLAGS_SUPPORT_FILS
;
373 if (ext_feature_isset(ext_features
, len
,
374 NL80211_EXT_FEATURE_BEACON_RATE_LEGACY
))
375 capa
->flags
|= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY
;
377 if (ext_feature_isset(ext_features
, len
,
378 NL80211_EXT_FEATURE_BEACON_RATE_HT
))
379 capa
->flags
|= WPA_DRIVER_FLAGS_BEACON_RATE_HT
;
381 if (ext_feature_isset(ext_features
, len
,
382 NL80211_EXT_FEATURE_BEACON_RATE_VHT
))
383 capa
->flags
|= WPA_DRIVER_FLAGS_BEACON_RATE_VHT
;
385 if (ext_feature_isset(ext_features
, len
,
386 NL80211_EXT_FEATURE_SET_SCAN_DWELL
))
387 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL
;
389 if (ext_feature_isset(ext_features
, len
,
390 NL80211_EXT_FEATURE_SCAN_START_TIME
) &&
391 ext_feature_isset(ext_features
, len
,
392 NL80211_EXT_FEATURE_BSS_PARENT_TSF
) &&
393 ext_feature_isset(ext_features
, len
,
394 NL80211_EXT_FEATURE_SET_SCAN_DWELL
))
395 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT
;
396 if (ext_feature_isset(ext_features
, len
,
397 NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA
))
398 capa
->flags
|= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA
;
399 if (ext_feature_isset(ext_features
, len
,
400 NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED
))
401 capa
->flags
|= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED
;
402 if (ext_feature_isset(ext_features
, len
,
403 NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI
))
404 capa
->flags
|= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI
;
405 if (ext_feature_isset(ext_features
, len
,
406 NL80211_EXT_FEATURE_FILS_SK_OFFLOAD
))
407 capa
->flags
|= WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD
;
409 if (ext_feature_isset(ext_features
, len
,
410 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK
))
411 capa
->flags
|= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK
;
412 if (ext_feature_isset(ext_features
, len
,
413 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X
))
414 capa
->flags
|= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X
;
416 if (ext_feature_isset(ext_features
, len
,
417 NL80211_EXT_FEATURE_MFP_OPTIONAL
))
418 capa
->flags
|= WPA_DRIVER_FLAGS_MFP_OPTIONAL
;
420 if (ext_feature_isset(ext_features
, len
,
421 NL80211_EXT_FEATURE_DFS_OFFLOAD
))
422 capa
->flags
|= WPA_DRIVER_FLAGS_DFS_OFFLOAD
;
425 if (ext_feature_isset(ext_features
, len
,
426 NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME
) &&
427 ext_feature_isset(ext_features
, len
,
428 NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP
) &&
429 ext_feature_isset(ext_features
, len
,
430 NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE
) &&
433 NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION
))
434 capa
->flags
|= WPA_DRIVER_FLAGS_OCE_STA
;
435 #endif /* CONFIG_MBO */
437 if (ext_feature_isset(ext_features
, len
,
438 NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER
))
439 capa
->flags
|= WPA_DRIVER_FLAGS_FTM_RESPONDER
;
441 if (ext_feature_isset(ext_features
, len
,
442 NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211
))
443 capa
->flags
|= WPA_DRIVER_FLAGS_CONTROL_PORT
;
445 if (ext_feature_isset(ext_features
, len
,
446 NL80211_EXT_FEATURE_VLAN_OFFLOAD
))
447 capa
->flags
|= WPA_DRIVER_FLAGS_VLAN_OFFLOAD
;
451 static void wiphy_info_feature_flags(struct wiphy_info_data
*info
,
455 struct wpa_driver_capa
*capa
= info
->capa
;
460 flags
= nla_get_u32(tb
);
462 if (flags
& NL80211_FEATURE_SK_TX_STATUS
)
463 info
->data_tx_status
= 1;
465 if (flags
& NL80211_FEATURE_INACTIVITY_TIMER
)
466 capa
->flags
|= WPA_DRIVER_FLAGS_INACTIVITY_TIMER
;
468 if (flags
& NL80211_FEATURE_SAE
)
469 capa
->flags
|= WPA_DRIVER_FLAGS_SAE
;
471 if (flags
& NL80211_FEATURE_NEED_OBSS_SCAN
)
472 capa
->flags
|= WPA_DRIVER_FLAGS_OBSS_SCAN
;
474 if (flags
& NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE
)
475 capa
->flags
|= WPA_DRIVER_FLAGS_HT_2040_COEX
;
477 if (flags
& NL80211_FEATURE_TDLS_CHANNEL_SWITCH
) {
478 wpa_printf(MSG_DEBUG
, "nl80211: TDLS channel switch");
479 capa
->flags
|= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH
;
482 if (flags
& NL80211_FEATURE_P2P_GO_CTWIN
)
483 info
->p2p_go_ctwindow_supported
= 1;
485 if (flags
& NL80211_FEATURE_LOW_PRIORITY_SCAN
)
486 info
->have_low_prio_scan
= 1;
488 if (flags
& NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR
)
489 info
->mac_addr_rand_scan_supported
= 1;
491 if (flags
& NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR
)
492 info
->mac_addr_rand_sched_scan_supported
= 1;
494 if (flags
& NL80211_FEATURE_SUPPORTS_WMM_ADMISSION
)
495 info
->wmm_ac_supported
= 1;
497 if (flags
& NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES
)
498 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES
;
500 if (flags
& NL80211_FEATURE_WFA_TPC_IE_IN_PROBES
)
501 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES
;
503 if (flags
& NL80211_FEATURE_QUIET
)
504 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_QUIET
;
506 if (flags
& NL80211_FEATURE_TX_POWER_INSERTION
)
507 capa
->rrm_flags
|= WPA_DRIVER_FLAGS_TX_POWER_INSERTION
;
509 if (flags
& NL80211_FEATURE_HT_IBSS
)
510 capa
->flags
|= WPA_DRIVER_FLAGS_HT_IBSS
;
512 if (flags
& NL80211_FEATURE_FULL_AP_CLIENT_STATE
)
513 capa
->flags
|= WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE
;
517 static void wiphy_info_probe_resp_offload(struct wpa_driver_capa
*capa
,
525 protocols
= nla_get_u32(tb
);
526 wpa_printf(MSG_DEBUG
, "nl80211: Supports Probe Response offload in AP "
528 capa
->flags
|= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD
;
529 capa
->probe_resp_offloads
= probe_resp_offload_support(protocols
);
533 static void wiphy_info_wowlan_triggers(struct wpa_driver_capa
*capa
,
536 struct nlattr
*triggers
[MAX_NL80211_WOWLAN_TRIG
+ 1];
541 if (nla_parse_nested(triggers
, MAX_NL80211_WOWLAN_TRIG
,
545 if (triggers
[NL80211_WOWLAN_TRIG_ANY
])
546 capa
->wowlan_triggers
.any
= 1;
547 if (triggers
[NL80211_WOWLAN_TRIG_DISCONNECT
])
548 capa
->wowlan_triggers
.disconnect
= 1;
549 if (triggers
[NL80211_WOWLAN_TRIG_MAGIC_PKT
])
550 capa
->wowlan_triggers
.magic_pkt
= 1;
551 if (triggers
[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE
])
552 capa
->wowlan_triggers
.gtk_rekey_failure
= 1;
553 if (triggers
[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST
])
554 capa
->wowlan_triggers
.eap_identity_req
= 1;
555 if (triggers
[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE
])
556 capa
->wowlan_triggers
.four_way_handshake
= 1;
557 if (triggers
[NL80211_WOWLAN_TRIG_RFKILL_RELEASE
])
558 capa
->wowlan_triggers
.rfkill_release
= 1;
562 static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data
*drv
,
566 struct nlattr
*tb1
[NL80211_ATTR_MAX
+ 1], *attr
;
568 if (!tb
|| drv
->num_iface_ext_capa
== NL80211_IFTYPE_MAX
)
571 nla_for_each_nested(attr
, tb
, rem
) {
573 struct drv_nl80211_ext_capa
*capa
;
575 nla_parse(tb1
, NL80211_ATTR_MAX
, nla_data(attr
),
576 nla_len(attr
), NULL
);
578 if (!tb1
[NL80211_ATTR_IFTYPE
] ||
579 !tb1
[NL80211_ATTR_EXT_CAPA
] ||
580 !tb1
[NL80211_ATTR_EXT_CAPA_MASK
])
583 capa
= &drv
->iface_ext_capa
[drv
->num_iface_ext_capa
];
584 capa
->iftype
= nla_get_u32(tb1
[NL80211_ATTR_IFTYPE
]);
585 wpa_printf(MSG_DEBUG
,
586 "nl80211: Driver-advertised extended capabilities for interface type %s",
587 nl80211_iftype_str(capa
->iftype
));
589 len
= nla_len(tb1
[NL80211_ATTR_EXT_CAPA
]);
590 capa
->ext_capa
= os_memdup(nla_data(tb1
[NL80211_ATTR_EXT_CAPA
]),
595 capa
->ext_capa_len
= len
;
596 wpa_hexdump(MSG_DEBUG
, "nl80211: Extended capabilities",
597 capa
->ext_capa
, capa
->ext_capa_len
);
599 len
= nla_len(tb1
[NL80211_ATTR_EXT_CAPA_MASK
]);
600 capa
->ext_capa_mask
=
601 os_memdup(nla_data(tb1
[NL80211_ATTR_EXT_CAPA_MASK
]),
603 if (!capa
->ext_capa_mask
)
606 wpa_hexdump(MSG_DEBUG
, "nl80211: Extended capabilities mask",
607 capa
->ext_capa_mask
, capa
->ext_capa_len
);
609 drv
->num_iface_ext_capa
++;
610 if (drv
->num_iface_ext_capa
== NL80211_IFTYPE_MAX
)
617 /* Cleanup allocated memory on error */
618 for (i
= 0; i
< NL80211_IFTYPE_MAX
; i
++) {
619 os_free(drv
->iface_ext_capa
[i
].ext_capa
);
620 drv
->iface_ext_capa
[i
].ext_capa
= NULL
;
621 os_free(drv
->iface_ext_capa
[i
].ext_capa_mask
);
622 drv
->iface_ext_capa
[i
].ext_capa_mask
= NULL
;
623 drv
->iface_ext_capa
[i
].ext_capa_len
= 0;
625 drv
->num_iface_ext_capa
= 0;
629 static int wiphy_info_handler(struct nl_msg
*msg
, void *arg
)
631 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
632 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
633 struct wiphy_info_data
*info
= arg
;
634 struct wpa_driver_capa
*capa
= info
->capa
;
635 struct wpa_driver_nl80211_data
*drv
= info
->drv
;
637 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
638 genlmsg_attrlen(gnlh
, 0), NULL
);
640 if (tb
[NL80211_ATTR_WIPHY
])
641 drv
->wiphy_idx
= nla_get_u32(tb
[NL80211_ATTR_WIPHY
]);
643 if (tb
[NL80211_ATTR_WIPHY_NAME
])
644 os_strlcpy(drv
->phyname
,
645 nla_get_string(tb
[NL80211_ATTR_WIPHY_NAME
]),
646 sizeof(drv
->phyname
));
647 if (tb
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
])
648 capa
->max_scan_ssids
=
649 nla_get_u8(tb
[NL80211_ATTR_MAX_NUM_SCAN_SSIDS
]);
651 if (tb
[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS
])
652 capa
->max_sched_scan_ssids
=
653 nla_get_u8(tb
[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS
]);
655 if (tb
[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS
] &&
656 tb
[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL
] &&
657 tb
[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS
]) {
658 capa
->max_sched_scan_plans
=
659 nla_get_u32(tb
[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS
]);
661 capa
->max_sched_scan_plan_interval
=
662 nla_get_u32(tb
[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL
]);
664 capa
->max_sched_scan_plan_iterations
=
665 nla_get_u32(tb
[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS
]);
668 if (tb
[NL80211_ATTR_MAX_MATCH_SETS
])
669 capa
->max_match_sets
=
670 nla_get_u8(tb
[NL80211_ATTR_MAX_MATCH_SETS
]);
672 if (tb
[NL80211_ATTR_MAC_ACL_MAX
])
673 capa
->max_acl_mac_addrs
=
674 nla_get_u8(tb
[NL80211_ATTR_MAC_ACL_MAX
]);
676 wiphy_info_supported_iftypes(info
, tb
[NL80211_ATTR_SUPPORTED_IFTYPES
]);
677 wiphy_info_iface_comb(info
, tb
[NL80211_ATTR_INTERFACE_COMBINATIONS
]);
678 wiphy_info_supp_cmds(info
, tb
[NL80211_ATTR_SUPPORTED_COMMANDS
]);
679 wiphy_info_cipher_suites(info
, tb
[NL80211_ATTR_CIPHER_SUITES
]);
681 if (tb
[NL80211_ATTR_OFFCHANNEL_TX_OK
]) {
682 wpa_printf(MSG_DEBUG
, "nl80211: Using driver-based "
684 capa
->flags
|= WPA_DRIVER_FLAGS_OFFCHANNEL_TX
;
687 if (tb
[NL80211_ATTR_ROAM_SUPPORT
]) {
688 wpa_printf(MSG_DEBUG
, "nl80211: Using driver-based roaming");
689 capa
->flags
|= WPA_DRIVER_FLAGS_BSS_SELECTION
;
692 wiphy_info_max_roc(capa
,
693 tb
[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION
]);
695 if (tb
[NL80211_ATTR_SUPPORT_AP_UAPSD
])
696 capa
->flags
|= WPA_DRIVER_FLAGS_AP_UAPSD
;
698 wiphy_info_tdls(capa
, tb
[NL80211_ATTR_TDLS_SUPPORT
],
699 tb
[NL80211_ATTR_TDLS_EXTERNAL_SETUP
]);
701 if (tb
[NL80211_ATTR_DEVICE_AP_SME
])
702 info
->device_ap_sme
= 1;
704 wiphy_info_feature_flags(info
, tb
[NL80211_ATTR_FEATURE_FLAGS
]);
705 wiphy_info_ext_feature_flags(info
, tb
[NL80211_ATTR_EXT_FEATURES
]);
706 wiphy_info_probe_resp_offload(capa
,
707 tb
[NL80211_ATTR_PROBE_RESP_OFFLOAD
]);
709 if (tb
[NL80211_ATTR_EXT_CAPA
] && tb
[NL80211_ATTR_EXT_CAPA_MASK
] &&
710 drv
->extended_capa
== NULL
) {
712 os_malloc(nla_len(tb
[NL80211_ATTR_EXT_CAPA
]));
713 if (drv
->extended_capa
) {
714 os_memcpy(drv
->extended_capa
,
715 nla_data(tb
[NL80211_ATTR_EXT_CAPA
]),
716 nla_len(tb
[NL80211_ATTR_EXT_CAPA
]));
717 drv
->extended_capa_len
=
718 nla_len(tb
[NL80211_ATTR_EXT_CAPA
]);
719 wpa_hexdump(MSG_DEBUG
,
720 "nl80211: Driver-advertised extended capabilities (default)",
721 drv
->extended_capa
, drv
->extended_capa_len
);
723 drv
->extended_capa_mask
=
724 os_malloc(nla_len(tb
[NL80211_ATTR_EXT_CAPA_MASK
]));
725 if (drv
->extended_capa_mask
) {
726 os_memcpy(drv
->extended_capa_mask
,
727 nla_data(tb
[NL80211_ATTR_EXT_CAPA_MASK
]),
728 nla_len(tb
[NL80211_ATTR_EXT_CAPA_MASK
]));
729 wpa_hexdump(MSG_DEBUG
,
730 "nl80211: Driver-advertised extended capabilities mask (default)",
731 drv
->extended_capa_mask
,
732 drv
->extended_capa_len
);
734 os_free(drv
->extended_capa
);
735 drv
->extended_capa
= NULL
;
736 drv
->extended_capa_len
= 0;
740 wiphy_info_extended_capab(drv
, tb
[NL80211_ATTR_IFTYPE_EXT_CAPA
]);
742 if (tb
[NL80211_ATTR_VENDOR_DATA
]) {
746 nla_for_each_nested(nl
, tb
[NL80211_ATTR_VENDOR_DATA
], rem
) {
747 struct nl80211_vendor_cmd_info
*vinfo
;
748 if (nla_len(nl
) != sizeof(*vinfo
)) {
749 wpa_printf(MSG_DEBUG
, "nl80211: Unexpected vendor data info");
752 vinfo
= nla_data(nl
);
753 if (vinfo
->vendor_id
== OUI_QCA
) {
754 switch (vinfo
->subcmd
) {
755 case QCA_NL80211_VENDOR_SUBCMD_TEST
:
756 drv
->vendor_cmd_test_avail
= 1;
758 #ifdef CONFIG_DRIVER_NL80211_QCA
759 case QCA_NL80211_VENDOR_SUBCMD_ROAMING
:
760 drv
->roaming_vendor_cmd_avail
= 1;
762 case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY
:
763 drv
->dfs_vendor_cmd_avail
= 1;
765 case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES
:
766 drv
->get_features_vendor_cmd_avail
= 1;
768 case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST
:
769 drv
->get_pref_freq_list
= 1;
771 case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL
:
772 drv
->set_prob_oper_freq
= 1;
774 case QCA_NL80211_VENDOR_SUBCMD_DO_ACS
:
776 WPA_DRIVER_FLAGS_ACS_OFFLOAD
;
778 case QCA_NL80211_VENDOR_SUBCMD_SETBAND
:
779 drv
->setband_vendor_cmd_avail
= 1;
781 case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
:
782 drv
->scan_vendor_cmd_avail
= 1;
784 case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION
:
785 drv
->set_wifi_conf_vendor_cmd_avail
= 1;
787 case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS
:
788 drv
->fetch_bss_trans_status
= 1;
790 case QCA_NL80211_VENDOR_SUBCMD_ROAM
:
791 drv
->roam_vendor_cmd_avail
= 1;
793 case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS
:
794 drv
->get_supported_akm_suites_avail
= 1;
796 case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE
:
797 drv
->add_sta_node_vendor_cmd_avail
= 1;
799 #endif /* CONFIG_DRIVER_NL80211_QCA */
803 wpa_printf(MSG_DEBUG
, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
804 vinfo
->vendor_id
, vinfo
->subcmd
);
808 if (tb
[NL80211_ATTR_VENDOR_EVENTS
]) {
812 nla_for_each_nested(nl
, tb
[NL80211_ATTR_VENDOR_EVENTS
], rem
) {
813 struct nl80211_vendor_cmd_info
*vinfo
;
814 if (nla_len(nl
) != sizeof(*vinfo
)) {
815 wpa_printf(MSG_DEBUG
, "nl80211: Unexpected vendor data info");
818 vinfo
= nla_data(nl
);
819 wpa_printf(MSG_DEBUG
, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
820 vinfo
->vendor_id
, vinfo
->subcmd
);
824 wiphy_info_wowlan_triggers(capa
,
825 tb
[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED
]);
827 if (tb
[NL80211_ATTR_MAX_AP_ASSOC_STA
])
829 nla_get_u32(tb
[NL80211_ATTR_MAX_AP_ASSOC_STA
]);
831 if (tb
[NL80211_ATTR_MAX_CSA_COUNTERS
])
832 capa
->max_csa_counters
=
833 nla_get_u8(tb
[NL80211_ATTR_MAX_CSA_COUNTERS
]);
835 if (tb
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG
])
836 capa
->flags
|= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY
;
842 static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data
*drv
,
843 struct wiphy_info_data
*info
)
849 os_memset(info
, 0, sizeof(*info
));
850 info
->capa
= &drv
->capa
;
853 feat
= get_nl80211_protocol_features(drv
);
854 if (feat
& NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP
)
856 msg
= nl80211_cmd_msg(drv
->first_bss
, flags
, NL80211_CMD_GET_WIPHY
);
857 if (!msg
|| nla_put_flag(msg
, NL80211_ATTR_SPLIT_WIPHY_DUMP
)) {
862 if (send_and_recv_msgs(drv
, msg
, wiphy_info_handler
, info
))
865 if (info
->auth_supported
)
866 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_SME
;
867 else if (!info
->connect_supported
) {
868 wpa_printf(MSG_INFO
, "nl80211: Driver does not support "
869 "authentication/association or connect commands");
873 if (info
->p2p_go_supported
&& info
->p2p_client_supported
)
874 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_P2P_CAPABLE
;
875 if (info
->p2p_concurrent
) {
876 wpa_printf(MSG_DEBUG
, "nl80211: Use separate P2P group "
877 "interface (driver advertised support)");
878 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_P2P_CONCURRENT
;
879 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P
;
881 if (info
->num_multichan_concurrent
> 1) {
882 wpa_printf(MSG_DEBUG
, "nl80211: Enable multi-channel "
883 "concurrent (driver advertised support)");
884 drv
->capa
.num_multichan_concurrent
=
885 info
->num_multichan_concurrent
;
887 if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE
)
888 wpa_printf(MSG_DEBUG
, "nl80211: use P2P_DEVICE support");
890 /* default to 5000 since early versions of mac80211 don't set it */
891 if (!drv
->capa
.max_remain_on_chan
)
892 drv
->capa
.max_remain_on_chan
= 5000;
894 drv
->capa
.wmm_ac_supported
= info
->wmm_ac_supported
;
896 drv
->capa
.mac_addr_rand_sched_scan_supported
=
897 info
->mac_addr_rand_sched_scan_supported
;
898 drv
->capa
.mac_addr_rand_scan_supported
=
899 info
->mac_addr_rand_scan_supported
;
901 if (info
->channel_switch_supported
) {
902 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_AP_CSA
;
903 if (!drv
->capa
.max_csa_counters
)
904 drv
->capa
.max_csa_counters
= 1;
907 if (!drv
->capa
.max_sched_scan_plans
) {
908 drv
->capa
.max_sched_scan_plans
= 1;
909 drv
->capa
.max_sched_scan_plan_interval
= UINT32_MAX
;
910 drv
->capa
.max_sched_scan_plan_iterations
= 0;
913 if (info
->update_ft_ies_supported
)
914 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_UPDATE_FT_IES
;
920 #ifdef CONFIG_DRIVER_NL80211_QCA
922 static int dfs_info_handler(struct nl_msg
*msg
, void *arg
)
924 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
925 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
926 int *dfs_capability_ptr
= arg
;
928 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
929 genlmsg_attrlen(gnlh
, 0), NULL
);
931 if (tb
[NL80211_ATTR_VENDOR_DATA
]) {
932 struct nlattr
*nl_vend
= tb
[NL80211_ATTR_VENDOR_DATA
];
933 struct nlattr
*tb_vendor
[QCA_WLAN_VENDOR_ATTR_MAX
+ 1];
935 nla_parse(tb_vendor
, QCA_WLAN_VENDOR_ATTR_MAX
,
936 nla_data(nl_vend
), nla_len(nl_vend
), NULL
);
938 if (tb_vendor
[QCA_WLAN_VENDOR_ATTR_DFS
]) {
940 val
= nla_get_u32(tb_vendor
[QCA_WLAN_VENDOR_ATTR_DFS
]);
941 wpa_printf(MSG_DEBUG
, "nl80211: DFS offload capability: %u",
943 *dfs_capability_ptr
= val
;
951 static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data
*drv
)
954 int dfs_capability
= 0;
957 if (!drv
->dfs_vendor_cmd_avail
)
960 if (!(msg
= nl80211_drv_msg(drv
, 0, NL80211_CMD_VENDOR
)) ||
961 nla_put_u32(msg
, NL80211_ATTR_VENDOR_ID
, OUI_QCA
) ||
962 nla_put_u32(msg
, NL80211_ATTR_VENDOR_SUBCMD
,
963 QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY
)) {
968 ret
= send_and_recv_msgs(drv
, msg
, dfs_info_handler
, &dfs_capability
);
969 if (!ret
&& dfs_capability
)
970 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_DFS_OFFLOAD
;
974 static unsigned int get_akm_suites_info(struct nlattr
*tb
)
977 unsigned int key_mgmt
= 0;
983 num
= nla_len(tb
) / sizeof(u32
);
985 for (i
= 0; i
< num
; i
++) {
988 wpa_printf(MSG_DEBUG
,
989 "nl80211: Supported AKM %02x-%02x-%02x:%u",
990 a
>> 24, (a
>> 16) & 0xff,
991 (a
>> 8) & 0xff, a
& 0xff);
993 case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X
:
994 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_WPA
|
995 WPA_DRIVER_CAPA_KEY_MGMT_WPA2
;
997 case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X
:
998 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK
|
999 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK
;
1001 case RSN_AUTH_KEY_MGMT_FT_802_1X
:
1002 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FT
;
1004 case RSN_AUTH_KEY_MGMT_FT_PSK
:
1005 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK
;
1007 case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B
:
1008 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B
;
1010 case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192
:
1011 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192
;
1013 case RSN_AUTH_KEY_MGMT_OWE
:
1014 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_OWE
;
1016 case RSN_AUTH_KEY_MGMT_DPP
:
1017 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_DPP
;
1019 case RSN_AUTH_KEY_MGMT_FILS_SHA256
:
1020 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256
;
1022 case RSN_AUTH_KEY_MGMT_FILS_SHA384
:
1023 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384
;
1025 case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256
:
1026 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256
;
1028 case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384
:
1029 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384
;
1031 case RSN_AUTH_KEY_MGMT_SAE
:
1032 key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_SAE
;
1041 static int get_akm_suites_handler(struct nl_msg
*msg
, void *arg
)
1043 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1044 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1045 unsigned int *key_mgmt
= arg
;
1047 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1048 genlmsg_attrlen(gnlh
, 0), NULL
);
1050 if (tb
[NL80211_ATTR_VENDOR_DATA
]) {
1051 struct nlattr
*nl_vend
= tb
[NL80211_ATTR_VENDOR_DATA
];
1052 struct nlattr
*tb_data
[NL80211_ATTR_MAX
+ 1];
1054 nla_parse(tb_data
, NL80211_ATTR_MAX
,
1055 nla_data(nl_vend
), nla_len(nl_vend
), NULL
);
1058 get_akm_suites_info(tb_data
[NL80211_ATTR_AKM_SUITES
]);
1065 static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data
*drv
)
1068 unsigned int key_mgmt
= 0;
1071 if (!drv
->get_supported_akm_suites_avail
)
1074 if (!(msg
= nl80211_drv_msg(drv
, 0, NL80211_CMD_VENDOR
)) ||
1075 nla_put_u32(msg
, NL80211_ATTR_VENDOR_ID
, OUI_QCA
) ||
1076 nla_put_u32(msg
, NL80211_ATTR_VENDOR_SUBCMD
,
1077 QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS
)) {
1082 ret
= send_and_recv_msgs(drv
, msg
, get_akm_suites_handler
, &key_mgmt
);
1084 wpa_printf(MSG_DEBUG
,
1085 "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x",
1087 drv
->capa
.key_mgmt
= key_mgmt
;
1094 struct features_info
{
1097 struct wpa_driver_capa
*capa
;
1101 static int features_info_handler(struct nl_msg
*msg
, void *arg
)
1103 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1104 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1105 struct features_info
*info
= arg
;
1106 struct nlattr
*nl_vend
, *attr
;
1108 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1109 genlmsg_attrlen(gnlh
, 0), NULL
);
1111 nl_vend
= tb
[NL80211_ATTR_VENDOR_DATA
];
1113 struct nlattr
*tb_vendor
[QCA_WLAN_VENDOR_ATTR_MAX
+ 1];
1115 nla_parse(tb_vendor
, QCA_WLAN_VENDOR_ATTR_MAX
,
1116 nla_data(nl_vend
), nla_len(nl_vend
), NULL
);
1118 attr
= tb_vendor
[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS
];
1120 int len
= nla_len(attr
);
1121 info
->flags
= os_malloc(len
);
1122 if (info
->flags
!= NULL
) {
1123 os_memcpy(info
->flags
, nla_data(attr
), len
);
1124 info
->flags_len
= len
;
1127 attr
= tb_vendor
[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA
];
1129 info
->capa
->conc_capab
= nla_get_u32(attr
);
1132 QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND
];
1134 info
->capa
->max_conc_chan_2_4
= nla_get_u32(attr
);
1137 QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND
];
1139 info
->capa
->max_conc_chan_5_0
= nla_get_u32(attr
);
1146 static int check_feature(enum qca_wlan_vendor_features feature
,
1147 struct features_info
*info
)
1149 size_t idx
= feature
/ 8;
1151 return (idx
< info
->flags_len
) &&
1152 (info
->flags
[idx
] & BIT(feature
% 8));
1156 static void qca_nl80211_get_features(struct wpa_driver_nl80211_data
*drv
)
1159 struct features_info info
;
1162 if (!drv
->get_features_vendor_cmd_avail
)
1165 if (!(msg
= nl80211_drv_msg(drv
, 0, NL80211_CMD_VENDOR
)) ||
1166 nla_put_u32(msg
, NL80211_ATTR_VENDOR_ID
, OUI_QCA
) ||
1167 nla_put_u32(msg
, NL80211_ATTR_VENDOR_SUBCMD
,
1168 QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES
)) {
1173 os_memset(&info
, 0, sizeof(info
));
1174 info
.capa
= &drv
->capa
;
1175 ret
= send_and_recv_msgs(drv
, msg
, features_info_handler
, &info
);
1176 if (ret
|| !info
.flags
)
1179 if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD
, &info
))
1180 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD
;
1182 if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY
, &info
))
1183 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY
;
1185 if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS
,
1187 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS
;
1188 if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD
, &info
))
1189 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD
;
1190 if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA
, &info
))
1191 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_OCE_STA
;
1192 if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_AP
, &info
))
1193 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_OCE_AP
;
1194 if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON
, &info
))
1195 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_OCE_STA_CFON
;
1196 os_free(info
.flags
);
1199 #endif /* CONFIG_DRIVER_NL80211_QCA */
1202 int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data
*drv
)
1204 struct wiphy_info_data info
;
1205 if (wpa_driver_nl80211_get_info(drv
, &info
))
1211 drv
->has_capability
= 1;
1212 drv
->capa
.key_mgmt
= WPA_DRIVER_CAPA_KEY_MGMT_WPA
|
1213 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK
|
1214 WPA_DRIVER_CAPA_KEY_MGMT_WPA2
|
1215 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK
|
1216 WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B
|
1217 WPA_DRIVER_CAPA_KEY_MGMT_OWE
|
1218 WPA_DRIVER_CAPA_KEY_MGMT_DPP
;
1220 if (drv
->capa
.enc
& (WPA_DRIVER_CAPA_ENC_CCMP_256
|
1221 WPA_DRIVER_CAPA_ENC_GCMP_256
))
1222 drv
->capa
.key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192
;
1224 if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
)
1225 drv
->capa
.key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256
|
1226 WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384
|
1227 WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256
|
1228 WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384
|
1229 WPA_DRIVER_CAPA_KEY_MGMT_SAE
;
1230 else if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD
)
1231 drv
->capa
.key_mgmt
|= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256
|
1232 WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384
;
1234 #ifdef CONFIG_DRIVER_NL80211_QCA
1235 /* Override drv->capa.key_mgmt based on driver advertised capability
1236 * constraints, if available. */
1237 qca_nl80211_get_akm_suites(drv
);
1238 #endif /* CONFIG_DRIVER_NL80211_QCA */
1240 drv
->capa
.auth
= WPA_DRIVER_AUTH_OPEN
|
1241 WPA_DRIVER_AUTH_SHARED
|
1242 WPA_DRIVER_AUTH_LEAP
;
1244 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_SANE_ERROR_CODES
;
1245 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE
;
1246 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS
;
1249 * As all cfg80211 drivers must support cases where the AP interface is
1250 * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
1251 * case that the user space daemon has crashed, they must be able to
1252 * cleanup all stations and key entries in the AP tear down flow. Thus,
1253 * this flag can/should always be set for cfg80211 drivers.
1255 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT
;
1257 if (!info
.device_ap_sme
) {
1258 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS
;
1261 * No AP SME is currently assumed to also indicate no AP MLME
1262 * in the driver/firmware.
1264 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_AP_MLME
;
1267 drv
->device_ap_sme
= info
.device_ap_sme
;
1268 drv
->poll_command_supported
= info
.poll_command_supported
;
1269 drv
->data_tx_status
= info
.data_tx_status
;
1270 drv
->p2p_go_ctwindow_supported
= info
.p2p_go_ctwindow_supported
;
1271 if (info
.set_qos_map_supported
)
1272 drv
->capa
.flags
|= WPA_DRIVER_FLAGS_QOS_MAPPING
;
1273 drv
->have_low_prio_scan
= info
.have_low_prio_scan
;
1276 * If poll command and tx status are supported, mac80211 is new enough
1277 * to have everything we need to not need monitor interfaces.
1279 drv
->use_monitor
= !info
.device_ap_sme
&&
1280 (!info
.poll_command_supported
|| !info
.data_tx_status
);
1283 * If we aren't going to use monitor interfaces, but the
1284 * driver doesn't support data TX status, we won't get TX
1285 * status for EAPOL frames.
1287 if (!drv
->use_monitor
&& !info
.data_tx_status
)
1288 drv
->capa
.flags
&= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS
;
1290 #ifdef CONFIG_DRIVER_NL80211_QCA
1291 if (!(info
.capa
->flags
& WPA_DRIVER_FLAGS_DFS_OFFLOAD
))
1292 qca_nl80211_check_dfs_capa(drv
);
1293 qca_nl80211_get_features(drv
);
1296 * To enable offchannel simultaneous support in wpa_supplicant, the
1297 * underlying driver needs to support the same along with offchannel TX.
1298 * Offchannel TX support is needed since remain_on_channel and
1299 * action_tx use some common data structures and hence cannot be
1300 * scheduled simultaneously.
1302 if (!(drv
->capa
.flags
& WPA_DRIVER_FLAGS_OFFCHANNEL_TX
))
1303 drv
->capa
.flags
&= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS
;
1304 #endif /* CONFIG_DRIVER_NL80211_QCA */
1310 struct phy_info_arg
{
1312 struct hostapd_hw_modes
*modes
;
1313 int last_mode
, last_chan_idx
;
1318 static void phy_info_ht_capa(struct hostapd_hw_modes
*mode
, struct nlattr
*capa
,
1319 struct nlattr
*ampdu_factor
,
1320 struct nlattr
*ampdu_density
,
1321 struct nlattr
*mcs_set
)
1324 mode
->ht_capab
= nla_get_u16(capa
);
1327 mode
->a_mpdu_params
|= nla_get_u8(ampdu_factor
) & 0x03;
1330 mode
->a_mpdu_params
|= nla_get_u8(ampdu_density
) << 2;
1332 if (mcs_set
&& nla_len(mcs_set
) >= 16) {
1334 mcs
= nla_data(mcs_set
);
1335 os_memcpy(mode
->mcs_set
, mcs
, 16);
1340 static void phy_info_vht_capa(struct hostapd_hw_modes
*mode
,
1341 struct nlattr
*capa
,
1342 struct nlattr
*mcs_set
)
1345 mode
->vht_capab
= nla_get_u32(capa
);
1347 if (mcs_set
&& nla_len(mcs_set
) >= 8) {
1349 mcs
= nla_data(mcs_set
);
1350 os_memcpy(mode
->vht_mcs_set
, mcs
, 8);
1355 static int phy_info_edmg_capa(struct hostapd_hw_modes
*mode
,
1356 struct nlattr
*bw_config
,
1357 struct nlattr
*channels
)
1359 if (!bw_config
|| !channels
)
1362 mode
->edmg
.bw_config
= nla_get_u8(bw_config
);
1363 mode
->edmg
.channels
= nla_get_u8(channels
);
1365 if (!mode
->edmg
.channels
|| !mode
->edmg
.bw_config
)
1372 static int cw2ecw(unsigned int cw
)
1379 for (bit
= 1; cw
!= 1; bit
++)
1386 static void phy_info_freq(struct hostapd_hw_modes
*mode
,
1387 struct hostapd_channel_data
*chan
,
1388 struct nlattr
*tb_freq
[])
1392 os_memset(chan
, 0, sizeof(*chan
));
1393 chan
->freq
= nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
]);
1395 chan
->allowed_bw
= ~0;
1396 chan
->dfs_cac_ms
= 0;
1397 if (ieee80211_freq_to_chan(chan
->freq
, &channel
) != NUM_HOSTAPD_MODES
)
1398 chan
->chan
= channel
;
1400 wpa_printf(MSG_DEBUG
,
1401 "nl80211: No channel number found for frequency %u MHz",
1404 if (tb_freq
[NL80211_FREQUENCY_ATTR_DISABLED
])
1405 chan
->flag
|= HOSTAPD_CHAN_DISABLED
;
1406 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_IR
])
1407 chan
->flag
|= HOSTAPD_CHAN_NO_IR
;
1408 if (tb_freq
[NL80211_FREQUENCY_ATTR_RADAR
])
1409 chan
->flag
|= HOSTAPD_CHAN_RADAR
;
1410 if (tb_freq
[NL80211_FREQUENCY_ATTR_INDOOR_ONLY
])
1411 chan
->flag
|= HOSTAPD_CHAN_INDOOR_ONLY
;
1412 if (tb_freq
[NL80211_FREQUENCY_ATTR_GO_CONCURRENT
])
1413 chan
->flag
|= HOSTAPD_CHAN_GO_CONCURRENT
;
1415 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_10MHZ
])
1416 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_10
;
1417 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_20MHZ
])
1418 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_20
;
1419 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS
])
1420 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_40P
;
1421 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS
])
1422 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_40M
;
1423 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_80MHZ
])
1424 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_80
;
1425 if (tb_freq
[NL80211_FREQUENCY_ATTR_NO_160MHZ
])
1426 chan
->allowed_bw
&= ~HOSTAPD_CHAN_WIDTH_160
;
1428 if (tb_freq
[NL80211_FREQUENCY_ATTR_DFS_STATE
]) {
1429 enum nl80211_dfs_state state
=
1430 nla_get_u32(tb_freq
[NL80211_FREQUENCY_ATTR_DFS_STATE
]);
1433 case NL80211_DFS_USABLE
:
1434 chan
->flag
|= HOSTAPD_CHAN_DFS_USABLE
;
1436 case NL80211_DFS_AVAILABLE
:
1437 chan
->flag
|= HOSTAPD_CHAN_DFS_AVAILABLE
;
1439 case NL80211_DFS_UNAVAILABLE
:
1440 chan
->flag
|= HOSTAPD_CHAN_DFS_UNAVAILABLE
;
1445 if (tb_freq
[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME
]) {
1446 chan
->dfs_cac_ms
= nla_get_u32(
1447 tb_freq
[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME
]);
1450 chan
->wmm_rules_valid
= 0;
1451 if (tb_freq
[NL80211_FREQUENCY_ATTR_WMM
]) {
1452 static struct nla_policy wmm_policy
[NL80211_WMMR_MAX
+ 1] = {
1453 [NL80211_WMMR_CW_MIN
] = { .type
= NLA_U16
},
1454 [NL80211_WMMR_CW_MAX
] = { .type
= NLA_U16
},
1455 [NL80211_WMMR_AIFSN
] = { .type
= NLA_U8
},
1456 [NL80211_WMMR_TXOP
] = { .type
= NLA_U16
},
1458 static const u8 wmm_map
[4] = {
1459 [NL80211_AC_BE
] = WMM_AC_BE
,
1460 [NL80211_AC_BK
] = WMM_AC_BK
,
1461 [NL80211_AC_VI
] = WMM_AC_VI
,
1462 [NL80211_AC_VO
] = WMM_AC_VO
,
1464 struct nlattr
*nl_wmm
;
1465 struct nlattr
*tb_wmm
[NL80211_WMMR_MAX
+ 1];
1466 int rem_wmm
, ac
, count
= 0;
1468 nla_for_each_nested(nl_wmm
, tb_freq
[NL80211_FREQUENCY_ATTR_WMM
],
1470 if (nla_parse_nested(tb_wmm
, NL80211_WMMR_MAX
, nl_wmm
,
1472 wpa_printf(MSG_DEBUG
,
1473 "nl80211: Failed to parse WMM rules attribute");
1476 if (!tb_wmm
[NL80211_WMMR_CW_MIN
] ||
1477 !tb_wmm
[NL80211_WMMR_CW_MAX
] ||
1478 !tb_wmm
[NL80211_WMMR_AIFSN
] ||
1479 !tb_wmm
[NL80211_WMMR_TXOP
]) {
1480 wpa_printf(MSG_DEBUG
,
1481 "nl80211: Channel is missing WMM rule attribute");
1484 ac
= nl_wmm
->nla_type
;
1485 if ((unsigned int) ac
>= ARRAY_SIZE(wmm_map
)) {
1486 wpa_printf(MSG_DEBUG
,
1487 "nl80211: Invalid AC value %d", ac
);
1492 chan
->wmm_rules
[ac
].min_cwmin
=
1494 tb_wmm
[NL80211_WMMR_CW_MIN
]));
1495 chan
->wmm_rules
[ac
].min_cwmax
=
1497 tb_wmm
[NL80211_WMMR_CW_MAX
]));
1498 chan
->wmm_rules
[ac
].min_aifs
=
1499 nla_get_u8(tb_wmm
[NL80211_WMMR_AIFSN
]);
1500 chan
->wmm_rules
[ac
].max_txop
=
1501 nla_get_u16(tb_wmm
[NL80211_WMMR_TXOP
]) / 32;
1505 /* Set valid flag if all the AC rules are present */
1506 if (count
== WMM_AC_NUM
)
1507 chan
->wmm_rules_valid
= 1;
1512 static int phy_info_freqs(struct phy_info_arg
*phy_info
,
1513 struct hostapd_hw_modes
*mode
, struct nlattr
*tb
)
1515 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
1516 [NL80211_FREQUENCY_ATTR_FREQ
] = { .type
= NLA_U32
},
1517 [NL80211_FREQUENCY_ATTR_DISABLED
] = { .type
= NLA_FLAG
},
1518 [NL80211_FREQUENCY_ATTR_NO_IR
] = { .type
= NLA_FLAG
},
1519 [NL80211_FREQUENCY_ATTR_RADAR
] = { .type
= NLA_FLAG
},
1520 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] = { .type
= NLA_U32
},
1521 [NL80211_FREQUENCY_ATTR_DFS_STATE
] = { .type
= NLA_U32
},
1522 [NL80211_FREQUENCY_ATTR_NO_10MHZ
] = { .type
= NLA_FLAG
},
1523 [NL80211_FREQUENCY_ATTR_NO_20MHZ
] = { .type
= NLA_FLAG
},
1524 [NL80211_FREQUENCY_ATTR_NO_HT40_PLUS
] = { .type
= NLA_FLAG
},
1525 [NL80211_FREQUENCY_ATTR_NO_HT40_MINUS
] = { .type
= NLA_FLAG
},
1526 [NL80211_FREQUENCY_ATTR_NO_80MHZ
] = { .type
= NLA_FLAG
},
1527 [NL80211_FREQUENCY_ATTR_NO_160MHZ
] = { .type
= NLA_FLAG
},
1529 int new_channels
= 0;
1530 struct hostapd_channel_data
*channel
;
1531 struct nlattr
*tb_freq
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
1532 struct nlattr
*nl_freq
;
1538 nla_for_each_nested(nl_freq
, tb
, rem_freq
) {
1539 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
,
1540 nla_data(nl_freq
), nla_len(nl_freq
), freq_policy
);
1541 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
1546 channel
= os_realloc_array(mode
->channels
,
1547 mode
->num_channels
+ new_channels
,
1548 sizeof(struct hostapd_channel_data
));
1552 mode
->channels
= channel
;
1553 mode
->num_channels
+= new_channels
;
1555 idx
= phy_info
->last_chan_idx
;
1557 nla_for_each_nested(nl_freq
, tb
, rem_freq
) {
1558 nla_parse(tb_freq
, NL80211_FREQUENCY_ATTR_MAX
,
1559 nla_data(nl_freq
), nla_len(nl_freq
), freq_policy
);
1560 if (!tb_freq
[NL80211_FREQUENCY_ATTR_FREQ
])
1562 phy_info_freq(mode
, &mode
->channels
[idx
], tb_freq
);
1565 phy_info
->last_chan_idx
= idx
;
1571 static int phy_info_rates(struct hostapd_hw_modes
*mode
, struct nlattr
*tb
)
1573 static struct nla_policy rate_policy
[NL80211_BITRATE_ATTR_MAX
+ 1] = {
1574 [NL80211_BITRATE_ATTR_RATE
] = { .type
= NLA_U32
},
1575 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE
] =
1576 { .type
= NLA_FLAG
},
1578 struct nlattr
*tb_rate
[NL80211_BITRATE_ATTR_MAX
+ 1];
1579 struct nlattr
*nl_rate
;
1585 nla_for_each_nested(nl_rate
, tb
, rem_rate
) {
1586 nla_parse(tb_rate
, NL80211_BITRATE_ATTR_MAX
,
1587 nla_data(nl_rate
), nla_len(nl_rate
),
1589 if (!tb_rate
[NL80211_BITRATE_ATTR_RATE
])
1594 mode
->rates
= os_calloc(mode
->num_rates
, sizeof(int));
1600 nla_for_each_nested(nl_rate
, tb
, rem_rate
) {
1601 nla_parse(tb_rate
, NL80211_BITRATE_ATTR_MAX
,
1602 nla_data(nl_rate
), nla_len(nl_rate
),
1604 if (!tb_rate
[NL80211_BITRATE_ATTR_RATE
])
1606 mode
->rates
[idx
] = nla_get_u32(
1607 tb_rate
[NL80211_BITRATE_ATTR_RATE
]);
1615 static void phy_info_iftype_copy(struct he_capabilities
*he_capab
,
1616 enum ieee80211_op_mode opmode
,
1617 struct nlattr
**tb
, struct nlattr
**tb_flags
)
1619 enum nl80211_iftype iftype
;
1623 case IEEE80211_MODE_INFRA
:
1624 iftype
= NL80211_IFTYPE_STATION
;
1626 case IEEE80211_MODE_IBSS
:
1627 iftype
= NL80211_IFTYPE_ADHOC
;
1629 case IEEE80211_MODE_AP
:
1630 iftype
= NL80211_IFTYPE_AP
;
1632 case IEEE80211_MODE_MESH
:
1633 iftype
= NL80211_IFTYPE_MESH_POINT
;
1639 if (!nla_get_flag(tb_flags
[iftype
]))
1642 he_capab
->he_supported
= 1;
1644 if (tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY
]) {
1645 len
= nla_len(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY
]);
1647 if (len
> sizeof(he_capab
->phy_cap
))
1648 len
= sizeof(he_capab
->phy_cap
);
1649 os_memcpy(he_capab
->phy_cap
,
1650 nla_data(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY
]),
1654 if (tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC
]) {
1655 len
= nla_len(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC
]);
1657 if (len
> sizeof(he_capab
->mac_cap
))
1658 len
= sizeof(he_capab
->mac_cap
);
1659 os_memcpy(he_capab
->mac_cap
,
1660 nla_data(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC
]),
1664 if (tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET
]) {
1665 len
= nla_len(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET
]);
1667 if (len
> sizeof(he_capab
->mcs
))
1668 len
= sizeof(he_capab
->mcs
);
1669 os_memcpy(he_capab
->mcs
,
1670 nla_data(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET
]),
1674 if (tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE
]) {
1675 len
= nla_len(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE
]);
1677 if (len
> sizeof(he_capab
->ppet
))
1678 len
= sizeof(he_capab
->ppet
);
1679 os_memcpy(&he_capab
->ppet
,
1680 nla_data(tb
[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE
]),
1686 static int phy_info_iftype(struct hostapd_hw_modes
*mode
,
1687 struct nlattr
*nl_iftype
)
1689 struct nlattr
*tb
[NL80211_BAND_IFTYPE_ATTR_MAX
+ 1];
1690 struct nlattr
*tb_flags
[NL80211_IFTYPE_MAX
+ 1];
1693 nla_parse(tb
, NL80211_BAND_IFTYPE_ATTR_MAX
,
1694 nla_data(nl_iftype
), nla_len(nl_iftype
), NULL
);
1696 if (!tb
[NL80211_BAND_IFTYPE_ATTR_IFTYPES
])
1699 if (nla_parse_nested(tb_flags
, NL80211_IFTYPE_MAX
,
1700 tb
[NL80211_BAND_IFTYPE_ATTR_IFTYPES
], NULL
))
1703 for (i
= 0; i
< IEEE80211_MODE_NUM
; i
++)
1704 phy_info_iftype_copy(&mode
->he_capab
[i
], i
, tb
, tb_flags
);
1710 static int phy_info_band(struct phy_info_arg
*phy_info
, struct nlattr
*nl_band
)
1712 struct nlattr
*tb_band
[NL80211_BAND_ATTR_MAX
+ 1];
1713 struct hostapd_hw_modes
*mode
;
1716 if (phy_info
->last_mode
!= nl_band
->nla_type
) {
1717 mode
= os_realloc_array(phy_info
->modes
,
1718 *phy_info
->num_modes
+ 1,
1721 phy_info
->failed
= 1;
1724 phy_info
->modes
= mode
;
1726 mode
= &phy_info
->modes
[*(phy_info
->num_modes
)];
1727 os_memset(mode
, 0, sizeof(*mode
));
1728 mode
->mode
= NUM_HOSTAPD_MODES
;
1729 mode
->flags
= HOSTAPD_MODE_FLAG_HT_INFO_KNOWN
|
1730 HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN
;
1733 * Unsupported VHT MCS stream is defined as value 3, so the VHT
1734 * MCS RX/TX map must be initialized with 0xffff to mark all 8
1735 * possible streams as unsupported. This will be overridden if
1736 * driver advertises VHT support.
1738 mode
->vht_mcs_set
[0] = 0xff;
1739 mode
->vht_mcs_set
[1] = 0xff;
1740 mode
->vht_mcs_set
[4] = 0xff;
1741 mode
->vht_mcs_set
[5] = 0xff;
1743 *(phy_info
->num_modes
) += 1;
1744 phy_info
->last_mode
= nl_band
->nla_type
;
1745 phy_info
->last_chan_idx
= 0;
1747 mode
= &phy_info
->modes
[*(phy_info
->num_modes
) - 1];
1749 nla_parse(tb_band
, NL80211_BAND_ATTR_MAX
, nla_data(nl_band
),
1750 nla_len(nl_band
), NULL
);
1752 phy_info_ht_capa(mode
, tb_band
[NL80211_BAND_ATTR_HT_CAPA
],
1753 tb_band
[NL80211_BAND_ATTR_HT_AMPDU_FACTOR
],
1754 tb_band
[NL80211_BAND_ATTR_HT_AMPDU_DENSITY
],
1755 tb_band
[NL80211_BAND_ATTR_HT_MCS_SET
]);
1756 phy_info_vht_capa(mode
, tb_band
[NL80211_BAND_ATTR_VHT_CAPA
],
1757 tb_band
[NL80211_BAND_ATTR_VHT_MCS_SET
]);
1758 ret
= phy_info_edmg_capa(mode
,
1759 tb_band
[NL80211_BAND_ATTR_EDMG_BW_CONFIG
],
1760 tb_band
[NL80211_BAND_ATTR_EDMG_CHANNELS
]);
1762 ret
= phy_info_freqs(phy_info
, mode
,
1763 tb_band
[NL80211_BAND_ATTR_FREQS
]);
1765 ret
= phy_info_rates(mode
, tb_band
[NL80211_BAND_ATTR_RATES
]);
1767 phy_info
->failed
= 1;
1771 if (tb_band
[NL80211_BAND_ATTR_IFTYPE_DATA
]) {
1772 struct nlattr
*nl_iftype
;
1775 nla_for_each_nested(nl_iftype
,
1776 tb_band
[NL80211_BAND_ATTR_IFTYPE_DATA
],
1778 ret
= phy_info_iftype(mode
, nl_iftype
);
1788 static int phy_info_handler(struct nl_msg
*msg
, void *arg
)
1790 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
1791 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1792 struct phy_info_arg
*phy_info
= arg
;
1793 struct nlattr
*nl_band
;
1796 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1797 genlmsg_attrlen(gnlh
, 0), NULL
);
1799 if (!tb_msg
[NL80211_ATTR_WIPHY_BANDS
])
1802 nla_for_each_nested(nl_band
, tb_msg
[NL80211_ATTR_WIPHY_BANDS
], rem_band
)
1804 int res
= phy_info_band(phy_info
, nl_band
);
1813 static struct hostapd_hw_modes
*
1814 wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes
*modes
,
1818 struct hostapd_hw_modes
*mode11g
= NULL
, *nmodes
, *mode
;
1819 int i
, mode11g_idx
= -1;
1821 /* heuristic to set up modes */
1822 for (m
= 0; m
< *num_modes
; m
++) {
1823 if (!modes
[m
].num_channels
)
1825 if (modes
[m
].channels
[0].freq
< 4000) {
1826 modes
[m
].mode
= HOSTAPD_MODE_IEEE80211B
;
1827 for (i
= 0; i
< modes
[m
].num_rates
; i
++) {
1828 if (modes
[m
].rates
[i
] > 200) {
1829 modes
[m
].mode
= HOSTAPD_MODE_IEEE80211G
;
1833 } else if (modes
[m
].channels
[0].freq
> 50000)
1834 modes
[m
].mode
= HOSTAPD_MODE_IEEE80211AD
;
1836 modes
[m
].mode
= HOSTAPD_MODE_IEEE80211A
;
1839 /* If only 802.11g mode is included, use it to construct matching
1840 * 802.11b mode data. */
1842 for (m
= 0; m
< *num_modes
; m
++) {
1843 if (modes
[m
].mode
== HOSTAPD_MODE_IEEE80211B
)
1844 return modes
; /* 802.11b already included */
1845 if (modes
[m
].mode
== HOSTAPD_MODE_IEEE80211G
)
1849 if (mode11g_idx
< 0)
1850 return modes
; /* 2.4 GHz band not supported at all */
1852 nmodes
= os_realloc_array(modes
, *num_modes
+ 1, sizeof(*nmodes
));
1854 return modes
; /* Could not add 802.11b mode */
1856 mode
= &nmodes
[*num_modes
];
1857 os_memset(mode
, 0, sizeof(*mode
));
1861 mode
->mode
= HOSTAPD_MODE_IEEE80211B
;
1863 mode11g
= &modes
[mode11g_idx
];
1864 mode
->num_channels
= mode11g
->num_channels
;
1865 mode
->channels
= os_memdup(mode11g
->channels
,
1866 mode11g
->num_channels
*
1867 sizeof(struct hostapd_channel_data
));
1868 if (mode
->channels
== NULL
) {
1870 return modes
; /* Could not add 802.11b mode */
1873 mode
->num_rates
= 0;
1874 mode
->rates
= os_malloc(4 * sizeof(int));
1875 if (mode
->rates
== NULL
) {
1876 os_free(mode
->channels
);
1878 return modes
; /* Could not add 802.11b mode */
1881 for (i
= 0; i
< mode11g
->num_rates
; i
++) {
1882 if (mode11g
->rates
[i
] != 10 && mode11g
->rates
[i
] != 20 &&
1883 mode11g
->rates
[i
] != 55 && mode11g
->rates
[i
] != 110)
1885 mode
->rates
[mode
->num_rates
] = mode11g
->rates
[i
];
1887 if (mode
->num_rates
== 4)
1891 if (mode
->num_rates
== 0) {
1892 os_free(mode
->channels
);
1893 os_free(mode
->rates
);
1895 return modes
; /* No 802.11b rates */
1898 wpa_printf(MSG_DEBUG
, "nl80211: Added 802.11b mode based on 802.11g "
1905 static void nl80211_set_ht40_mode(struct hostapd_hw_modes
*mode
, int start
,
1910 for (c
= 0; c
< mode
->num_channels
; c
++) {
1911 struct hostapd_channel_data
*chan
= &mode
->channels
[c
];
1912 if (chan
->freq
- 10 >= start
&& chan
->freq
+ 10 <= end
)
1913 chan
->flag
|= HOSTAPD_CHAN_HT40
;
1918 static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes
*mode
, int start
,
1923 for (c
= 0; c
< mode
->num_channels
; c
++) {
1924 struct hostapd_channel_data
*chan
= &mode
->channels
[c
];
1925 if (!(chan
->flag
& HOSTAPD_CHAN_HT40
))
1927 if (chan
->freq
- 30 >= start
&& chan
->freq
- 10 <= end
)
1928 chan
->flag
|= HOSTAPD_CHAN_HT40MINUS
;
1929 if (chan
->freq
+ 10 >= start
&& chan
->freq
+ 30 <= end
)
1930 chan
->flag
|= HOSTAPD_CHAN_HT40PLUS
;
1935 static void nl80211_reg_rule_max_eirp(u32 start
, u32 end
, u32 max_eirp
,
1936 struct phy_info_arg
*results
)
1940 for (m
= 0; m
< *results
->num_modes
; m
++) {
1942 struct hostapd_hw_modes
*mode
= &results
->modes
[m
];
1944 for (c
= 0; c
< mode
->num_channels
; c
++) {
1945 struct hostapd_channel_data
*chan
= &mode
->channels
[c
];
1946 if ((u32
) chan
->freq
- 10 >= start
&&
1947 (u32
) chan
->freq
+ 10 <= end
)
1948 chan
->max_tx_power
= max_eirp
;
1954 static void nl80211_reg_rule_ht40(u32 start
, u32 end
,
1955 struct phy_info_arg
*results
)
1959 for (m
= 0; m
< *results
->num_modes
; m
++) {
1960 if (!(results
->modes
[m
].ht_capab
&
1961 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
))
1963 nl80211_set_ht40_mode(&results
->modes
[m
], start
, end
);
1968 static void nl80211_reg_rule_sec(struct nlattr
*tb
[],
1969 struct phy_info_arg
*results
)
1971 u32 start
, end
, max_bw
;
1974 if (tb
[NL80211_ATTR_FREQ_RANGE_START
] == NULL
||
1975 tb
[NL80211_ATTR_FREQ_RANGE_END
] == NULL
||
1976 tb
[NL80211_ATTR_FREQ_RANGE_MAX_BW
] == NULL
)
1979 start
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_START
]) / 1000;
1980 end
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_END
]) / 1000;
1981 max_bw
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]) / 1000;
1986 for (m
= 0; m
< *results
->num_modes
; m
++) {
1987 if (!(results
->modes
[m
].ht_capab
&
1988 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
))
1990 nl80211_set_ht40_mode_sec(&results
->modes
[m
], start
, end
);
1995 static void nl80211_set_vht_mode(struct hostapd_hw_modes
*mode
, int start
,
1996 int end
, int max_bw
)
2000 for (c
= 0; c
< mode
->num_channels
; c
++) {
2001 struct hostapd_channel_data
*chan
= &mode
->channels
[c
];
2002 if (chan
->freq
- 10 >= start
&& chan
->freq
+ 70 <= end
)
2003 chan
->flag
|= HOSTAPD_CHAN_VHT_10_70
;
2005 if (chan
->freq
- 30 >= start
&& chan
->freq
+ 50 <= end
)
2006 chan
->flag
|= HOSTAPD_CHAN_VHT_30_50
;
2008 if (chan
->freq
- 50 >= start
&& chan
->freq
+ 30 <= end
)
2009 chan
->flag
|= HOSTAPD_CHAN_VHT_50_30
;
2011 if (chan
->freq
- 70 >= start
&& chan
->freq
+ 10 <= end
)
2012 chan
->flag
|= HOSTAPD_CHAN_VHT_70_10
;
2014 if (max_bw
>= 160) {
2015 if (chan
->freq
- 10 >= start
&& chan
->freq
+ 150 <= end
)
2016 chan
->flag
|= HOSTAPD_CHAN_VHT_10_150
;
2018 if (chan
->freq
- 30 >= start
&& chan
->freq
+ 130 <= end
)
2019 chan
->flag
|= HOSTAPD_CHAN_VHT_30_130
;
2021 if (chan
->freq
- 50 >= start
&& chan
->freq
+ 110 <= end
)
2022 chan
->flag
|= HOSTAPD_CHAN_VHT_50_110
;
2024 if (chan
->freq
- 70 >= start
&& chan
->freq
+ 90 <= end
)
2025 chan
->flag
|= HOSTAPD_CHAN_VHT_70_90
;
2027 if (chan
->freq
- 90 >= start
&& chan
->freq
+ 70 <= end
)
2028 chan
->flag
|= HOSTAPD_CHAN_VHT_90_70
;
2030 if (chan
->freq
- 110 >= start
&& chan
->freq
+ 50 <= end
)
2031 chan
->flag
|= HOSTAPD_CHAN_VHT_110_50
;
2033 if (chan
->freq
- 130 >= start
&& chan
->freq
+ 30 <= end
)
2034 chan
->flag
|= HOSTAPD_CHAN_VHT_130_30
;
2036 if (chan
->freq
- 150 >= start
&& chan
->freq
+ 10 <= end
)
2037 chan
->flag
|= HOSTAPD_CHAN_VHT_150_10
;
2043 static void nl80211_reg_rule_vht(struct nlattr
*tb
[],
2044 struct phy_info_arg
*results
)
2046 u32 start
, end
, max_bw
;
2049 if (tb
[NL80211_ATTR_FREQ_RANGE_START
] == NULL
||
2050 tb
[NL80211_ATTR_FREQ_RANGE_END
] == NULL
||
2051 tb
[NL80211_ATTR_FREQ_RANGE_MAX_BW
] == NULL
)
2054 start
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_START
]) / 1000;
2055 end
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_END
]) / 1000;
2056 max_bw
= nla_get_u32(tb
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]) / 1000;
2061 for (m
= 0; m
< *results
->num_modes
; m
++) {
2062 if (!(results
->modes
[m
].ht_capab
&
2063 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET
))
2065 /* TODO: use a real VHT support indication */
2066 if (!results
->modes
[m
].vht_capab
)
2069 nl80211_set_vht_mode(&results
->modes
[m
], start
, end
, max_bw
);
2074 static void nl80211_set_dfs_domain(enum nl80211_dfs_regions region
,
2077 if (region
== NL80211_DFS_FCC
)
2078 *dfs_domain
= HOSTAPD_DFS_REGION_FCC
;
2079 else if (region
== NL80211_DFS_ETSI
)
2080 *dfs_domain
= HOSTAPD_DFS_REGION_ETSI
;
2081 else if (region
== NL80211_DFS_JP
)
2082 *dfs_domain
= HOSTAPD_DFS_REGION_JP
;
2088 static const char * dfs_domain_name(enum nl80211_dfs_regions region
)
2091 case NL80211_DFS_UNSET
:
2093 case NL80211_DFS_FCC
:
2095 case NL80211_DFS_ETSI
:
2097 case NL80211_DFS_JP
:
2100 return "DFS-invalid";
2105 static int nl80211_get_reg(struct nl_msg
*msg
, void *arg
)
2107 struct phy_info_arg
*results
= arg
;
2108 struct nlattr
*tb_msg
[NL80211_ATTR_MAX
+ 1];
2109 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2110 struct nlattr
*nl_rule
;
2111 struct nlattr
*tb_rule
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
2113 static struct nla_policy reg_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
2114 [NL80211_ATTR_REG_RULE_FLAGS
] = { .type
= NLA_U32
},
2115 [NL80211_ATTR_FREQ_RANGE_START
] = { .type
= NLA_U32
},
2116 [NL80211_ATTR_FREQ_RANGE_END
] = { .type
= NLA_U32
},
2117 [NL80211_ATTR_FREQ_RANGE_MAX_BW
] = { .type
= NLA_U32
},
2118 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN
] = { .type
= NLA_U32
},
2119 [NL80211_ATTR_POWER_RULE_MAX_EIRP
] = { .type
= NLA_U32
},
2122 nla_parse(tb_msg
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2123 genlmsg_attrlen(gnlh
, 0), NULL
);
2124 if (!tb_msg
[NL80211_ATTR_REG_ALPHA2
] ||
2125 !tb_msg
[NL80211_ATTR_REG_RULES
]) {
2126 wpa_printf(MSG_DEBUG
, "nl80211: No regulatory information "
2131 if (tb_msg
[NL80211_ATTR_DFS_REGION
]) {
2132 enum nl80211_dfs_regions dfs_domain
;
2133 dfs_domain
= nla_get_u8(tb_msg
[NL80211_ATTR_DFS_REGION
]);
2134 nl80211_set_dfs_domain(dfs_domain
, &results
->dfs_domain
);
2135 wpa_printf(MSG_DEBUG
, "nl80211: Regulatory information - country=%s (%s)",
2136 (char *) nla_data(tb_msg
[NL80211_ATTR_REG_ALPHA2
]),
2137 dfs_domain_name(dfs_domain
));
2139 wpa_printf(MSG_DEBUG
, "nl80211: Regulatory information - country=%s",
2140 (char *) nla_data(tb_msg
[NL80211_ATTR_REG_ALPHA2
]));
2143 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
)
2145 u32 start
, end
, max_eirp
= 0, max_bw
= 0, flags
= 0;
2146 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
,
2147 nla_data(nl_rule
), nla_len(nl_rule
), reg_policy
);
2148 if (tb_rule
[NL80211_ATTR_FREQ_RANGE_START
] == NULL
||
2149 tb_rule
[NL80211_ATTR_FREQ_RANGE_END
] == NULL
)
2151 start
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_START
]) / 1000;
2152 end
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_END
]) / 1000;
2153 if (tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
])
2154 max_eirp
= nla_get_u32(tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
]) / 100;
2155 if (tb_rule
[NL80211_ATTR_FREQ_RANGE_MAX_BW
])
2156 max_bw
= nla_get_u32(tb_rule
[NL80211_ATTR_FREQ_RANGE_MAX_BW
]) / 1000;
2157 if (tb_rule
[NL80211_ATTR_REG_RULE_FLAGS
])
2158 flags
= nla_get_u32(tb_rule
[NL80211_ATTR_REG_RULE_FLAGS
]);
2160 wpa_printf(MSG_DEBUG
, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
2161 start
, end
, max_bw
, max_eirp
,
2162 flags
& NL80211_RRF_NO_OFDM
? " (no OFDM)" : "",
2163 flags
& NL80211_RRF_NO_CCK
? " (no CCK)" : "",
2164 flags
& NL80211_RRF_NO_INDOOR
? " (no indoor)" : "",
2165 flags
& NL80211_RRF_NO_OUTDOOR
? " (no outdoor)" :
2167 flags
& NL80211_RRF_DFS
? " (DFS)" : "",
2168 flags
& NL80211_RRF_PTP_ONLY
? " (PTP only)" : "",
2169 flags
& NL80211_RRF_PTMP_ONLY
? " (PTMP only)" : "",
2170 flags
& NL80211_RRF_NO_IR
? " (no IR)" : "");
2172 nl80211_reg_rule_ht40(start
, end
, results
);
2173 if (tb_rule
[NL80211_ATTR_POWER_RULE_MAX_EIRP
])
2174 nl80211_reg_rule_max_eirp(start
, end
, max_eirp
,
2178 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
)
2180 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
,
2181 nla_data(nl_rule
), nla_len(nl_rule
), reg_policy
);
2182 nl80211_reg_rule_sec(tb_rule
, results
);
2185 nla_for_each_nested(nl_rule
, tb_msg
[NL80211_ATTR_REG_RULES
], rem_rule
)
2187 nla_parse(tb_rule
, NL80211_FREQUENCY_ATTR_MAX
,
2188 nla_data(nl_rule
), nla_len(nl_rule
), reg_policy
);
2189 nl80211_reg_rule_vht(tb_rule
, results
);
2196 static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data
*drv
,
2197 struct phy_info_arg
*results
)
2201 msg
= nlmsg_alloc();
2205 nl80211_cmd(drv
, msg
, 0, NL80211_CMD_GET_REG
);
2206 if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY
) {
2207 if (nla_put_u32(msg
, NL80211_ATTR_WIPHY
, drv
->wiphy_idx
)) {
2213 return send_and_recv_msgs(drv
, msg
, nl80211_get_reg
, results
);
2217 static const char * modestr(enum hostapd_hw_mode mode
)
2220 case HOSTAPD_MODE_IEEE80211B
:
2222 case HOSTAPD_MODE_IEEE80211G
:
2224 case HOSTAPD_MODE_IEEE80211A
:
2226 case HOSTAPD_MODE_IEEE80211AD
:
2234 static void nl80211_dump_chan_list(struct hostapd_hw_modes
*modes
,
2242 for (i
= 0; i
< num_modes
; i
++) {
2243 struct hostapd_hw_modes
*mode
= &modes
[i
];
2246 char *end
= pos
+ sizeof(str
);
2249 for (j
= 0; j
< mode
->num_channels
; j
++) {
2250 struct hostapd_channel_data
*chan
= &mode
->channels
[j
];
2252 res
= os_snprintf(pos
, end
- pos
, " %d%s%s%s",
2254 (chan
->flag
& HOSTAPD_CHAN_DISABLED
) ?
2256 (chan
->flag
& HOSTAPD_CHAN_NO_IR
) ?
2258 (chan
->flag
& HOSTAPD_CHAN_RADAR
) ?
2260 if (os_snprintf_error(end
- pos
, res
))
2266 wpa_printf(MSG_DEBUG
, "nl80211: Mode IEEE %s:%s",
2267 modestr(mode
->mode
), str
);
2272 struct hostapd_hw_modes
*
2273 nl80211_get_hw_feature_data(void *priv
, u16
*num_modes
, u16
*flags
,
2277 struct i802_bss
*bss
= priv
;
2278 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
2281 struct phy_info_arg result
= {
2282 .num_modes
= num_modes
,
2293 feat
= get_nl80211_protocol_features(drv
);
2294 if (feat
& NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP
)
2295 nl_flags
= NLM_F_DUMP
;
2296 if (!(msg
= nl80211_cmd_msg(bss
, nl_flags
, NL80211_CMD_GET_WIPHY
)) ||
2297 nla_put_flag(msg
, NL80211_ATTR_SPLIT_WIPHY_DUMP
)) {
2302 if (send_and_recv_msgs(drv
, msg
, phy_info_handler
, &result
) == 0) {
2303 struct hostapd_hw_modes
*modes
;
2305 nl80211_set_regulatory_flags(drv
, &result
);
2306 if (result
.failed
) {
2309 for (i
= 0; result
.modes
&& i
< *num_modes
; i
++) {
2310 os_free(result
.modes
[i
].channels
);
2311 os_free(result
.modes
[i
].rates
);
2313 os_free(result
.modes
);
2318 *dfs_domain
= result
.dfs_domain
;
2320 modes
= wpa_driver_nl80211_postprocess_modes(result
.modes
,
2322 nl80211_dump_chan_list(modes
, *num_modes
);