157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt/* 257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * hostapd - MBO 357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * Copyright (c) 2016, Qualcomm Atheros, Inc. 457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * 557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * See README for more details. 757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "utils/includes.h" 1057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 1157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "utils/common.h" 1257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "common/ieee802_11_defs.h" 1357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "common/ieee802_11_common.h" 1457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "hostapd.h" 1557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "sta_info.h" 1657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt#include "mbo_ap.h" 1757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 1857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 1957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtvoid mbo_ap_sta_free(struct sta_info *sta) 2057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 2157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct mbo_non_pref_chan_info *info, *prev; 2257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 2357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info = sta->non_pref_chan; 2457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sta->non_pref_chan = NULL; 2557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt while (info) { 2657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt prev = info; 2757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info = info->next; 2857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_free(prev); 2957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 3057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 3157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 3257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 3357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic void mbo_ap_parse_non_pref_chan(struct sta_info *sta, 3457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *buf, size_t len) 3557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 3657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct mbo_non_pref_chan_info *info, *tmp; 3757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt char channels[200], *pos, *end; 3857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt size_t num_chan, i; 3957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int ret; 4057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 41aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt if (len <= 3) 4257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; /* Not enough room for any channels */ 4357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 44aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt num_chan = len - 3; 4557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info = os_zalloc(sizeof(*info) + num_chan); 4657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!info) 4757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; 4857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info->op_class = buf[0]; 49aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt info->pref = buf[len - 2]; 50aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt info->reason_code = buf[len - 1]; 5157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info->num_channels = num_chan; 5257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt buf++; 5357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt os_memcpy(info->channels, buf, num_chan); 5457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!sta->non_pref_chan) { 5557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sta->non_pref_chan = info; 5657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } else { 5757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tmp = sta->non_pref_chan; 5857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt while (tmp->next) 5957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tmp = tmp->next; 6057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt tmp->next = info; 6157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 6257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 6357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos = channels; 6457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt end = pos + sizeof(channels); 6557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos = '\0'; 6657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (i = 0; i < num_chan; i++) { 6757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ret = os_snprintf(pos, end - pos, "%s%u", 6857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt i == 0 ? "" : " ", buf[i]); 6957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_snprintf_error(end - pos, ret)) { 7057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *pos = '\0'; 7157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 7257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 7357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += ret; 7457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 7557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 7657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR 77aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)", 7857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(sta->addr), info->op_class, info->pref, 79aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt info->reason_code, channels); 8057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 8157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 8257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 8357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtvoid mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta, 8457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct ieee802_11_elems *elems) 8557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 8657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *pos, *attr, *end; 8757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt size_t len; 8857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 8957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!hapd->conf->mbo_enabled || !elems->mbo) 9057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; 9157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 9257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos = elems->mbo + 4; 9357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt len = elems->mbo_len - 4; 9457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len); 9557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 9657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA); 9757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (attr && attr[1] >= 1) 9857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sta->cell_capa = attr[2]; 9957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 10057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_sta_free(sta); 10157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt end = pos + len; 10257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt while (end - pos > 1) { 10357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 ie_len = pos[1]; 10457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 10557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (2 + ie_len > end - pos) 10657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 10757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 10857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT) 10957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len); 11057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += 2 + pos[1]; 11157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 11257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 11357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 11457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 11557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtint mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen) 11657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 11757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt char *pos = buf, *end = buf + buflen; 11857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int ret; 11957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct mbo_non_pref_chan_info *info; 12057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 i; 12157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt unsigned int count = 0; 12257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 12357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!sta->cell_capa) 12457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return 0; 12557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 12657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa); 12757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_snprintf_error(end - pos, ret)) 12857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 12957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += ret; 13057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 13157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (info = sta->non_pref_chan; info; info = info->next) { 13257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt char *pos2 = pos; 13357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 13457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ret = os_snprintf(pos2, end - pos2, 135aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt "non_pref_chan[%u]=%u:%u:%u:", 13657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt count, info->op_class, info->pref, 137aca489e0b2daec9e67dd611b7a44f47bd1f41e27Dmitry Shmidt info->reason_code); 13857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt count++; 13957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_snprintf_error(end - pos2, ret)) 14057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 14157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos2 += ret; 14257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 14357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt for (i = 0; i < info->num_channels; i++) { 14457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ret = os_snprintf(pos2, end - pos2, "%u%s", 14557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt info->channels[i], 14657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt i + 1 < info->num_channels ? 14757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "," : ""); 14857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_snprintf_error(end - pos2, ret)) { 14957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos2 = NULL; 15057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 15157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 15257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos2 += ret; 15357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 15457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 15557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!pos2) 15657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 15757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ret = os_snprintf(pos2, end - pos2, "\n"); 15857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (os_snprintf_error(end - pos2, ret)) 15957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 16057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos2 += ret; 16157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos = pos2; 16257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 16357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 16457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return pos - buf; 16557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 16657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 16757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 16857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta, 16957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *buf, size_t len) 17057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 17157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (len < 1) 17257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; 17357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR 17457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt " updated cellular data capability: %u", 17557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt MAC2STR(sta->addr), buf[0]); 17657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sta->cell_capa = buf[0]; 17757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 17857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 17957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 18057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtstatic void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type, 18157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *buf, size_t len, 18257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int *first_non_pref_chan) 18357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 18457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt switch (type) { 18557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT: 18657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (*first_non_pref_chan) { 18757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt /* 18857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * Need to free the previously stored entries now to 18957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt * allow the update to replace all entries. 19057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt */ 19157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt *first_non_pref_chan = 0; 19257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_sta_free(sta); 19357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 19457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_parse_non_pref_chan(sta, buf, len); 19557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 19657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA: 19757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_wnm_notif_req_cell_capa(sta, buf, len); 19857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 19957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt default: 20057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 20157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "MBO: Ignore unknown WNM Notification WFA subelement %u", 20257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt type); 20357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 20457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 20557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 20657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 20757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 20857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtvoid mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr, 20957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *buf, size_t len) 21057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt{ 21157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt const u8 *pos, *end; 21257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt u8 ie_len; 21357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt struct sta_info *sta; 21457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt int first_non_pref_chan = 1; 21557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 21657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!hapd->conf->mbo_enabled) 21757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; 21857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 21957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt sta = ap_get_sta(hapd, addr); 22057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (!sta) 22157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt return; 22257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 22357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos = buf; 22457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt end = buf + len; 22557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 22657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt while (end - pos > 1) { 22757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_len = pos[1]; 22857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 22957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (2 + ie_len > end - pos) 23057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt break; 23157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 23257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && 23357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA) 23457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt mbo_ap_wnm_notif_req_elem(sta, pos[5], 23557c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos + 6, ie_len - 4, 23657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt &first_non_pref_chan); 23757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt else 23857c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt wpa_printf(MSG_DEBUG, 23957c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt "MBO: Ignore unknown WNM Notification element %u (len=%u)", 24057c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos[0], pos[1]); 24157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt 24257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt pos += 2 + pos[1]; 24357c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt } 24457c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt} 245