static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid) { u8 op_class, channel; if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !hapd->iface->freq) return eid; if (ieee80211_freq_to_channel_ext(hapd->iface->freq, hapd->iconf->secondary_channel, hapd->iconf->vht_oper_chwidth, &op_class, &channel) == NUM_HOSTAPD_MODES) return eid; *eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES; *eid++ = 2; /* Current Operating Class */ *eid++ = op_class; /* TODO: Advertise all the supported operating classes */ *eid++ = 0; return eid; }
/** * p2p_freq_to_channel - Convert frequency into channel info * @op_class: Buffer for returning operating class * @channel: Buffer for returning channel number * Returns: 0 on success, -1 if the specified frequency is unknown */ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel) { /* TODO: this function can be completely removed */ if (ieee80211_freq_to_channel_ext(freq, 0, 0, op_class, channel) == NUM_HOSTAPD_MODES) return -1; return 0; }
static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *buf, size_t len, u8 pref) { const u8 *ie; u8 op_class, chan; int sec_chan = 0, vht = 0; enum phy_type phy_type; u32 info; struct ieee80211_ht_operation *ht_oper = NULL; struct ieee80211_vht_operation *vht_oper = NULL; ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); if (ie && ie[1] >= 2) { ht_oper = (struct ieee80211_ht_operation *) (ie + 2); if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) sec_chan = 1; else if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) sec_chan = -1; } ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION); if (ie && ie[1] >= 1) { vht_oper = (struct ieee80211_vht_operation *) (ie + 2); if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ || vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ || vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ) vht = vht_oper->vht_op_info_chwidth; } if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class, &chan) == NUM_HOSTAPD_MODES) { wpa_printf(MSG_DEBUG, "WNM: Cannot determine operating class and channel"); return -2; } phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL), (vht_oper != NULL)); if (phy_type == PHY_TYPE_UNSPECIFIED) { wpa_printf(MSG_DEBUG, "WNM: Cannot determine BSS phy type for Neighbor Report"); return -2; } info = wnm_get_bss_info(wpa_s, bss); return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan, phy_type, pref); }
int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos, size_t len) { struct wpabuf *buf; u8 op, current, chan; u8 *ie_len; int res; /* * Assume 20 MHz channel for now. * TODO: Use the secondary channel and VHT channel width that will be * used after association. */ if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT, ¤t, &chan) == NUM_HOSTAPD_MODES) return 0; /* * Need 3 bytes for EID, length, and current operating class, plus * 1 byte for every other supported operating class. */ buf = wpabuf_alloc(global_op_class_size + 3); if (!buf) return 0; wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES); /* Will set the length later, putting a placeholder */ ie_len = wpabuf_put(buf, 1); wpabuf_put_u8(buf, current); for (op = 0; global_op_class[op].op_class; op++) { if (wpas_op_class_supported(wpa_s, &global_op_class[op])) wpabuf_put_u8(buf, global_op_class[op].op_class); } *ie_len = wpabuf_len(buf) - 2; if (*ie_len < 2 || wpabuf_len(buf) > len) { wpa_printf(MSG_ERROR, "Failed to add supported operating classes IE"); res = 0; } else { os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf)); res = wpabuf_len(buf); wpa_hexdump_buf(MSG_DEBUG, "MBO: Added supported operating classes IE", buf); } wpabuf_free(buf); return res; }
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) { #ifdef NEED_AP_MLME u16 capab = hostapd_own_capab_info(hapd); int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; struct wpa_ssid_value ssid; u8 channel, op_class; u8 center_freq1_idx = 0, center_freq2_idx = 0; enum nr_chan_width width; u32 bssid_info; struct wpabuf *nr; if (!(hapd->conf->radio_measurements[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) return; bssid_info = 3; /* AP is reachable */ bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */ bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT; bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */ if (hapd->conf->wmm_enabled) { bssid_info |= NEI_REP_BSSID_INFO_QOS; if (hapd->conf->wmm_uapsd && (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD)) bssid_info |= NEI_REP_BSSID_INFO_APSD; } if (ht) { bssid_info |= NEI_REP_BSSID_INFO_HT | NEI_REP_BSSID_INFO_DELAYED_BA; /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ if (vht) bssid_info |= NEI_REP_BSSID_INFO_VHT; } /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ if (ieee80211_freq_to_channel_ext(hapd->iface->freq, hapd->iconf->secondary_channel, hapd->iconf->vht_oper_chwidth, &op_class, &channel) == NUM_HOSTAPD_MODES) return; width = hostapd_get_nr_chan_width(hapd, ht, vht); if (vht) { center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx; if (width == NR_CHAN_WIDTH_80P80) center_freq2_idx = hapd->iconf->vht_oper_centr_freq_seg1_idx; } else if (ht) { ieee80211_freq_to_chan(hapd->iface->freq + 10 * hapd->iconf->secondary_channel, ¢er_freq1_idx); } ssid.ssid_len = hapd->conf->ssid.ssid_len; os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); /* * Neighbor Report element size = BSSID + BSSID info + op_class + chan + * phy type + wide bandwidth channel subelement. */ nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5); if (!nr) return; wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN); wpabuf_put_le32(nr, bssid_info); wpabuf_put_u8(nr, op_class); wpabuf_put_u8(nr, channel); wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht)); /* * Wide Bandwidth Channel subelement may be needed to allow the * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0 * Figure 9-301. */ wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN); wpabuf_put_u8(nr, 3); wpabuf_put_u8(nr, width); wpabuf_put_u8(nr, center_freq1_idx); wpabuf_put_u8(nr, center_freq2_idx); hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci, hapd->iconf->civic, hapd->iconf->stationary_ap); wpabuf_free(nr); #endif /* NEED_AP_MLME */ }