5fc41c20e68d41e65f2d40964b05b8388fa4cbc6
[openwrt/staging/jow.git] /
1 From 5abc7823bd01f69b8afbe1fd19f65fff86137c44 Mon Sep 17 00:00:00 2001
2 From: Venkateswara Naralasetty <vnaralas@codeaurora.org>
3 Date: Wed, 5 Dec 2018 11:23:53 +0100
4 Subject: [PATCH] wpa_supplicant: Add Multi-AP backhaul STA support
5
6 Advertise vendor specific Multi-AP IE in (Re)Association Request frames
7 and process Multi-AP IE from (Re)Association Response frames if the user
8 enables Multi-AP fuctionality. If the (Re)Association Response frame
9 does not contain the Multi-AP IE, disassociate.
10
11 This adds a new configuration parameter 'multi_ap_backhaul_sta' to
12 enable/disable Multi-AP functionality.
13
14 Enable 4-address mode after association (if the Association Response
15 frame contains the Multi-AP IE). Also enable the bridge in that case.
16 This is necessary because wpa_supplicant only enables the bridge in
17 wpa_drv_if_add(), which only gets called when an interface is added
18 through the control interface, not when it is configured from the
19 command line.
20
21 Signed-off-by: Venkateswara Naralasetty <vnaralas@codeaurora.org>
22 Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
23 Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
24 ---
25 src/drivers/driver.h | 9 ++++++
26 src/drivers/driver_nl80211.c | 44 ++++++++++++++++++++++++++
27 wpa_supplicant/config.c | 1 +
28 wpa_supplicant/config_ssid.h | 7 +++++
29 wpa_supplicant/driver_i.h | 8 +++++
30 wpa_supplicant/events.c | 50 ++++++++++++++++++++++++++++++
31 wpa_supplicant/sme.c | 16 ++++++++++
32 wpa_supplicant/wpa_supplicant.c | 18 +++++++++++
33 wpa_supplicant/wpa_supplicant.conf | 7 +++++
34 wpa_supplicant/wpa_supplicant_i.h | 1 +
35 10 files changed, 161 insertions(+)
36
37 --- a/src/drivers/driver.h
38 +++ b/src/drivers/driver.h
39 @@ -4100,6 +4100,15 @@ struct wpa_driver_ops {
40 */
41 int (*send_external_auth_status)(void *priv,
42 struct external_auth *params);
43 +
44 + /**
45 + * set_4addr_mode - Set 4-address mode
46 + * @priv: Private driver interface data
47 + * @bridge_ifname: Bridge interface name
48 + * @val: 0 - disable 4addr mode, 1 - enable 4addr mode
49 + * Returns: 0 on success, < 0 on failure
50 + */
51 + int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
52 };
53
54 /**
55 --- a/src/drivers/driver_nl80211.c
56 +++ b/src/drivers/driver_nl80211.c
57 @@ -10728,6 +10728,49 @@ fail:
58 }
59
60
61 +static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
62 + int val)
63 +{
64 + struct i802_bss *bss = priv;
65 + struct wpa_driver_nl80211_data *drv = bss->drv;
66 + struct nl_msg *msg;
67 + int ret = -ENOBUFS;
68 +
69 + wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
70 + val ? "Enable" : "Disable", bridge_ifname);
71 +
72 + msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
73 + if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
74 + goto fail;
75 +
76 + if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
77 + if (linux_br_del_if(drv->global->ioctl_sock,
78 + bridge_ifname, bss->ifname)) {
79 + wpa_printf(MSG_ERROR,
80 + "nl80211: Failed to remove interface %s from bridge %s",
81 + bss->ifname, bridge_ifname);
82 + return -1;
83 + }
84 + bss->added_if_into_bridge = 0;
85 + }
86 +
87 + ret = send_and_recv_msgs(drv, msg, NULL, NULL);
88 + msg = NULL;
89 + if (!ret) {
90 + if (bridge_ifname[0] && val &&
91 + i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
92 + return -1;
93 + return 0;
94 + }
95 +
96 +fail:
97 + nlmsg_free(msg);
98 + wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
99 +
100 + return ret;
101 +}
102 +
103 +
104 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
105 .name = "nl80211",
106 .desc = "Linux nl80211/cfg80211",
107 @@ -10856,4 +10899,5 @@ const struct wpa_driver_ops wpa_driver_n
108 .get_ext_capab = nl80211_get_ext_capab,
109 .update_connect_params = nl80211_update_connection_params,
110 .send_external_auth_status = nl80211_send_external_auth_status,
111 + .set_4addr_mode = nl80211_set_4addr_mode,
112 };
113 --- a/wpa_supplicant/config.c
114 +++ b/wpa_supplicant/config.c
115 @@ -2416,6 +2416,7 @@ static const struct parse_data ssid_fiel
116 #endif /* CONFIG_DPP */
117 { INT_RANGE(owe_group, 0, 65535) },
118 { INT_RANGE(owe_only, 0, 1) },
119 + { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
120 };
121
122 #undef OFFSET
123 --- a/wpa_supplicant/config_ssid.h
124 +++ b/wpa_supplicant/config_ssid.h
125 @@ -950,6 +950,13 @@ struct wpa_ssid {
126 * the selection attempts for OWE BSS exceed the configured threshold.
127 */
128 int owe_transition_bss_select_count;
129 +
130 + /**
131 + * multi_ap_backhaul_sta - Multi-AP backhaul STA
132 + * 0 = normal (non-Multi-AP) station
133 + * 1 = Multi-AP backhaul station
134 + */
135 + int multi_ap_backhaul_sta;
136 };
137
138 #endif /* CONFIG_SSID_H */
139 --- a/wpa_supplicant/driver_i.h
140 +++ b/wpa_supplicant/driver_i.h
141 @@ -1046,4 +1046,12 @@ wpa_drv_send_external_auth_status(struct
142 params);
143 }
144
145 +static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
146 +{
147 + if (!wpa_s->driver->set_4addr_mode)
148 + return -1;
149 + return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv,
150 + wpa_s->bridge_ifname, val);
151 +}
152 +
153 #endif /* DRIVER_I_H */
154 --- a/wpa_supplicant/events.c
155 +++ b/wpa_supplicant/events.c
156 @@ -324,6 +324,9 @@ void wpa_supplicant_mark_disassoc(struct
157 os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
158 #endif /* CONFIG_TESTING_OPTIONS */
159 wpa_s->ieee80211ac = 0;
160 +
161 + if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
162 + wpa_s->enabled_4addr_mode = 0;
163 }
164
165
166 @@ -2267,6 +2270,50 @@ static void interworking_process_assoc_r
167 #endif /* CONFIG_INTERWORKING */
168
169
170 +static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
171 + const u8 *ies, size_t ies_len)
172 +{
173 + struct ieee802_11_elems elems;
174 + const u8 *map_sub_elem, *pos;
175 + size_t len;
176 +
177 + if (!wpa_s->current_ssid ||
178 + !wpa_s->current_ssid->multi_ap_backhaul_sta ||
179 + !ies ||
180 + ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
181 + return;
182 +
183 + if (!elems.multi_ap || elems.multi_ap_len < 7) {
184 + wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
185 + goto fail;
186 + }
187 +
188 + pos = elems.multi_ap + 4;
189 + len = elems.multi_ap_len - 4;
190 +
191 + map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
192 + if (!map_sub_elem || map_sub_elem[1] < 1) {
193 + wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
194 + goto fail;
195 + }
196 +
197 + if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
198 + wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
199 + goto fail;
200 + }
201 +
202 + if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
203 + wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
204 + goto fail;
205 + }
206 + wpa_s->enabled_4addr_mode = 1;
207 + return;
208 +
209 +fail:
210 + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
211 +}
212 +
213 +
214 #ifdef CONFIG_FST
215 static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
216 const u8 *ie, size_t ie_len)
217 @@ -2343,6 +2390,9 @@ static int wpa_supplicant_event_associnf
218 get_ie(data->assoc_info.resp_ies,
219 data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
220 wpa_s->ieee80211ac = 1;
221 +
222 + multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
223 + data->assoc_info.resp_ies_len);
224 }
225 if (data->assoc_info.beacon_ies)
226 wpa_hexdump(MSG_DEBUG, "beacon_ies",
227 --- a/wpa_supplicant/sme.c
228 +++ b/wpa_supplicant/sme.c
229 @@ -1552,6 +1552,22 @@ void sme_associate(struct wpa_supplicant
230 }
231 #endif /* CONFIG_OWE */
232
233 + if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
234 + size_t multi_ap_ie_len;
235 +
236 + multi_ap_ie_len = add_multi_ap_ie(
237 + wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
238 + sizeof(wpa_s->sme.assoc_req_ie) -
239 + wpa_s->sme.assoc_req_ie_len,
240 + MULTI_AP_BACKHAUL_STA);
241 + if (multi_ap_ie_len == 0) {
242 + wpa_printf(MSG_ERROR,
243 + "Multi-AP: Failed to build Multi-AP IE");
244 + return;
245 + }
246 + wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
247 + }
248 +
249 params.bssid = bssid;
250 params.ssid = wpa_s->sme.ssid;
251 params.ssid_len = wpa_s->sme.ssid_len;
252 --- a/wpa_supplicant/wpa_supplicant.c
253 +++ b/wpa_supplicant/wpa_supplicant.c
254 @@ -2893,6 +2893,21 @@ static u8 * wpas_populate_assoc_ies(
255 }
256 #endif /* CONFIG_IEEE80211R */
257
258 + if (ssid->multi_ap_backhaul_sta) {
259 + size_t multi_ap_ie_len;
260 +
261 + multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
262 + max_wpa_ie_len - wpa_ie_len,
263 + MULTI_AP_BACKHAUL_STA);
264 + if (multi_ap_ie_len == 0) {
265 + wpa_printf(MSG_ERROR,
266 + "Multi-AP: Failed to build Multi-AP IE");
267 + os_free(wpa_ie);
268 + return NULL;
269 + }
270 + wpa_ie_len += multi_ap_ie_len;
271 + }
272 +
273 params->wpa_ie = wpa_ie;
274 params->wpa_ie_len = wpa_ie_len;
275 params->auth_alg = algs;
276 @@ -3377,6 +3392,9 @@ void wpa_supplicant_deauthenticate(struc
277 zero_addr = 1;
278 }
279
280 + if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
281 + wpa_s->enabled_4addr_mode = 0;
282 +
283 #ifdef CONFIG_TDLS
284 wpa_tdls_teardown_peers(wpa_s->wpa);
285 #endif /* CONFIG_TDLS */
286 --- a/wpa_supplicant/wpa_supplicant.conf
287 +++ b/wpa_supplicant/wpa_supplicant.conf
288 @@ -1399,6 +1399,13 @@ fast_reauth=1
289 # 2: MCS 0-9
290 # 3: not supported
291
292 +# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
293 +# 0 = normal STA (default)
294 +# 1 = backhaul STA
295 +# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not
296 +# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
297 +# added to a bridge to allow forwarding frames over this backhaul link.
298 +
299 ##### Fast Session Transfer (FST) support #####################################
300 #
301 # The options in this section are only available when the build configuration
302 --- a/wpa_supplicant/wpa_supplicant_i.h
303 +++ b/wpa_supplicant/wpa_supplicant_i.h
304 @@ -1242,6 +1242,7 @@ struct wpa_supplicant {
305 unsigned int disable_fils:1;
306 #endif /* CONFIG_FILS */
307 unsigned int ieee80211ac:1;
308 + unsigned int enabled_4addr_mode:1;
309 };
310
311