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)",