3 * Copyright (c) 2016, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "common/ieee802_11_defs.h"
13 #include "common/ieee802_11_common.h"
19 void mbo_ap_sta_free(struct sta_info *sta)
21 struct mbo_non_pref_chan_info *info, *prev;
23 info = sta->non_pref_chan;
24 sta->non_pref_chan = NULL;
33 static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
34 const u8 *buf, size_t len)
36 struct mbo_non_pref_chan_info *info, *tmp;
37 char channels[200], *pos, *end;
42 return; /* Not enough room for any channels */
45 info = os_zalloc(sizeof(*info) + num_chan);
48 info->op_class = buf[0];
49 info->pref = buf[len - 2];
50 info->reason_code = buf[len - 1];
51 info->num_channels = num_chan;
53 os_memcpy(info->channels, buf, num_chan);
54 if (!sta->non_pref_chan) {
55 sta->non_pref_chan = info;
57 tmp = sta->non_pref_chan;
64 end = pos + sizeof(channels);
66 for (i = 0; i < num_chan; i++) {
67 ret = os_snprintf(pos, end - pos, "%s%u",
68 i == 0 ? "" : " ", buf[i]);
69 if (os_snprintf_error(end - pos, ret)) {
76 wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
77 " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
78 MAC2STR(sta->addr), info->op_class, info->pref,
79 info->reason_code, channels);
83 void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
84 struct ieee802_11_elems *elems)
86 const u8 *pos, *attr, *end;
89 if (!hapd->conf->mbo_enabled || !elems->mbo)
93 len = elems->mbo_len - 4;
94 wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
96 attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
97 if (attr && attr[1] >= 1)
98 sta->cell_capa = attr[2];
100 mbo_ap_sta_free(sta);
102 while (end - pos > 1) {
105 if (2 + ie_len > end - pos)
108 if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
109 mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
115 int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
117 char *pos = buf, *end = buf + buflen;
119 struct mbo_non_pref_chan_info *info;
121 unsigned int count = 0;
126 ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
127 if (os_snprintf_error(end - pos, ret))
131 for (info = sta->non_pref_chan; info; info = info->next) {
134 ret = os_snprintf(pos2, end - pos2,
135 "non_pref_chan[%u]=%u:%u:%u:",
136 count, info->op_class, info->pref,
139 if (os_snprintf_error(end - pos2, ret))
143 for (i = 0; i < info->num_channels; i++) {
144 ret = os_snprintf(pos2, end - pos2, "%u%s",
146 i + 1 < info->num_channels ?
148 if (os_snprintf_error(end - pos2, ret)) {
157 ret = os_snprintf(pos2, end - pos2, "\n");
158 if (os_snprintf_error(end - pos2, ret))
168 static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
169 const u8 *buf, size_t len)
173 wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
174 " updated cellular data capability: %u",
175 MAC2STR(sta->addr), buf[0]);
176 sta->cell_capa = buf[0];
180 static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
181 const u8 *buf, size_t len,
182 int *first_non_pref_chan)
185 case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
186 if (*first_non_pref_chan) {
188 * Need to free the previously stored entries now to
189 * allow the update to replace all entries.
191 *first_non_pref_chan = 0;
192 mbo_ap_sta_free(sta);
194 mbo_ap_parse_non_pref_chan(sta, buf, len);
196 case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
197 mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
200 wpa_printf(MSG_DEBUG,
201 "MBO: Ignore unknown WNM Notification WFA subelement %u",
208 void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
209 const u8 *buf, size_t len)
213 struct sta_info *sta;
214 int first_non_pref_chan = 1;
216 if (!hapd->conf->mbo_enabled)
219 sta = ap_get_sta(hapd, addr);
226 while (end - pos > 1) {
229 if (2 + ie_len > end - pos)
232 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
233 ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
234 mbo_ap_wnm_notif_req_elem(sta, pos[5],
236 &first_non_pref_chan);
238 wpa_printf(MSG_DEBUG,
239 "MBO: Ignore unknown WNM Notification element %u (len=%u)",