5fc41c20e68d41e65f2d40964b05b8388fa4cbc6
[librecmc/librecmc.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