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