1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker * wpa_supplicant - MBO
3*03f9172cSAndroid Build Coastguard Worker *
4*03f9172cSAndroid Build Coastguard Worker * Copyright(c) 2015 Intel Deutschland GmbH
5*03f9172cSAndroid Build Coastguard Worker * Contact Information:
6*03f9172cSAndroid Build Coastguard Worker * Intel Linux Wireless <[email protected]>
7*03f9172cSAndroid Build Coastguard Worker * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
8*03f9172cSAndroid Build Coastguard Worker *
9*03f9172cSAndroid Build Coastguard Worker * This software may be distributed under the terms of the BSD license.
10*03f9172cSAndroid Build Coastguard Worker * See README for more details.
11*03f9172cSAndroid Build Coastguard Worker */
12*03f9172cSAndroid Build Coastguard Worker
13*03f9172cSAndroid Build Coastguard Worker #include "utils/includes.h"
14*03f9172cSAndroid Build Coastguard Worker
15*03f9172cSAndroid Build Coastguard Worker #include "utils/common.h"
16*03f9172cSAndroid Build Coastguard Worker #include "common/ieee802_11_defs.h"
17*03f9172cSAndroid Build Coastguard Worker #include "common/gas.h"
18*03f9172cSAndroid Build Coastguard Worker #include "rsn_supp/wpa.h"
19*03f9172cSAndroid Build Coastguard Worker #include "config.h"
20*03f9172cSAndroid Build Coastguard Worker #include "wpa_supplicant_i.h"
21*03f9172cSAndroid Build Coastguard Worker #include "driver_i.h"
22*03f9172cSAndroid Build Coastguard Worker #include "bss.h"
23*03f9172cSAndroid Build Coastguard Worker #include "scan.h"
24*03f9172cSAndroid Build Coastguard Worker
25*03f9172cSAndroid Build Coastguard Worker /* type + length + oui + oui type */
26*03f9172cSAndroid Build Coastguard Worker #define MBO_IE_HEADER 6
27*03f9172cSAndroid Build Coastguard Worker
28*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_validate_non_pref_chan(u8 oper_class,u8 chan,u8 reason)29*03f9172cSAndroid Build Coastguard Worker static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason)
30*03f9172cSAndroid Build Coastguard Worker {
31*03f9172cSAndroid Build Coastguard Worker if (reason > MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE)
32*03f9172cSAndroid Build Coastguard Worker return -1;
33*03f9172cSAndroid Build Coastguard Worker
34*03f9172cSAndroid Build Coastguard Worker /* Only checking the validity of the channel and oper_class */
35*03f9172cSAndroid Build Coastguard Worker if (ieee80211_chan_to_freq(NULL, oper_class, chan) == -1)
36*03f9172cSAndroid Build Coastguard Worker return -1;
37*03f9172cSAndroid Build Coastguard Worker
38*03f9172cSAndroid Build Coastguard Worker return 0;
39*03f9172cSAndroid Build Coastguard Worker }
40*03f9172cSAndroid Build Coastguard Worker
41*03f9172cSAndroid Build Coastguard Worker
mbo_attr_from_mbo_ie(const u8 * mbo_ie,enum mbo_attr_id attr)42*03f9172cSAndroid Build Coastguard Worker const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
43*03f9172cSAndroid Build Coastguard Worker {
44*03f9172cSAndroid Build Coastguard Worker const u8 *mbo;
45*03f9172cSAndroid Build Coastguard Worker u8 ie_len = mbo_ie[1];
46*03f9172cSAndroid Build Coastguard Worker
47*03f9172cSAndroid Build Coastguard Worker if (ie_len < MBO_IE_HEADER - 2)
48*03f9172cSAndroid Build Coastguard Worker return NULL;
49*03f9172cSAndroid Build Coastguard Worker mbo = mbo_ie + MBO_IE_HEADER;
50*03f9172cSAndroid Build Coastguard Worker
51*03f9172cSAndroid Build Coastguard Worker return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr);
52*03f9172cSAndroid Build Coastguard Worker }
53*03f9172cSAndroid Build Coastguard Worker
54*03f9172cSAndroid Build Coastguard Worker
mbo_get_attr_from_ies(const u8 * ies,size_t ies_len,enum mbo_attr_id attr)55*03f9172cSAndroid Build Coastguard Worker const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
56*03f9172cSAndroid Build Coastguard Worker enum mbo_attr_id attr)
57*03f9172cSAndroid Build Coastguard Worker {
58*03f9172cSAndroid Build Coastguard Worker const u8 *mbo_ie;
59*03f9172cSAndroid Build Coastguard Worker
60*03f9172cSAndroid Build Coastguard Worker mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
61*03f9172cSAndroid Build Coastguard Worker if (!mbo_ie)
62*03f9172cSAndroid Build Coastguard Worker return NULL;
63*03f9172cSAndroid Build Coastguard Worker
64*03f9172cSAndroid Build Coastguard Worker return mbo_attr_from_mbo_ie(mbo_ie, attr);
65*03f9172cSAndroid Build Coastguard Worker }
66*03f9172cSAndroid Build Coastguard Worker
67*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_get_bss_attr(struct wpa_bss * bss,enum mbo_attr_id attr,bool beacon)68*03f9172cSAndroid Build Coastguard Worker static const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss,
69*03f9172cSAndroid Build Coastguard Worker enum mbo_attr_id attr, bool beacon)
70*03f9172cSAndroid Build Coastguard Worker {
71*03f9172cSAndroid Build Coastguard Worker const u8 *mbo, *end;
72*03f9172cSAndroid Build Coastguard Worker
73*03f9172cSAndroid Build Coastguard Worker if (!bss)
74*03f9172cSAndroid Build Coastguard Worker return NULL;
75*03f9172cSAndroid Build Coastguard Worker
76*03f9172cSAndroid Build Coastguard Worker if (beacon)
77*03f9172cSAndroid Build Coastguard Worker mbo = wpa_bss_get_vendor_ie_beacon(bss, MBO_IE_VENDOR_TYPE);
78*03f9172cSAndroid Build Coastguard Worker else
79*03f9172cSAndroid Build Coastguard Worker mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
80*03f9172cSAndroid Build Coastguard Worker if (!mbo)
81*03f9172cSAndroid Build Coastguard Worker return NULL;
82*03f9172cSAndroid Build Coastguard Worker
83*03f9172cSAndroid Build Coastguard Worker end = mbo + 2 + mbo[1];
84*03f9172cSAndroid Build Coastguard Worker mbo += MBO_IE_HEADER;
85*03f9172cSAndroid Build Coastguard Worker
86*03f9172cSAndroid Build Coastguard Worker return get_ie(mbo, end - mbo, attr);
87*03f9172cSAndroid Build Coastguard Worker }
88*03f9172cSAndroid Build Coastguard Worker
89*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_check_assoc_disallow(struct wpa_bss * bss)90*03f9172cSAndroid Build Coastguard Worker const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss)
91*03f9172cSAndroid Build Coastguard Worker {
92*03f9172cSAndroid Build Coastguard Worker const u8 *assoc_disallow;
93*03f9172cSAndroid Build Coastguard Worker
94*03f9172cSAndroid Build Coastguard Worker assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW,
95*03f9172cSAndroid Build Coastguard Worker bss->beacon_newer);
96*03f9172cSAndroid Build Coastguard Worker if (assoc_disallow && assoc_disallow[1] >= 1)
97*03f9172cSAndroid Build Coastguard Worker return assoc_disallow;
98*03f9172cSAndroid Build Coastguard Worker
99*03f9172cSAndroid Build Coastguard Worker return NULL;
100*03f9172cSAndroid Build Coastguard Worker }
101*03f9172cSAndroid Build Coastguard Worker
102*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_check_pmf(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid)103*03f9172cSAndroid Build Coastguard Worker void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
104*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid)
105*03f9172cSAndroid Build Coastguard Worker {
106*03f9172cSAndroid Build Coastguard Worker const u8 *rsne, *mbo, *oce;
107*03f9172cSAndroid Build Coastguard Worker struct wpa_ie_data ie;
108*03f9172cSAndroid Build Coastguard Worker
109*03f9172cSAndroid Build Coastguard Worker wpa_s->disable_mbo_oce = 0;
110*03f9172cSAndroid Build Coastguard Worker if (!bss)
111*03f9172cSAndroid Build Coastguard Worker return;
112*03f9172cSAndroid Build Coastguard Worker mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND, false);
113*03f9172cSAndroid Build Coastguard Worker oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND, false);
114*03f9172cSAndroid Build Coastguard Worker if (!mbo && !oce)
115*03f9172cSAndroid Build Coastguard Worker return;
116*03f9172cSAndroid Build Coastguard Worker if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
117*03f9172cSAndroid Build Coastguard Worker return; /* STA-CFON is not required to enable PMF */
118*03f9172cSAndroid Build Coastguard Worker rsne = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
119*03f9172cSAndroid Build Coastguard Worker if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
120*03f9172cSAndroid Build Coastguard Worker return; /* AP is not using RSN */
121*03f9172cSAndroid Build Coastguard Worker
122*03f9172cSAndroid Build Coastguard Worker if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
123*03f9172cSAndroid Build Coastguard Worker wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
124*03f9172cSAndroid Build Coastguard Worker if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
125*03f9172cSAndroid Build Coastguard Worker wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
126*03f9172cSAndroid Build Coastguard Worker if (wpa_s->disable_mbo_oce)
127*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO,
128*03f9172cSAndroid Build Coastguard Worker "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
129*03f9172cSAndroid Build Coastguard Worker }
130*03f9172cSAndroid Build Coastguard Worker
131*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant * wpa_s,struct wpabuf * mbo,u8 start,u8 end)132*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
133*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mbo,
134*03f9172cSAndroid Build Coastguard Worker u8 start, u8 end)
135*03f9172cSAndroid Build Coastguard Worker {
136*03f9172cSAndroid Build Coastguard Worker u8 i;
137*03f9172cSAndroid Build Coastguard Worker
138*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].oper_class);
139*03f9172cSAndroid Build Coastguard Worker
140*03f9172cSAndroid Build Coastguard Worker for (i = start; i < end; i++)
141*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, wpa_s->non_pref_chan[i].chan);
142*03f9172cSAndroid Build Coastguard Worker
143*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
144*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
145*03f9172cSAndroid Build Coastguard Worker }
146*03f9172cSAndroid Build Coastguard Worker
147*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf * mbo,size_t size)148*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size)
149*03f9172cSAndroid Build Coastguard Worker {
150*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
151*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, size); /* Length */
152*03f9172cSAndroid Build Coastguard Worker }
153*03f9172cSAndroid Build Coastguard Worker
154*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_attr(struct wpa_supplicant * wpa_s,struct wpabuf * mbo,u8 start,u8 end)155*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
156*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mbo, u8 start, u8 end)
157*03f9172cSAndroid Build Coastguard Worker {
158*03f9172cSAndroid Build Coastguard Worker size_t size = end - start + 3;
159*03f9172cSAndroid Build Coastguard Worker
160*03f9172cSAndroid Build Coastguard Worker if (size + 2 > wpabuf_tailroom(mbo))
161*03f9172cSAndroid Build Coastguard Worker return;
162*03f9172cSAndroid Build Coastguard Worker
163*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attr_hdr(mbo, size);
164*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
165*03f9172cSAndroid Build Coastguard Worker }
166*03f9172cSAndroid Build Coastguard Worker
167*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf * mbo,u8 len)168*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
169*03f9172cSAndroid Build Coastguard Worker {
170*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
171*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, len); /* Length */
172*03f9172cSAndroid Build Coastguard Worker wpabuf_put_be24(mbo, OUI_WFA);
173*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
174*03f9172cSAndroid Build Coastguard Worker }
175*03f9172cSAndroid Build Coastguard Worker
176*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant * wpa_s,struct wpabuf * mbo,u8 start,u8 end)177*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
178*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mbo, u8 start,
179*03f9172cSAndroid Build Coastguard Worker u8 end)
180*03f9172cSAndroid Build Coastguard Worker {
181*03f9172cSAndroid Build Coastguard Worker size_t size = end - start + 7;
182*03f9172cSAndroid Build Coastguard Worker
183*03f9172cSAndroid Build Coastguard Worker if (size + 2 > wpabuf_tailroom(mbo))
184*03f9172cSAndroid Build Coastguard Worker return;
185*03f9172cSAndroid Build Coastguard Worker
186*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
187*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
188*03f9172cSAndroid Build Coastguard Worker }
189*03f9172cSAndroid Build Coastguard Worker
190*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant * wpa_s,struct wpabuf * mbo,int subelement)191*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
192*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mbo, int subelement)
193*03f9172cSAndroid Build Coastguard Worker {
194*03f9172cSAndroid Build Coastguard Worker u8 i, start = 0;
195*03f9172cSAndroid Build Coastguard Worker struct wpa_mbo_non_pref_channel *start_pref;
196*03f9172cSAndroid Build Coastguard Worker
197*03f9172cSAndroid Build Coastguard Worker if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
198*03f9172cSAndroid Build Coastguard Worker if (subelement)
199*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
200*03f9172cSAndroid Build Coastguard Worker else
201*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attr_hdr(mbo, 0);
202*03f9172cSAndroid Build Coastguard Worker return;
203*03f9172cSAndroid Build Coastguard Worker }
204*03f9172cSAndroid Build Coastguard Worker start_pref = &wpa_s->non_pref_chan[0];
205*03f9172cSAndroid Build Coastguard Worker
206*03f9172cSAndroid Build Coastguard Worker for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
207*03f9172cSAndroid Build Coastguard Worker struct wpa_mbo_non_pref_channel *non_pref = NULL;
208*03f9172cSAndroid Build Coastguard Worker
209*03f9172cSAndroid Build Coastguard Worker if (i < wpa_s->non_pref_chan_num)
210*03f9172cSAndroid Build Coastguard Worker non_pref = &wpa_s->non_pref_chan[i];
211*03f9172cSAndroid Build Coastguard Worker if (!non_pref ||
212*03f9172cSAndroid Build Coastguard Worker non_pref->oper_class != start_pref->oper_class ||
213*03f9172cSAndroid Build Coastguard Worker non_pref->reason != start_pref->reason ||
214*03f9172cSAndroid Build Coastguard Worker non_pref->preference != start_pref->preference) {
215*03f9172cSAndroid Build Coastguard Worker if (subelement)
216*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
217*03f9172cSAndroid Build Coastguard Worker start, i);
218*03f9172cSAndroid Build Coastguard Worker else
219*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
220*03f9172cSAndroid Build Coastguard Worker i);
221*03f9172cSAndroid Build Coastguard Worker
222*03f9172cSAndroid Build Coastguard Worker if (!non_pref)
223*03f9172cSAndroid Build Coastguard Worker return;
224*03f9172cSAndroid Build Coastguard Worker
225*03f9172cSAndroid Build Coastguard Worker start = i;
226*03f9172cSAndroid Build Coastguard Worker start_pref = non_pref;
227*03f9172cSAndroid Build Coastguard Worker }
228*03f9172cSAndroid Build Coastguard Worker }
229*03f9172cSAndroid Build Coastguard Worker }
230*03f9172cSAndroid Build Coastguard Worker
231*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_ie(struct wpa_supplicant * wpa_s,u8 * buf,size_t len,int add_oce_capa)232*03f9172cSAndroid Build Coastguard Worker int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
233*03f9172cSAndroid Build Coastguard Worker int add_oce_capa)
234*03f9172cSAndroid Build Coastguard Worker {
235*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mbo;
236*03f9172cSAndroid Build Coastguard Worker int res;
237*03f9172cSAndroid Build Coastguard Worker
238*03f9172cSAndroid Build Coastguard Worker if (len < MBO_IE_HEADER + 3 + 7 +
239*03f9172cSAndroid Build Coastguard Worker ((wpa_s->enable_oce & OCE_STA) ? 3 : 0))
240*03f9172cSAndroid Build Coastguard Worker return 0;
241*03f9172cSAndroid Build Coastguard Worker
242*03f9172cSAndroid Build Coastguard Worker /* Leave room for the MBO IE header */
243*03f9172cSAndroid Build Coastguard Worker mbo = wpabuf_alloc(len - MBO_IE_HEADER);
244*03f9172cSAndroid Build Coastguard Worker if (!mbo)
245*03f9172cSAndroid Build Coastguard Worker return 0;
246*03f9172cSAndroid Build Coastguard Worker
247*03f9172cSAndroid Build Coastguard Worker /* Add non-preferred channels attribute */
248*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
249*03f9172cSAndroid Build Coastguard Worker
250*03f9172cSAndroid Build Coastguard Worker /*
251*03f9172cSAndroid Build Coastguard Worker * Send cellular capabilities attribute even if AP does not advertise
252*03f9172cSAndroid Build Coastguard Worker * cellular capabilities.
253*03f9172cSAndroid Build Coastguard Worker */
254*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, MBO_ATTR_ID_CELL_DATA_CAPA);
255*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, 1);
256*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
257*03f9172cSAndroid Build Coastguard Worker
258*03f9172cSAndroid Build Coastguard Worker /* Add OCE capability indication attribute if OCE is enabled */
259*03f9172cSAndroid Build Coastguard Worker if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) {
260*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND);
261*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, 1);
262*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(mbo, OCE_RELEASE);
263*03f9172cSAndroid Build Coastguard Worker }
264*03f9172cSAndroid Build Coastguard Worker
265*03f9172cSAndroid Build Coastguard Worker res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
266*03f9172cSAndroid Build Coastguard Worker if (!res)
267*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR, "Failed to add MBO/OCE IE");
268*03f9172cSAndroid Build Coastguard Worker
269*03f9172cSAndroid Build Coastguard Worker wpabuf_free(mbo);
270*03f9172cSAndroid Build Coastguard Worker return res;
271*03f9172cSAndroid Build Coastguard Worker }
272*03f9172cSAndroid Build Coastguard Worker
273*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_send_wnm_notification(struct wpa_supplicant * wpa_s,const u8 * data,size_t len)274*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s,
275*03f9172cSAndroid Build Coastguard Worker const u8 *data, size_t len)
276*03f9172cSAndroid Build Coastguard Worker {
277*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
278*03f9172cSAndroid Build Coastguard Worker int res;
279*03f9172cSAndroid Build Coastguard Worker
280*03f9172cSAndroid Build Coastguard Worker /*
281*03f9172cSAndroid Build Coastguard Worker * Send WNM-Notification Request frame only in case of a change in
282*03f9172cSAndroid Build Coastguard Worker * non-preferred channels list during association, if the AP supports
283*03f9172cSAndroid Build Coastguard Worker * MBO.
284*03f9172cSAndroid Build Coastguard Worker */
285*03f9172cSAndroid Build Coastguard Worker if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss ||
286*03f9172cSAndroid Build Coastguard Worker !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
287*03f9172cSAndroid Build Coastguard Worker return;
288*03f9172cSAndroid Build Coastguard Worker
289*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(4 + len);
290*03f9172cSAndroid Build Coastguard Worker if (!buf)
291*03f9172cSAndroid Build Coastguard Worker return;
292*03f9172cSAndroid Build Coastguard Worker
293*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WLAN_ACTION_WNM);
294*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
295*03f9172cSAndroid Build Coastguard Worker wpa_s->mbo_wnm_token++;
296*03f9172cSAndroid Build Coastguard Worker if (wpa_s->mbo_wnm_token == 0)
297*03f9172cSAndroid Build Coastguard Worker wpa_s->mbo_wnm_token++;
298*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
299*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
300*03f9172cSAndroid Build Coastguard Worker
301*03f9172cSAndroid Build Coastguard Worker wpabuf_put_data(buf, data, len);
302*03f9172cSAndroid Build Coastguard Worker
303*03f9172cSAndroid Build Coastguard Worker res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
304*03f9172cSAndroid Build Coastguard Worker wpa_s->own_addr, wpa_s->bssid,
305*03f9172cSAndroid Build Coastguard Worker wpabuf_head(buf), wpabuf_len(buf), 0);
306*03f9172cSAndroid Build Coastguard Worker if (res < 0)
307*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
308*03f9172cSAndroid Build Coastguard Worker "Failed to send WNM-Notification Request frame with non-preferred channel list");
309*03f9172cSAndroid Build Coastguard Worker
310*03f9172cSAndroid Build Coastguard Worker wpabuf_free(buf);
311*03f9172cSAndroid Build Coastguard Worker }
312*03f9172cSAndroid Build Coastguard Worker
313*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_non_pref_chan_changed(struct wpa_supplicant * wpa_s)314*03f9172cSAndroid Build Coastguard Worker static void wpas_mbo_non_pref_chan_changed(struct wpa_supplicant *wpa_s)
315*03f9172cSAndroid Build Coastguard Worker {
316*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
317*03f9172cSAndroid Build Coastguard Worker
318*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(512);
319*03f9172cSAndroid Build Coastguard Worker if (!buf)
320*03f9172cSAndroid Build Coastguard Worker return;
321*03f9172cSAndroid Build Coastguard Worker
322*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
323*03f9172cSAndroid Build Coastguard Worker wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
324*03f9172cSAndroid Build Coastguard Worker wpabuf_len(buf));
325*03f9172cSAndroid Build Coastguard Worker wpas_update_mbo_connect_params(wpa_s);
326*03f9172cSAndroid Build Coastguard Worker wpabuf_free(buf);
327*03f9172cSAndroid Build Coastguard Worker }
328*03f9172cSAndroid Build Coastguard Worker
329*03f9172cSAndroid Build Coastguard Worker
wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel * a,struct wpa_mbo_non_pref_channel * b)330*03f9172cSAndroid Build Coastguard Worker static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
331*03f9172cSAndroid Build Coastguard Worker struct wpa_mbo_non_pref_channel *b)
332*03f9172cSAndroid Build Coastguard Worker {
333*03f9172cSAndroid Build Coastguard Worker return a->oper_class == b->oper_class && a->chan == b->chan;
334*03f9172cSAndroid Build Coastguard Worker }
335*03f9172cSAndroid Build Coastguard Worker
336*03f9172cSAndroid Build Coastguard Worker
337*03f9172cSAndroid Build Coastguard Worker /*
338*03f9172cSAndroid Build Coastguard Worker * wpa_non_pref_chan_cmp - Compare two channels for sorting
339*03f9172cSAndroid Build Coastguard Worker *
340*03f9172cSAndroid Build Coastguard Worker * In MBO IE non-preferred channel subelement we can put many channels in an
341*03f9172cSAndroid Build Coastguard Worker * attribute if they are in the same operating class and have the same
342*03f9172cSAndroid Build Coastguard Worker * preference and reason. To make it easy for the functions that build
343*03f9172cSAndroid Build Coastguard Worker * the IE attributes and WNM Request subelements, save the channels sorted
344*03f9172cSAndroid Build Coastguard Worker * by their oper_class and reason.
345*03f9172cSAndroid Build Coastguard Worker */
wpa_non_pref_chan_cmp(const void * _a,const void * _b)346*03f9172cSAndroid Build Coastguard Worker static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
347*03f9172cSAndroid Build Coastguard Worker {
348*03f9172cSAndroid Build Coastguard Worker const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
349*03f9172cSAndroid Build Coastguard Worker
350*03f9172cSAndroid Build Coastguard Worker if (a->oper_class != b->oper_class)
351*03f9172cSAndroid Build Coastguard Worker return (int) a->oper_class - (int) b->oper_class;
352*03f9172cSAndroid Build Coastguard Worker if (a->reason != b->reason)
353*03f9172cSAndroid Build Coastguard Worker return (int) a->reason - (int) b->reason;
354*03f9172cSAndroid Build Coastguard Worker return (int) a->preference - (int) b->preference;
355*03f9172cSAndroid Build Coastguard Worker }
356*03f9172cSAndroid Build Coastguard Worker
357*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_update_non_pref_chan(struct wpa_supplicant * wpa_s,const char * non_pref_chan)358*03f9172cSAndroid Build Coastguard Worker int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
359*03f9172cSAndroid Build Coastguard Worker const char *non_pref_chan)
360*03f9172cSAndroid Build Coastguard Worker {
361*03f9172cSAndroid Build Coastguard Worker char *cmd, *token, *context = NULL;
362*03f9172cSAndroid Build Coastguard Worker struct wpa_mbo_non_pref_channel *chans = NULL, *tmp_chans;
363*03f9172cSAndroid Build Coastguard Worker size_t num = 0, size = 0;
364*03f9172cSAndroid Build Coastguard Worker unsigned i;
365*03f9172cSAndroid Build Coastguard Worker
366*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MBO: Update non-preferred channels, non_pref_chan=%s",
367*03f9172cSAndroid Build Coastguard Worker non_pref_chan ? non_pref_chan : "N/A");
368*03f9172cSAndroid Build Coastguard Worker
369*03f9172cSAndroid Build Coastguard Worker /*
370*03f9172cSAndroid Build Coastguard Worker * The shortest channel configuration is 7 characters - 3 colons and
371*03f9172cSAndroid Build Coastguard Worker * 4 values.
372*03f9172cSAndroid Build Coastguard Worker */
373*03f9172cSAndroid Build Coastguard Worker if (!non_pref_chan || os_strlen(non_pref_chan) < 7)
374*03f9172cSAndroid Build Coastguard Worker goto update;
375*03f9172cSAndroid Build Coastguard Worker
376*03f9172cSAndroid Build Coastguard Worker cmd = os_strdup(non_pref_chan);
377*03f9172cSAndroid Build Coastguard Worker if (!cmd)
378*03f9172cSAndroid Build Coastguard Worker return -1;
379*03f9172cSAndroid Build Coastguard Worker
380*03f9172cSAndroid Build Coastguard Worker while ((token = str_token(cmd, " ", &context))) {
381*03f9172cSAndroid Build Coastguard Worker struct wpa_mbo_non_pref_channel *chan;
382*03f9172cSAndroid Build Coastguard Worker int ret;
383*03f9172cSAndroid Build Coastguard Worker unsigned int _oper_class;
384*03f9172cSAndroid Build Coastguard Worker unsigned int _chan;
385*03f9172cSAndroid Build Coastguard Worker unsigned int _preference;
386*03f9172cSAndroid Build Coastguard Worker unsigned int _reason;
387*03f9172cSAndroid Build Coastguard Worker
388*03f9172cSAndroid Build Coastguard Worker if (num == size) {
389*03f9172cSAndroid Build Coastguard Worker size = size ? size * 2 : 1;
390*03f9172cSAndroid Build Coastguard Worker tmp_chans = os_realloc_array(chans, size,
391*03f9172cSAndroid Build Coastguard Worker sizeof(*chans));
392*03f9172cSAndroid Build Coastguard Worker if (!tmp_chans) {
393*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR,
394*03f9172cSAndroid Build Coastguard Worker "Couldn't reallocate non_pref_chan");
395*03f9172cSAndroid Build Coastguard Worker goto fail;
396*03f9172cSAndroid Build Coastguard Worker }
397*03f9172cSAndroid Build Coastguard Worker chans = tmp_chans;
398*03f9172cSAndroid Build Coastguard Worker }
399*03f9172cSAndroid Build Coastguard Worker
400*03f9172cSAndroid Build Coastguard Worker chan = &chans[num];
401*03f9172cSAndroid Build Coastguard Worker
402*03f9172cSAndroid Build Coastguard Worker ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
403*03f9172cSAndroid Build Coastguard Worker &_chan, &_preference, &_reason);
404*03f9172cSAndroid Build Coastguard Worker if (ret != 4 ||
405*03f9172cSAndroid Build Coastguard Worker _oper_class > 255 || _chan > 255 ||
406*03f9172cSAndroid Build Coastguard Worker _preference > 255 || _reason > 65535 ) {
407*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
408*03f9172cSAndroid Build Coastguard Worker token);
409*03f9172cSAndroid Build Coastguard Worker goto fail;
410*03f9172cSAndroid Build Coastguard Worker }
411*03f9172cSAndroid Build Coastguard Worker chan->oper_class = _oper_class;
412*03f9172cSAndroid Build Coastguard Worker chan->chan = _chan;
413*03f9172cSAndroid Build Coastguard Worker chan->preference = _preference;
414*03f9172cSAndroid Build Coastguard Worker chan->reason = _reason;
415*03f9172cSAndroid Build Coastguard Worker
416*03f9172cSAndroid Build Coastguard Worker if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
417*03f9172cSAndroid Build Coastguard Worker chan->chan, chan->reason)) {
418*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR,
419*03f9172cSAndroid Build Coastguard Worker "Invalid non_pref_chan: oper class %d chan %d reason %d",
420*03f9172cSAndroid Build Coastguard Worker chan->oper_class, chan->chan, chan->reason);
421*03f9172cSAndroid Build Coastguard Worker goto fail;
422*03f9172cSAndroid Build Coastguard Worker }
423*03f9172cSAndroid Build Coastguard Worker
424*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < num; i++)
425*03f9172cSAndroid Build Coastguard Worker if (wpa_non_pref_chan_is_eq(chan, &chans[i]))
426*03f9172cSAndroid Build Coastguard Worker break;
427*03f9172cSAndroid Build Coastguard Worker if (i != num) {
428*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR,
429*03f9172cSAndroid Build Coastguard Worker "oper class %d chan %d is duplicated",
430*03f9172cSAndroid Build Coastguard Worker chan->oper_class, chan->chan);
431*03f9172cSAndroid Build Coastguard Worker goto fail;
432*03f9172cSAndroid Build Coastguard Worker }
433*03f9172cSAndroid Build Coastguard Worker
434*03f9172cSAndroid Build Coastguard Worker num++;
435*03f9172cSAndroid Build Coastguard Worker }
436*03f9172cSAndroid Build Coastguard Worker
437*03f9172cSAndroid Build Coastguard Worker os_free(cmd);
438*03f9172cSAndroid Build Coastguard Worker
439*03f9172cSAndroid Build Coastguard Worker if (chans) {
440*03f9172cSAndroid Build Coastguard Worker qsort(chans, num, sizeof(struct wpa_mbo_non_pref_channel),
441*03f9172cSAndroid Build Coastguard Worker wpa_non_pref_chan_cmp);
442*03f9172cSAndroid Build Coastguard Worker }
443*03f9172cSAndroid Build Coastguard Worker
444*03f9172cSAndroid Build Coastguard Worker update:
445*03f9172cSAndroid Build Coastguard Worker os_free(wpa_s->non_pref_chan);
446*03f9172cSAndroid Build Coastguard Worker wpa_s->non_pref_chan = chans;
447*03f9172cSAndroid Build Coastguard Worker wpa_s->non_pref_chan_num = num;
448*03f9172cSAndroid Build Coastguard Worker wpas_mbo_non_pref_chan_changed(wpa_s);
449*03f9172cSAndroid Build Coastguard Worker
450*03f9172cSAndroid Build Coastguard Worker return 0;
451*03f9172cSAndroid Build Coastguard Worker
452*03f9172cSAndroid Build Coastguard Worker fail:
453*03f9172cSAndroid Build Coastguard Worker os_free(chans);
454*03f9172cSAndroid Build Coastguard Worker os_free(cmd);
455*03f9172cSAndroid Build Coastguard Worker return -1;
456*03f9172cSAndroid Build Coastguard Worker }
457*03f9172cSAndroid Build Coastguard Worker
458*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_scan_ie(struct wpa_supplicant * wpa_s,struct wpabuf * ie)459*03f9172cSAndroid Build Coastguard Worker void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie)
460*03f9172cSAndroid Build Coastguard Worker {
461*03f9172cSAndroid Build Coastguard Worker u8 *len;
462*03f9172cSAndroid Build Coastguard Worker
463*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
464*03f9172cSAndroid Build Coastguard Worker len = wpabuf_put(ie, 1);
465*03f9172cSAndroid Build Coastguard Worker
466*03f9172cSAndroid Build Coastguard Worker wpabuf_put_be24(ie, OUI_WFA);
467*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, MBO_OUI_TYPE);
468*03f9172cSAndroid Build Coastguard Worker
469*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, MBO_ATTR_ID_CELL_DATA_CAPA);
470*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, 1);
471*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, wpa_s->conf->mbo_cell_capa);
472*03f9172cSAndroid Build Coastguard Worker if (wpa_s->enable_oce & OCE_STA) {
473*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, OCE_ATTR_ID_CAPA_IND);
474*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, 1);
475*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(ie, OCE_RELEASE);
476*03f9172cSAndroid Build Coastguard Worker }
477*03f9172cSAndroid Build Coastguard Worker *len = (u8 *) wpabuf_put(ie, 0) - len - 1;
478*03f9172cSAndroid Build Coastguard Worker }
479*03f9172cSAndroid Build Coastguard Worker
480*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_ie_trans_req(struct wpa_supplicant * wpa_s,const u8 * mbo_ie,size_t len)481*03f9172cSAndroid Build Coastguard Worker void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
482*03f9172cSAndroid Build Coastguard Worker size_t len)
483*03f9172cSAndroid Build Coastguard Worker {
484*03f9172cSAndroid Build Coastguard Worker const u8 *pos;
485*03f9172cSAndroid Build Coastguard Worker u8 id, elen;
486*03f9172cSAndroid Build Coastguard Worker
487*03f9172cSAndroid Build Coastguard Worker if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
488*03f9172cSAndroid Build Coastguard Worker mbo_ie[3] != MBO_OUI_TYPE)
489*03f9172cSAndroid Build Coastguard Worker return;
490*03f9172cSAndroid Build Coastguard Worker
491*03f9172cSAndroid Build Coastguard Worker pos = mbo_ie + 4;
492*03f9172cSAndroid Build Coastguard Worker len -= 4;
493*03f9172cSAndroid Build Coastguard Worker
494*03f9172cSAndroid Build Coastguard Worker while (len >= 2) {
495*03f9172cSAndroid Build Coastguard Worker id = *pos++;
496*03f9172cSAndroid Build Coastguard Worker elen = *pos++;
497*03f9172cSAndroid Build Coastguard Worker len -= 2;
498*03f9172cSAndroid Build Coastguard Worker
499*03f9172cSAndroid Build Coastguard Worker if (elen > len)
500*03f9172cSAndroid Build Coastguard Worker goto fail;
501*03f9172cSAndroid Build Coastguard Worker
502*03f9172cSAndroid Build Coastguard Worker switch (id) {
503*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_CELL_DATA_PREF:
504*03f9172cSAndroid Build Coastguard Worker if (elen != 1)
505*03f9172cSAndroid Build Coastguard Worker goto fail;
506*03f9172cSAndroid Build Coastguard Worker
507*03f9172cSAndroid Build Coastguard Worker if (wpa_s->conf->mbo_cell_capa ==
508*03f9172cSAndroid Build Coastguard Worker MBO_CELL_CAPA_AVAILABLE) {
509*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_cell_pref_present = 1;
510*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_cell_preference = *pos;
511*03f9172cSAndroid Build Coastguard Worker } else {
512*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
513*03f9172cSAndroid Build Coastguard Worker "MBO: Station does not support "
514*03f9172cSAndroid Build Coastguard Worker "Cellular data connection");
515*03f9172cSAndroid Build Coastguard Worker }
516*03f9172cSAndroid Build Coastguard Worker break;
517*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_TRANSITION_REASON:
518*03f9172cSAndroid Build Coastguard Worker if (elen != 1)
519*03f9172cSAndroid Build Coastguard Worker goto fail;
520*03f9172cSAndroid Build Coastguard Worker
521*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_trans_reason_present = 1;
522*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_transition_reason = *pos;
523*03f9172cSAndroid Build Coastguard Worker break;
524*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_ASSOC_RETRY_DELAY:
525*03f9172cSAndroid Build Coastguard Worker if (elen != 2)
526*03f9172cSAndroid Build Coastguard Worker goto fail;
527*03f9172cSAndroid Build Coastguard Worker
528*03f9172cSAndroid Build Coastguard Worker if (wpa_s->wnm_mode &
529*03f9172cSAndroid Build Coastguard Worker WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
530*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
531*03f9172cSAndroid Build Coastguard Worker "MBO: Unexpected association retry delay, "
532*03f9172cSAndroid Build Coastguard Worker "BSS is terminating");
533*03f9172cSAndroid Build Coastguard Worker goto fail;
534*03f9172cSAndroid Build Coastguard Worker } else if (wpa_s->wnm_mode &
535*03f9172cSAndroid Build Coastguard Worker WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
536*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_assoc_retry_delay_present = 1;
537*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_assoc_retry_delay_sec = WPA_GET_LE16(pos);
538*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
539*03f9172cSAndroid Build Coastguard Worker "MBO: Association retry delay: %u",
540*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_assoc_retry_delay_sec);
541*03f9172cSAndroid Build Coastguard Worker } else {
542*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
543*03f9172cSAndroid Build Coastguard Worker "MBO: Association retry delay attribute "
544*03f9172cSAndroid Build Coastguard Worker "not in disassoc imminent mode");
545*03f9172cSAndroid Build Coastguard Worker }
546*03f9172cSAndroid Build Coastguard Worker
547*03f9172cSAndroid Build Coastguard Worker break;
548*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_AP_CAPA_IND:
549*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_NON_PREF_CHAN_REPORT:
550*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_CELL_DATA_CAPA:
551*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_ASSOC_DISALLOW:
552*03f9172cSAndroid Build Coastguard Worker case MBO_ATTR_ID_TRANSITION_REJECT_REASON:
553*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
554*03f9172cSAndroid Build Coastguard Worker "MBO: Attribute %d should not be included in BTM Request frame",
555*03f9172cSAndroid Build Coastguard Worker id);
556*03f9172cSAndroid Build Coastguard Worker break;
557*03f9172cSAndroid Build Coastguard Worker default:
558*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MBO: Unknown attribute id %u",
559*03f9172cSAndroid Build Coastguard Worker id);
560*03f9172cSAndroid Build Coastguard Worker return;
561*03f9172cSAndroid Build Coastguard Worker }
562*03f9172cSAndroid Build Coastguard Worker
563*03f9172cSAndroid Build Coastguard Worker pos += elen;
564*03f9172cSAndroid Build Coastguard Worker len -= elen;
565*03f9172cSAndroid Build Coastguard Worker }
566*03f9172cSAndroid Build Coastguard Worker
567*03f9172cSAndroid Build Coastguard Worker if (wpa_s->wnm_mbo_cell_pref_present)
568*03f9172cSAndroid Build Coastguard Worker wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
569*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_cell_preference);
570*03f9172cSAndroid Build Coastguard Worker
571*03f9172cSAndroid Build Coastguard Worker if (wpa_s->wnm_mbo_trans_reason_present)
572*03f9172cSAndroid Build Coastguard Worker wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
573*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_transition_reason);
574*03f9172cSAndroid Build Coastguard Worker
575*03f9172cSAndroid Build Coastguard Worker if (wpa_s->wnm_mbo_assoc_retry_delay_sec && wpa_s->current_bss)
576*03f9172cSAndroid Build Coastguard Worker wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
577*03f9172cSAndroid Build Coastguard Worker wpa_s->wnm_mbo_assoc_retry_delay_sec, 0);
578*03f9172cSAndroid Build Coastguard Worker
579*03f9172cSAndroid Build Coastguard Worker return;
580*03f9172cSAndroid Build Coastguard Worker fail:
581*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MBO IE parsing failed (id=%u len=%u left=%zu)",
582*03f9172cSAndroid Build Coastguard Worker id, elen, len);
583*03f9172cSAndroid Build Coastguard Worker }
584*03f9172cSAndroid Build Coastguard Worker
585*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant * wpa_s,u8 * pos,size_t len,enum mbo_transition_reject_reason reason)586*03f9172cSAndroid Build Coastguard Worker size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
587*03f9172cSAndroid Build Coastguard Worker size_t len,
588*03f9172cSAndroid Build Coastguard Worker enum mbo_transition_reject_reason reason)
589*03f9172cSAndroid Build Coastguard Worker {
590*03f9172cSAndroid Build Coastguard Worker u8 reject_attr[3];
591*03f9172cSAndroid Build Coastguard Worker
592*03f9172cSAndroid Build Coastguard Worker reject_attr[0] = MBO_ATTR_ID_TRANSITION_REJECT_REASON;
593*03f9172cSAndroid Build Coastguard Worker reject_attr[1] = 1;
594*03f9172cSAndroid Build Coastguard Worker reject_attr[2] = reason;
595*03f9172cSAndroid Build Coastguard Worker
596*03f9172cSAndroid Build Coastguard Worker return mbo_add_ie(pos, len, reject_attr, sizeof(reject_attr));
597*03f9172cSAndroid Build Coastguard Worker }
598*03f9172cSAndroid Build Coastguard Worker
599*03f9172cSAndroid Build Coastguard Worker
wpas_mbo_update_cell_capa(struct wpa_supplicant * wpa_s,u8 mbo_cell_capa)600*03f9172cSAndroid Build Coastguard Worker void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa)
601*03f9172cSAndroid Build Coastguard Worker {
602*03f9172cSAndroid Build Coastguard Worker u8 cell_capa[7];
603*03f9172cSAndroid Build Coastguard Worker
604*03f9172cSAndroid Build Coastguard Worker if (wpa_s->conf->mbo_cell_capa == mbo_cell_capa) {
605*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
606*03f9172cSAndroid Build Coastguard Worker "MBO: Cellular capability already set to %u",
607*03f9172cSAndroid Build Coastguard Worker mbo_cell_capa);
608*03f9172cSAndroid Build Coastguard Worker return;
609*03f9172cSAndroid Build Coastguard Worker }
610*03f9172cSAndroid Build Coastguard Worker
611*03f9172cSAndroid Build Coastguard Worker wpa_s->conf->mbo_cell_capa = mbo_cell_capa;
612*03f9172cSAndroid Build Coastguard Worker
613*03f9172cSAndroid Build Coastguard Worker cell_capa[0] = WLAN_EID_VENDOR_SPECIFIC;
614*03f9172cSAndroid Build Coastguard Worker cell_capa[1] = 5; /* Length */
615*03f9172cSAndroid Build Coastguard Worker WPA_PUT_BE24(cell_capa + 2, OUI_WFA);
616*03f9172cSAndroid Build Coastguard Worker cell_capa[5] = MBO_ATTR_ID_CELL_DATA_CAPA;
617*03f9172cSAndroid Build Coastguard Worker cell_capa[6] = mbo_cell_capa;
618*03f9172cSAndroid Build Coastguard Worker
619*03f9172cSAndroid Build Coastguard Worker wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
620*03f9172cSAndroid Build Coastguard Worker wpa_supplicant_set_default_scan_ies(wpa_s);
621*03f9172cSAndroid Build Coastguard Worker wpas_update_mbo_connect_params(wpa_s);
622*03f9172cSAndroid Build Coastguard Worker }
623*03f9172cSAndroid Build Coastguard Worker
624*03f9172cSAndroid Build Coastguard Worker
mbo_build_anqp_buf(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,u32 mbo_subtypes)625*03f9172cSAndroid Build Coastguard Worker struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
626*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, u32 mbo_subtypes)
627*03f9172cSAndroid Build Coastguard Worker {
628*03f9172cSAndroid Build Coastguard Worker struct wpabuf *anqp_buf;
629*03f9172cSAndroid Build Coastguard Worker u8 *len_pos;
630*03f9172cSAndroid Build Coastguard Worker u8 i;
631*03f9172cSAndroid Build Coastguard Worker
632*03f9172cSAndroid Build Coastguard Worker if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
633*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_INFO, "MBO: " MACSTR
634*03f9172cSAndroid Build Coastguard Worker " does not support MBO - cannot request MBO ANQP elements from it",
635*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid));
636*03f9172cSAndroid Build Coastguard Worker return NULL;
637*03f9172cSAndroid Build Coastguard Worker }
638*03f9172cSAndroid Build Coastguard Worker
639*03f9172cSAndroid Build Coastguard Worker /* Allocate size for the maximum case - all MBO subtypes are set */
640*03f9172cSAndroid Build Coastguard Worker anqp_buf = wpabuf_alloc(9 + MAX_MBO_ANQP_SUBTYPE);
641*03f9172cSAndroid Build Coastguard Worker if (!anqp_buf)
642*03f9172cSAndroid Build Coastguard Worker return NULL;
643*03f9172cSAndroid Build Coastguard Worker
644*03f9172cSAndroid Build Coastguard Worker len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
645*03f9172cSAndroid Build Coastguard Worker wpabuf_put_be24(anqp_buf, OUI_WFA);
646*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
647*03f9172cSAndroid Build Coastguard Worker
648*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_QUERY_LIST);
649*03f9172cSAndroid Build Coastguard Worker
650*03f9172cSAndroid Build Coastguard Worker /* The first valid MBO subtype is 1 */
651*03f9172cSAndroid Build Coastguard Worker for (i = 1; i <= MAX_MBO_ANQP_SUBTYPE; i++) {
652*03f9172cSAndroid Build Coastguard Worker if (mbo_subtypes & BIT(i))
653*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(anqp_buf, i);
654*03f9172cSAndroid Build Coastguard Worker }
655*03f9172cSAndroid Build Coastguard Worker
656*03f9172cSAndroid Build Coastguard Worker gas_anqp_set_element_len(anqp_buf, len_pos);
657*03f9172cSAndroid Build Coastguard Worker
658*03f9172cSAndroid Build Coastguard Worker return anqp_buf;
659*03f9172cSAndroid Build Coastguard Worker }
660*03f9172cSAndroid Build Coastguard Worker
661*03f9172cSAndroid Build Coastguard Worker
mbo_parse_rx_anqp_resp(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,const u8 * sa,const u8 * data,size_t slen)662*03f9172cSAndroid Build Coastguard Worker void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
663*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, const u8 *sa,
664*03f9172cSAndroid Build Coastguard Worker const u8 *data, size_t slen)
665*03f9172cSAndroid Build Coastguard Worker {
666*03f9172cSAndroid Build Coastguard Worker const u8 *pos = data;
667*03f9172cSAndroid Build Coastguard Worker u8 subtype;
668*03f9172cSAndroid Build Coastguard Worker
669*03f9172cSAndroid Build Coastguard Worker if (slen < 1)
670*03f9172cSAndroid Build Coastguard Worker return;
671*03f9172cSAndroid Build Coastguard Worker
672*03f9172cSAndroid Build Coastguard Worker subtype = *pos++;
673*03f9172cSAndroid Build Coastguard Worker slen--;
674*03f9172cSAndroid Build Coastguard Worker
675*03f9172cSAndroid Build Coastguard Worker switch (subtype) {
676*03f9172cSAndroid Build Coastguard Worker case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
677*03f9172cSAndroid Build Coastguard Worker if (slen < 1)
678*03f9172cSAndroid Build Coastguard Worker break;
679*03f9172cSAndroid Build Coastguard Worker wpa_msg(wpa_s, MSG_INFO, RX_MBO_ANQP MACSTR
680*03f9172cSAndroid Build Coastguard Worker " cell_conn_pref=%u", MAC2STR(sa), *pos);
681*03f9172cSAndroid Build Coastguard Worker break;
682*03f9172cSAndroid Build Coastguard Worker default:
683*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MBO: Unsupported ANQP subtype %u",
684*03f9172cSAndroid Build Coastguard Worker subtype);
685*03f9172cSAndroid Build Coastguard Worker break;
686*03f9172cSAndroid Build Coastguard Worker }
687*03f9172cSAndroid Build Coastguard Worker }
688