139beb93cSSam Leffler /* 239beb93cSSam Leffler * IEEE 802.11 Common routines 34bc52338SCy Schubert * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #ifndef IEEE802_11_COMMON_H 1039beb93cSSam Leffler #define IEEE802_11_COMMON_H 1139beb93cSSam Leffler 12780fb4a2SCy Schubert #include "defs.h" 134bc52338SCy Schubert #include "ieee802_11_defs.h" 144bc52338SCy Schubert 154bc52338SCy Schubert struct element { 164bc52338SCy Schubert u8 id; 174bc52338SCy Schubert u8 datalen; 184bc52338SCy Schubert u8 data[]; 194bc52338SCy Schubert } STRUCT_PACKED; 20780fb4a2SCy Schubert 2185732ac8SCy Schubert struct hostapd_hw_modes; 2285732ac8SCy Schubert 23325151a3SRui Paulo #define MAX_NOF_MB_IES_SUPPORTED 5 24*c1d255d3SCy Schubert #define MAX_NUM_FRAG_IES_SUPPORTED 3 25325151a3SRui Paulo 26325151a3SRui Paulo struct mb_ies_info { 27325151a3SRui Paulo struct { 28325151a3SRui Paulo const u8 *ie; 29325151a3SRui Paulo u8 ie_len; 30325151a3SRui Paulo } ies[MAX_NOF_MB_IES_SUPPORTED]; 31325151a3SRui Paulo u8 nof_ies; 32325151a3SRui Paulo }; 33325151a3SRui Paulo 34*c1d255d3SCy Schubert struct frag_ies_info { 35*c1d255d3SCy Schubert struct { 36*c1d255d3SCy Schubert u8 eid; 37*c1d255d3SCy Schubert u8 eid_ext; 38*c1d255d3SCy Schubert const u8 *ie; 39*c1d255d3SCy Schubert u8 ie_len; 40*c1d255d3SCy Schubert } frags[MAX_NUM_FRAG_IES_SUPPORTED]; 41*c1d255d3SCy Schubert 42*c1d255d3SCy Schubert u8 n_frags; 43*c1d255d3SCy Schubert 44*c1d255d3SCy Schubert /* the last parsed element ID and element extension ID */ 45*c1d255d3SCy Schubert u8 last_eid; 46*c1d255d3SCy Schubert u8 last_eid_ext; 47*c1d255d3SCy Schubert }; 48*c1d255d3SCy Schubert 4939beb93cSSam Leffler /* Parsed Information Elements */ 5039beb93cSSam Leffler struct ieee802_11_elems { 51e28a4053SRui Paulo const u8 *ssid; 52e28a4053SRui Paulo const u8 *supp_rates; 53e28a4053SRui Paulo const u8 *ds_params; 54e28a4053SRui Paulo const u8 *challenge; 55e28a4053SRui Paulo const u8 *erp_info; 56e28a4053SRui Paulo const u8 *ext_supp_rates; 57e28a4053SRui Paulo const u8 *wpa_ie; 58e28a4053SRui Paulo const u8 *rsn_ie; 59*c1d255d3SCy Schubert const u8 *rsnxe; 60e28a4053SRui Paulo const u8 *wmm; /* WMM Information or Parameter Element */ 61e28a4053SRui Paulo const u8 *wmm_tspec; 62e28a4053SRui Paulo const u8 *wps_ie; 63e28a4053SRui Paulo const u8 *supp_channels; 64e28a4053SRui Paulo const u8 *mdie; 65e28a4053SRui Paulo const u8 *ftie; 66e28a4053SRui Paulo const u8 *timeout_int; 67e28a4053SRui Paulo const u8 *ht_capabilities; 68e28a4053SRui Paulo const u8 *ht_operation; 695b9c547cSRui Paulo const u8 *mesh_config; 705b9c547cSRui Paulo const u8 *mesh_id; 715b9c547cSRui Paulo const u8 *peer_mgmt; 72f05cddf9SRui Paulo const u8 *vht_capabilities; 73f05cddf9SRui Paulo const u8 *vht_operation; 745b9c547cSRui Paulo const u8 *vht_opmode_notif; 75e28a4053SRui Paulo const u8 *vendor_ht_cap; 765b9c547cSRui Paulo const u8 *vendor_vht; 77f05cddf9SRui Paulo const u8 *p2p; 78f05cddf9SRui Paulo const u8 *wfd; 79f05cddf9SRui Paulo const u8 *link_id; 80f05cddf9SRui Paulo const u8 *interworking; 815b9c547cSRui Paulo const u8 *qos_map_set; 82f05cddf9SRui Paulo const u8 *hs20; 83f05cddf9SRui Paulo const u8 *ext_capab; 84f05cddf9SRui Paulo const u8 *bss_max_idle_period; 85f05cddf9SRui Paulo const u8 *ssid_list; 865b9c547cSRui Paulo const u8 *osen; 87780fb4a2SCy Schubert const u8 *mbo; 885b9c547cSRui Paulo const u8 *ampe; 895b9c547cSRui Paulo const u8 *mic; 90325151a3SRui Paulo const u8 *pref_freq_list; 91780fb4a2SCy Schubert const u8 *supp_op_classes; 92780fb4a2SCy Schubert const u8 *rrm_enabled; 9385732ac8SCy Schubert const u8 *cag_number; 9485732ac8SCy Schubert const u8 *ap_csn; 9585732ac8SCy Schubert const u8 *fils_indic; 9685732ac8SCy Schubert const u8 *dils; 9785732ac8SCy Schubert const u8 *assoc_delay_info; 9885732ac8SCy Schubert const u8 *fils_req_params; 9985732ac8SCy Schubert const u8 *fils_key_confirm; 10085732ac8SCy Schubert const u8 *fils_session; 10185732ac8SCy Schubert const u8 *fils_hlp; 10285732ac8SCy Schubert const u8 *fils_ip_addr_assign; 10385732ac8SCy Schubert const u8 *key_delivery; 104*c1d255d3SCy Schubert const u8 *wrapped_data; 10585732ac8SCy Schubert const u8 *fils_pk; 10685732ac8SCy Schubert const u8 *fils_nonce; 10785732ac8SCy Schubert const u8 *owe_dh; 10885732ac8SCy Schubert const u8 *power_capab; 10985732ac8SCy Schubert const u8 *roaming_cons_sel; 11085732ac8SCy Schubert const u8 *password_id; 1114bc52338SCy Schubert const u8 *oci; 1124bc52338SCy Schubert const u8 *multi_ap; 1134bc52338SCy Schubert const u8 *he_capabilities; 114206b73d0SCy Schubert const u8 *he_operation; 115*c1d255d3SCy Schubert const u8 *short_ssid_list; 116*c1d255d3SCy Schubert const u8 *he_6ghz_band_cap; 117*c1d255d3SCy Schubert const u8 *sae_pk; 118*c1d255d3SCy Schubert const u8 *s1g_capab; 119*c1d255d3SCy Schubert const u8 *pasn_params; 120e28a4053SRui Paulo 12139beb93cSSam Leffler u8 ssid_len; 12239beb93cSSam Leffler u8 supp_rates_len; 12339beb93cSSam Leffler u8 challenge_len; 12439beb93cSSam Leffler u8 ext_supp_rates_len; 12539beb93cSSam Leffler u8 wpa_ie_len; 12639beb93cSSam Leffler u8 rsn_ie_len; 127*c1d255d3SCy Schubert u8 rsnxe_len; 1283157ba21SRui Paulo u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ 1293157ba21SRui Paulo u8 wmm_tspec_len; 13039beb93cSSam Leffler u8 wps_ie_len; 13139beb93cSSam Leffler u8 supp_channels_len; 13239beb93cSSam Leffler u8 mdie_len; 13339beb93cSSam Leffler u8 ftie_len; 1345b9c547cSRui Paulo u8 mesh_config_len; 1355b9c547cSRui Paulo u8 mesh_id_len; 1365b9c547cSRui Paulo u8 peer_mgmt_len; 13739beb93cSSam Leffler u8 vendor_ht_cap_len; 1385b9c547cSRui Paulo u8 vendor_vht_len; 139f05cddf9SRui Paulo u8 p2p_len; 140f05cddf9SRui Paulo u8 wfd_len; 141f05cddf9SRui Paulo u8 interworking_len; 1425b9c547cSRui Paulo u8 qos_map_set_len; 143f05cddf9SRui Paulo u8 hs20_len; 144f05cddf9SRui Paulo u8 ext_capab_len; 145f05cddf9SRui Paulo u8 ssid_list_len; 1465b9c547cSRui Paulo u8 osen_len; 147780fb4a2SCy Schubert u8 mbo_len; 1485b9c547cSRui Paulo u8 ampe_len; 1495b9c547cSRui Paulo u8 mic_len; 150325151a3SRui Paulo u8 pref_freq_list_len; 151780fb4a2SCy Schubert u8 supp_op_classes_len; 152780fb4a2SCy Schubert u8 rrm_enabled_len; 15385732ac8SCy Schubert u8 cag_number_len; 15485732ac8SCy Schubert u8 fils_indic_len; 15585732ac8SCy Schubert u8 dils_len; 15685732ac8SCy Schubert u8 fils_req_params_len; 15785732ac8SCy Schubert u8 fils_key_confirm_len; 15885732ac8SCy Schubert u8 fils_hlp_len; 15985732ac8SCy Schubert u8 fils_ip_addr_assign_len; 16085732ac8SCy Schubert u8 key_delivery_len; 161*c1d255d3SCy Schubert u8 wrapped_data_len; 16285732ac8SCy Schubert u8 fils_pk_len; 16385732ac8SCy Schubert u8 owe_dh_len; 16485732ac8SCy Schubert u8 power_capab_len; 16585732ac8SCy Schubert u8 roaming_cons_sel_len; 16685732ac8SCy Schubert u8 password_id_len; 1674bc52338SCy Schubert u8 oci_len; 1684bc52338SCy Schubert u8 multi_ap_len; 1694bc52338SCy Schubert u8 he_capabilities_len; 170206b73d0SCy Schubert u8 he_operation_len; 171*c1d255d3SCy Schubert u8 short_ssid_list_len; 172*c1d255d3SCy Schubert u8 sae_pk_len; 173*c1d255d3SCy Schubert u8 pasn_params_len; 174780fb4a2SCy Schubert 175325151a3SRui Paulo struct mb_ies_info mb_ies; 176*c1d255d3SCy Schubert struct frag_ies_info frag_ies; 17739beb93cSSam Leffler }; 17839beb93cSSam Leffler 17939beb93cSSam Leffler typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; 18039beb93cSSam Leffler 181e28a4053SRui Paulo ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 18239beb93cSSam Leffler struct ieee802_11_elems *elems, 18339beb93cSSam Leffler int show_errors); 184e28a4053SRui Paulo int ieee802_11_ie_count(const u8 *ies, size_t ies_len); 185e28a4053SRui Paulo struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, 186e28a4053SRui Paulo u32 oui_type); 187f05cddf9SRui Paulo struct ieee80211_hdr; 188f05cddf9SRui Paulo const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len); 189f05cddf9SRui Paulo 190f05cddf9SRui Paulo struct hostapd_wmm_ac_params { 191f05cddf9SRui Paulo int cwmin; 192f05cddf9SRui Paulo int cwmax; 193f05cddf9SRui Paulo int aifs; 194f05cddf9SRui Paulo int txop_limit; /* in units of 32us */ 195f05cddf9SRui Paulo int admission_control_mandatory; 196f05cddf9SRui Paulo }; 197f05cddf9SRui Paulo 198f05cddf9SRui Paulo int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[], 199f05cddf9SRui Paulo const char *name, const char *val); 200*c1d255d3SCy Schubert 201*c1d255d3SCy Schubert struct hostapd_tx_queue_params { 202*c1d255d3SCy Schubert int aifs; 203*c1d255d3SCy Schubert int cwmin; 204*c1d255d3SCy Schubert int cwmax; 205*c1d255d3SCy Schubert int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ 206*c1d255d3SCy Schubert }; 207*c1d255d3SCy Schubert 208*c1d255d3SCy Schubert #define NUM_TX_QUEUES 4 209*c1d255d3SCy Schubert 210*c1d255d3SCy Schubert int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[], 211*c1d255d3SCy Schubert const char *name, const char *val); 2125b9c547cSRui Paulo enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel); 2135b9c547cSRui Paulo int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan); 214325151a3SRui Paulo enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, 215325151a3SRui Paulo int sec_channel, int vht, 216325151a3SRui Paulo u8 *op_class, u8 *channel); 2174bc52338SCy Schubert int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, 2184bc52338SCy Schubert int sec_channel, u8 *op_class, u8 *channel); 21985732ac8SCy Schubert int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, 22085732ac8SCy Schubert u16 num_modes); 221780fb4a2SCy Schubert enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht); 22239beb93cSSam Leffler 2235b9c547cSRui Paulo int supp_rates_11b_only(struct ieee802_11_elems *elems); 224325151a3SRui Paulo int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf, 225325151a3SRui Paulo size_t ies_len); 226325151a3SRui Paulo struct wpabuf * mb_ies_by_info(struct mb_ies_info *info); 2275b9c547cSRui Paulo 2285b9c547cSRui Paulo const char * fc2str(u16 fc); 229206b73d0SCy Schubert const char * reason2str(u16 reason); 230206b73d0SCy Schubert const char * status2str(u16 status); 231780fb4a2SCy Schubert 232780fb4a2SCy Schubert struct oper_class_map { 233780fb4a2SCy Schubert enum hostapd_hw_mode mode; 234780fb4a2SCy Schubert u8 op_class; 235780fb4a2SCy Schubert u8 min_chan; 236780fb4a2SCy Schubert u8 max_chan; 237780fb4a2SCy Schubert u8 inc; 238*c1d255d3SCy Schubert enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80, 239*c1d255d3SCy Schubert BW4320, BW6480, BW8640} bw; 240780fb4a2SCy Schubert enum { P2P_SUPP, NO_P2P_SUPP } p2p; 241780fb4a2SCy Schubert }; 242780fb4a2SCy Schubert 243780fb4a2SCy Schubert extern const struct oper_class_map global_op_class[]; 244780fb4a2SCy Schubert extern size_t global_op_class_size; 245780fb4a2SCy Schubert 246780fb4a2SCy Schubert const u8 * get_ie(const u8 *ies, size_t len, u8 eid); 24785732ac8SCy Schubert const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext); 2484bc52338SCy Schubert const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); 249780fb4a2SCy Schubert 250780fb4a2SCy Schubert size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); 251780fb4a2SCy Schubert 2524bc52338SCy Schubert size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value); 2534bc52338SCy Schubert 25485732ac8SCy Schubert struct country_op_class { 25585732ac8SCy Schubert u8 country_op_class; 25685732ac8SCy Schubert u8 global_op_class; 25785732ac8SCy Schubert }; 25885732ac8SCy Schubert 25985732ac8SCy Schubert u8 country_to_global_op_class(const char *country, u8 op_class); 26085732ac8SCy Schubert 26185732ac8SCy Schubert const struct oper_class_map * get_oper_class(const char *country, u8 op_class); 2624bc52338SCy Schubert int oper_class_bw_to_int(const struct oper_class_map *map); 263*c1d255d3SCy Schubert int center_idx_to_bw_6ghz(u8 idx); 264*c1d255d3SCy Schubert bool is_6ghz_freq(int freq); 265*c1d255d3SCy Schubert bool is_6ghz_op_class(u8 op_class); 266*c1d255d3SCy Schubert bool is_6ghz_psc_frequency(int freq); 26785732ac8SCy Schubert 26885732ac8SCy Schubert int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, 26985732ac8SCy Schubert size_t nei_rep_len); 27085732ac8SCy Schubert 2714bc52338SCy Schubert int ieee802_11_ext_capab(const u8 *ie, unsigned int capab); 272*c1d255d3SCy Schubert bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, 273*c1d255d3SCy Schubert unsigned int capab); 274*c1d255d3SCy Schubert bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab); 275*c1d255d3SCy Schubert int op_class_to_bandwidth(u8 op_class); 276*c1d255d3SCy Schubert int op_class_to_ch_width(u8 op_class); 2774bc52338SCy Schubert 2784bc52338SCy Schubert /* element iteration helpers */ 2794bc52338SCy Schubert #define for_each_element(_elem, _data, _datalen) \ 2804bc52338SCy Schubert for (_elem = (const struct element *) (_data); \ 2814bc52338SCy Schubert (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \ 2824bc52338SCy Schubert (int) sizeof(*_elem) && \ 2834bc52338SCy Schubert (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \ 2844bc52338SCy Schubert (int) sizeof(*_elem) + _elem->datalen; \ 2854bc52338SCy Schubert _elem = (const struct element *) (_elem->data + _elem->datalen)) 2864bc52338SCy Schubert 2874bc52338SCy Schubert #define for_each_element_id(element, _id, data, datalen) \ 2884bc52338SCy Schubert for_each_element(element, data, datalen) \ 2894bc52338SCy Schubert if (element->id == (_id)) 2904bc52338SCy Schubert 2914bc52338SCy Schubert #define for_each_element_extid(element, extid, _data, _datalen) \ 2924bc52338SCy Schubert for_each_element(element, _data, _datalen) \ 2934bc52338SCy Schubert if (element->id == WLAN_EID_EXTENSION && \ 2944bc52338SCy Schubert element->datalen > 0 && \ 2954bc52338SCy Schubert element->data[0] == (extid)) 2964bc52338SCy Schubert 2974bc52338SCy Schubert #define for_each_subelement(sub, element) \ 2984bc52338SCy Schubert for_each_element(sub, (element)->data, (element)->datalen) 2994bc52338SCy Schubert 3004bc52338SCy Schubert #define for_each_subelement_id(sub, id, element) \ 3014bc52338SCy Schubert for_each_element_id(sub, id, (element)->data, (element)->datalen) 3024bc52338SCy Schubert 3034bc52338SCy Schubert #define for_each_subelement_extid(sub, extid, element) \ 3044bc52338SCy Schubert for_each_element_extid(sub, extid, (element)->data, (element)->datalen) 3054bc52338SCy Schubert 3064bc52338SCy Schubert /** 3074bc52338SCy Schubert * for_each_element_completed - Determine if element parsing consumed all data 3084bc52338SCy Schubert * @element: Element pointer after for_each_element() or friends 3094bc52338SCy Schubert * @data: Same data pointer as passed to for_each_element() or friends 3104bc52338SCy Schubert * @datalen: Same data length as passed to for_each_element() or friends 3114bc52338SCy Schubert * 3124bc52338SCy Schubert * This function returns 1 if all the data was parsed or considered 3134bc52338SCy Schubert * while walking the elements. Only use this if your for_each_element() 3144bc52338SCy Schubert * loop cannot be broken out of, otherwise it always returns 0. 3154bc52338SCy Schubert * 3164bc52338SCy Schubert * If some data was malformed, this returns %false since the last parsed 3174bc52338SCy Schubert * element will not fill the whole remaining data. 3184bc52338SCy Schubert */ 3194bc52338SCy Schubert static inline int for_each_element_completed(const struct element *element, 3204bc52338SCy Schubert const void *data, size_t datalen) 3214bc52338SCy Schubert { 3224bc52338SCy Schubert return (const u8 *) element == (const u8 *) data + datalen; 3234bc52338SCy Schubert } 3244bc52338SCy Schubert 325*c1d255d3SCy Schubert struct ieee80211_edmg_config; 326*c1d255d3SCy Schubert 327*c1d255d3SCy Schubert void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel, 328*c1d255d3SCy Schubert int primary_channel, 329*c1d255d3SCy Schubert struct ieee80211_edmg_config *edmg); 330*c1d255d3SCy Schubert 331*c1d255d3SCy Schubert int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed, 332*c1d255d3SCy Schubert struct ieee80211_edmg_config requested); 333*c1d255d3SCy Schubert 334*c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems, 335*c1d255d3SCy Schubert u8 eid, u8 eid_ext, 336*c1d255d3SCy Schubert const u8 *data, u8 len); 337*c1d255d3SCy Schubert struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems, 338*c1d255d3SCy Schubert u8 eid, u8 eid_ext); 339*c1d255d3SCy Schubert 34039beb93cSSam Leffler #endif /* IEEE802_11_COMMON_H */ 341