mesh: Add timer for SAE authentication in RSN mesh
[mech_eap.git] / wpa_supplicant / mesh_mpm.c
1 /*
2  * WPA Supplicant - Basic mesh peer management
3  * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "common/ieee802_11_defs.h"
14 #include "ap/hostapd.h"
15 #include "ap/sta_info.h"
16 #include "ap/ieee802_11.h"
17 #include "wpa_supplicant_i.h"
18 #include "driver_i.h"
19 #include "mesh_mpm.h"
20 #include "mesh_rsn.h"
21
22 /* TODO make configurable */
23 #define dot11MeshMaxRetries 10
24 #define dot11MeshRetryTimeout 1
25 #define dot11MeshConfirmTimeout 1
26 #define dot11MeshHoldingTimeout 1
27
28 struct mesh_peer_mgmt_ie {
29         const u8 *proto_id;
30         const u8 *llid;
31         const u8 *plid;
32         const u8 *reason;
33         const u8 *pmk;
34 };
35
36 static void plink_timer(void *eloop_ctx, void *user_data);
37
38
39 enum plink_event {
40         PLINK_UNDEFINED,
41         OPN_ACPT,
42         OPN_RJCT,
43         OPN_IGNR,
44         CNF_ACPT,
45         CNF_RJCT,
46         CNF_IGNR,
47         CLS_ACPT,
48         CLS_IGNR
49 };
50
51 static const char * const mplstate[] = {
52         [PLINK_LISTEN] = "LISTEN",
53         [PLINK_OPEN_SENT] = "OPEN_SENT",
54         [PLINK_OPEN_RCVD] = "OPEN_RCVD",
55         [PLINK_CNF_RCVD] = "CNF_RCVD",
56         [PLINK_ESTAB] = "ESTAB",
57         [PLINK_HOLDING] = "HOLDING",
58         [PLINK_BLOCKED] = "BLOCKED"
59 };
60
61 static const char * const mplevent[] = {
62         [PLINK_UNDEFINED] = "UNDEFINED",
63         [OPN_ACPT] = "OPN_ACPT",
64         [OPN_RJCT] = "OPN_RJCT",
65         [OPN_IGNR] = "OPN_IGNR",
66         [CNF_ACPT] = "CNF_ACPT",
67         [CNF_RJCT] = "CNF_RJCT",
68         [CNF_IGNR] = "CNF_IGNR",
69         [CLS_ACPT] = "CLS_ACPT",
70         [CLS_IGNR] = "CLS_IGNR"
71 };
72
73
74 static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
75                                     u8 action_field,
76                                     const u8 *ie, size_t len,
77                                     struct mesh_peer_mgmt_ie *mpm_ie)
78 {
79         os_memset(mpm_ie, 0, sizeof(*mpm_ie));
80
81         /* remove optional PMK at end */
82         if (len >= 16) {
83                 len -= 16;
84                 mpm_ie->pmk = ie + len - 16;
85         }
86
87         if ((action_field == PLINK_OPEN && len != 4) ||
88             (action_field == PLINK_CONFIRM && len != 6) ||
89             (action_field == PLINK_CLOSE && len != 6 && len != 8)) {
90                 wpa_msg(wpa_s, MSG_DEBUG, "MPM: Invalid peer mgmt ie");
91                 return -1;
92         }
93
94         /* required fields */
95         if (len < 4)
96                 return -1;
97         mpm_ie->proto_id = ie;
98         mpm_ie->llid = ie + 2;
99         ie += 4;
100         len -= 4;
101
102         /* close reason is always present at end for close */
103         if (action_field == PLINK_CLOSE) {
104                 if (len < 2)
105                         return -1;
106                 mpm_ie->reason = ie + len - 2;
107                 len -= 2;
108         }
109
110         /* plid, present for confirm, and possibly close */
111         if (len)
112                 mpm_ie->plid = ie;
113
114         return 0;
115 }
116
117
118 static int plink_free_count(struct hostapd_data *hapd)
119 {
120         if (hapd->max_plinks > hapd->num_plinks)
121                 return hapd->max_plinks - hapd->num_plinks;
122         return 0;
123 }
124
125
126 static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
127                            struct sta_info *sta,
128                            struct ieee802_11_elems *elems)
129 {
130         if (!elems->supp_rates) {
131                 wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
132                         MAC2STR(sta->addr));
133                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
134         }
135
136         if (elems->supp_rates_len + elems->ext_supp_rates_len >
137             sizeof(sta->supported_rates)) {
138                 wpa_msg(wpa_s, MSG_ERROR,
139                         "Invalid supported rates element length " MACSTR
140                         " %d+%d", MAC2STR(sta->addr), elems->supp_rates_len,
141                         elems->ext_supp_rates_len);
142                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
143         }
144
145         sta->supported_rates_len = merge_byte_arrays(
146                 sta->supported_rates, sizeof(sta->supported_rates),
147                 elems->supp_rates, elems->supp_rates_len,
148                 elems->ext_supp_rates, elems->ext_supp_rates_len);
149
150         return WLAN_STATUS_SUCCESS;
151 }
152
153
154 /* return true if elems from a neighbor match this MBSS */
155 static Boolean matches_local(struct wpa_supplicant *wpa_s,
156                              struct ieee802_11_elems *elems)
157 {
158         struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
159
160         if (elems->mesh_config_len < 5)
161                 return FALSE;
162
163         return (mconf->meshid_len == elems->mesh_id_len &&
164                 os_memcmp(mconf->meshid, elems->mesh_id,
165                           elems->mesh_id_len) == 0 &&
166                 mconf->mesh_pp_id == elems->mesh_config[0] &&
167                 mconf->mesh_pm_id == elems->mesh_config[1] &&
168                 mconf->mesh_cc_id == elems->mesh_config[2] &&
169                 mconf->mesh_sp_id == elems->mesh_config[3] &&
170                 mconf->mesh_auth_id == elems->mesh_config[4]);
171 }
172
173
174 /* check if local link id is already used with another peer */
175 static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
176 {
177         struct sta_info *sta;
178         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
179
180         for (sta = hapd->sta_list; sta; sta = sta->next) {
181                 if (sta->my_lid == llid)
182                         return TRUE;
183         }
184
185         return FALSE;
186 }
187
188
189 /* generate an llid for a link and set to initial state */
190 static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
191                                struct sta_info *sta)
192 {
193         u16 llid;
194
195         do {
196                 if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
197                         continue;
198         } while (!llid || llid_in_use(wpa_s, llid));
199
200         sta->my_lid = llid;
201         sta->peer_lid = 0;
202         sta->plink_state = PLINK_LISTEN;
203 }
204
205
206 static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
207                                        struct sta_info *sta,
208                                        enum plink_action_field type,
209                                        u16 close_reason)
210 {
211         struct wpabuf *buf;
212         struct hostapd_iface *ifmsh = wpa_s->ifmsh;
213         struct hostapd_data *bss = ifmsh->bss[0];
214         struct mesh_conf *conf = ifmsh->mconf;
215         u8 supp_rates[2 + 2 + 32];
216         u8 *pos, *cat;
217         u8 ie_len, add_plid = 0;
218         int ret;
219         int ampe = conf->security & MESH_CONF_SEC_AMPE;
220
221         if (!sta)
222                 return;
223
224         buf = wpabuf_alloc(2 +      /* capability info */
225                            2 +      /* AID */
226                            2 + 8 +  /* supported rates */
227                            2 + (32 - 8) +
228                            2 + 32 + /* mesh ID */
229                            2 + 7 +  /* mesh config */
230                            2 + 26 + /* HT capabilities */
231                            2 + 22 + /* HT operation */
232                            2 + 23 + /* peering management */
233                            2 + 96 + /* AMPE */
234                            2 + 16); /* MIC */
235         if (!buf)
236                 return;
237
238         cat = wpabuf_mhead_u8(buf);
239         wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
240         wpabuf_put_u8(buf, type);
241
242         if (type != PLINK_CLOSE) {
243                 /* capability info */
244                 wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
245
246                 if (type == PLINK_CONFIRM)
247                         wpabuf_put_le16(buf, sta->peer_lid);
248
249                 /* IE: supp + ext. supp rates */
250                 pos = hostapd_eid_supp_rates(bss, supp_rates);
251                 pos = hostapd_eid_ext_supp_rates(bss, pos);
252                 wpabuf_put_data(buf, supp_rates, pos - supp_rates);
253
254                 /* IE: Mesh ID */
255                 wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
256                 wpabuf_put_u8(buf, conf->meshid_len);
257                 wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
258
259                 /* IE: mesh conf */
260                 wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG);
261                 wpabuf_put_u8(buf, 7);
262                 wpabuf_put_u8(buf, conf->mesh_pp_id);
263                 wpabuf_put_u8(buf, conf->mesh_pm_id);
264                 wpabuf_put_u8(buf, conf->mesh_cc_id);
265                 wpabuf_put_u8(buf, conf->mesh_sp_id);
266                 wpabuf_put_u8(buf, conf->mesh_auth_id);
267                 /* TODO: formation info */
268                 wpabuf_put_u8(buf, 0);
269                 /* always forwarding & accepting plinks for now */
270                 wpabuf_put_u8(buf, 0x1 | 0x8);
271         } else {        /* Peer closing frame */
272                 /* IE: Mesh ID */
273                 wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
274                 wpabuf_put_u8(buf, conf->meshid_len);
275                 wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
276         }
277
278         /* IE: Mesh Peering Management element */
279         ie_len = 4;
280         if (ampe)
281                 ie_len += PMKID_LEN;
282         switch (type) {
283         case PLINK_OPEN:
284                 break;
285         case PLINK_CONFIRM:
286                 ie_len += 2;
287                 add_plid = 1;
288                 break;
289         case PLINK_CLOSE:
290                 ie_len += 2;
291                 add_plid = 1;
292                 ie_len += 2; /* reason code */
293                 break;
294         }
295
296         wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
297         wpabuf_put_u8(buf, ie_len);
298         /* peering protocol */
299         if (ampe)
300                 wpabuf_put_le16(buf, 1);
301         else
302                 wpabuf_put_le16(buf, 0);
303         wpabuf_put_le16(buf, sta->my_lid);
304         if (add_plid)
305                 wpabuf_put_le16(buf, sta->peer_lid);
306         if (type == PLINK_CLOSE)
307                 wpabuf_put_le16(buf, close_reason);
308         if (ampe)
309                 mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
310                                    wpabuf_put(buf, PMKID_LEN));
311
312         /* TODO HT IEs */
313
314         if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
315                 wpa_msg(wpa_s, MSG_INFO,
316                         "Mesh MPM: failed to add AMPE and MIC IE");
317                 goto fail;
318         }
319
320         ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
321                                   sta->addr, wpa_s->own_addr, wpa_s->own_addr,
322                                   wpabuf_head(buf), wpabuf_len(buf), 0);
323         if (ret < 0)
324                 wpa_msg(wpa_s, MSG_INFO,
325                         "Mesh MPM: failed to send peering frame");
326
327 fail:
328         wpabuf_free(buf);
329 }
330
331
332 /* configure peering state in ours and driver's station entry */
333 static void
334 wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
335                          enum mesh_plink_state state)
336 {
337         struct hostapd_sta_add_params params;
338         int ret;
339
340         sta->plink_state = state;
341
342         os_memset(&params, 0, sizeof(params));
343         params.addr = sta->addr;
344         params.plink_state = state;
345         params.set = 1;
346
347         wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
348                 MAC2STR(sta->addr), mplstate[state]);
349         ret = wpa_drv_sta_add(wpa_s, &params);
350         if (ret) {
351                 wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
352                         ": %d", MAC2STR(sta->addr), ret);
353         }
354 }
355
356
357 static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
358                                  struct sta_info *sta)
359 {
360         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
361
362         eloop_cancel_timeout(plink_timer, wpa_s, sta);
363
364         if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
365                 ap_free_sta(hapd, sta);
366                 return;
367         }
368
369         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
370         sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
371         sta->mpm_retries = 0;
372 }
373
374
375 static void plink_timer(void *eloop_ctx, void *user_data)
376 {
377         struct wpa_supplicant *wpa_s = eloop_ctx;
378         struct sta_info *sta = user_data;
379         u16 reason = 0;
380
381         switch (sta->plink_state) {
382         case PLINK_OPEN_RCVD:
383         case PLINK_OPEN_SENT:
384                 /* retry timer */
385                 if (sta->mpm_retries < dot11MeshMaxRetries) {
386                         eloop_register_timeout(dot11MeshRetryTimeout, 0,
387                                                plink_timer, wpa_s, sta);
388                         mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
389                         sta->mpm_retries++;
390                         break;
391                 }
392                 reason = WLAN_REASON_MESH_MAX_RETRIES;
393                 /* fall through on else */
394
395         case PLINK_CNF_RCVD:
396                 /* confirm timer */
397                 if (!reason)
398                         reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
399                 sta->plink_state = PLINK_HOLDING;
400                 eloop_register_timeout(dot11MeshHoldingTimeout, 0,
401                                        plink_timer, wpa_s, sta);
402                 mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
403                 break;
404         case PLINK_HOLDING:
405                 /* holding timer */
406                 mesh_mpm_fsm_restart(wpa_s, sta);
407                 break;
408         default:
409                 break;
410         }
411 }
412
413
414 /* initiate peering with station */
415 static void
416 mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
417                     enum mesh_plink_state next_state)
418 {
419         eloop_cancel_timeout(plink_timer, wpa_s, sta);
420         eloop_register_timeout(dot11MeshRetryTimeout, 0, plink_timer,
421                                wpa_s, sta);
422         mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
423         wpa_mesh_set_plink_state(wpa_s, sta, next_state);
424 }
425
426
427 int mesh_mpm_plink_close(struct hostapd_data *hapd,
428                          struct sta_info *sta, void *ctx)
429 {
430         struct wpa_supplicant *wpa_s = ctx;
431         int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
432
433         if (sta) {
434                 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
435                 mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
436                 wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
437                            MAC2STR(sta->addr));
438                 eloop_cancel_timeout(plink_timer, wpa_s, sta);
439                 return 0;
440         }
441
442         return 1;
443 }
444
445
446 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
447 {
448         struct hostapd_data *hapd = ifmsh->bss[0];
449
450         /* notify peers we're leaving */
451         ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s);
452
453         hapd->num_plinks = 0;
454         hostapd_free_stas(hapd);
455 }
456
457
458 /* for mesh_rsn to indicate this peer has completed authentication, and we're
459  * ready to start AMPE */
460 void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
461 {
462         struct hostapd_data *data = wpa_s->ifmsh->bss[0];
463         struct hostapd_sta_add_params params;
464         struct sta_info *sta;
465         int ret;
466
467         sta = ap_get_sta(data, addr);
468         if (!sta) {
469                 wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer");
470                 return;
471         }
472
473         /* TODO: Should do nothing if this STA is already authenticated, but
474          * the AP code already sets this flag. */
475         sta->flags |= WLAN_STA_AUTH;
476
477         mesh_rsn_init_ampe_sta(wpa_s, sta);
478
479         os_memset(&params, 0, sizeof(params));
480         params.addr = sta->addr;
481         params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
482         params.set = 1;
483
484         wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
485                 MAC2STR(sta->addr));
486         ret = wpa_drv_sta_add(wpa_s, &params);
487         if (ret) {
488                 wpa_msg(wpa_s, MSG_ERROR,
489                         "Driver failed to set " MACSTR ": %d",
490                         MAC2STR(sta->addr), ret);
491         }
492
493         if (!sta->my_lid)
494                 mesh_mpm_init_link(wpa_s, sta);
495
496         mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
497 }
498
499
500 void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
501                             struct ieee802_11_elems *elems)
502 {
503         struct hostapd_sta_add_params params;
504         struct mesh_conf *conf = wpa_s->ifmsh->mconf;
505         struct hostapd_data *data = wpa_s->ifmsh->bss[0];
506         struct sta_info *sta;
507         struct wpa_ssid *ssid = wpa_s->current_ssid;
508         int ret = 0;
509
510         sta = ap_get_sta(data, addr);
511         if (!sta) {
512                 sta = ap_sta_add(data, addr);
513                 if (!sta)
514                         return;
515         }
516
517         /* initialize sta */
518         if (copy_supp_rates(wpa_s, sta, elems))
519                 return;
520
521         mesh_mpm_init_link(wpa_s, sta);
522
523         /* insert into driver */
524         os_memset(&params, 0, sizeof(params));
525         params.supp_rates = sta->supported_rates;
526         params.supp_rates_len = sta->supported_rates_len;
527         params.addr = addr;
528         params.plink_state = sta->plink_state;
529         params.aid = sta->peer_lid;
530         params.listen_interval = 100;
531         /* TODO: HT capabilities */
532         params.flags |= WPA_STA_WMM;
533         params.flags_mask |= WPA_STA_AUTHENTICATED;
534         if (conf->security == MESH_CONF_SEC_NONE) {
535                 params.flags |= WPA_STA_AUTHORIZED;
536                 params.flags |= WPA_STA_AUTHENTICATED;
537         } else {
538                 sta->flags |= WLAN_STA_MFP;
539                 params.flags |= WPA_STA_MFP;
540         }
541
542         ret = wpa_drv_sta_add(wpa_s, &params);
543         if (ret) {
544                 wpa_msg(wpa_s, MSG_ERROR,
545                         "Driver failed to insert " MACSTR ": %d",
546                         MAC2STR(addr), ret);
547                 return;
548         }
549
550         if (ssid && ssid->no_auto_peer) {
551                 wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
552                         MACSTR " because of no_auto_peer", MAC2STR(addr));
553                 return;
554         }
555
556         if (conf->security == MESH_CONF_SEC_NONE)
557                 mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
558         else
559                 mesh_rsn_auth_sae_sta(wpa_s, sta);
560 }
561
562
563 void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
564 {
565         struct hostapd_frame_info fi;
566
567         os_memset(&fi, 0, sizeof(fi));
568         fi.datarate = rx_mgmt->datarate;
569         fi.ssi_signal = rx_mgmt->ssi_signal;
570         ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
571                         rx_mgmt->frame_len, &fi);
572 }
573
574
575 static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
576                                  struct sta_info *sta)
577 {
578         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
579         struct mesh_conf *conf = wpa_s->ifmsh->mconf;
580         u8 seq[6] = {};
581
582         wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
583                 MAC2STR(sta->addr));
584
585         if (conf->security & MESH_CONF_SEC_AMPE) {
586                 wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
587                                 seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
588                 wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
589                                 seq, sizeof(seq),
590                                 sta->mgtk, sizeof(sta->mgtk));
591                 wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
592                                 seq, sizeof(seq),
593                                 sta->mgtk, sizeof(sta->mgtk));
594
595                 wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
596                 wpa_hexdump_key(MSG_DEBUG, "mgtk:",
597                                 sta->mgtk, sizeof(sta->mgtk));
598         }
599
600         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
601         hapd->num_plinks++;
602
603         sta->flags |= WLAN_STA_ASSOC;
604
605         eloop_cancel_timeout(plink_timer, wpa_s, sta);
606
607         /* Send ctrl event */
608         wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
609                      MAC2STR(sta->addr));
610 }
611
612
613 static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
614                          enum plink_event event)
615 {
616         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
617         struct mesh_conf *conf = wpa_s->ifmsh->mconf;
618         u16 reason = 0;
619
620         wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
621                 MAC2STR(sta->addr), mplstate[sta->plink_state],
622                 mplevent[event]);
623
624         switch (sta->plink_state) {
625         case PLINK_LISTEN:
626                 switch (event) {
627                 case CLS_ACPT:
628                         mesh_mpm_fsm_restart(wpa_s, sta);
629                         break;
630                 case OPN_ACPT:
631                         mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
632                         mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
633                                                    0);
634                         break;
635                 default:
636                         break;
637                 }
638                 break;
639         case PLINK_OPEN_SENT:
640                 switch (event) {
641                 case OPN_RJCT:
642                 case CNF_RJCT:
643                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
644                         /* fall-through */
645                 case CLS_ACPT:
646                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
647                         if (!reason)
648                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
649                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
650                                                plink_timer, wpa_s, sta);
651                         mesh_mpm_send_plink_action(wpa_s, sta,
652                                                    PLINK_CLOSE, reason);
653                         break;
654                 case OPN_ACPT:
655                         /* retry timer is left untouched */
656                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
657                         mesh_mpm_send_plink_action(wpa_s, sta,
658                                                    PLINK_CONFIRM, 0);
659                         break;
660                 case CNF_ACPT:
661                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
662                         eloop_register_timeout(dot11MeshConfirmTimeout, 0,
663                                                plink_timer, wpa_s, sta);
664                         break;
665                 default:
666                         break;
667                 }
668                 break;
669         case PLINK_OPEN_RCVD:
670                 switch (event) {
671                 case OPN_RJCT:
672                 case CNF_RJCT:
673                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
674                         /* fall-through */
675                 case CLS_ACPT:
676                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
677                         if (!reason)
678                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
679                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
680                                                plink_timer, wpa_s, sta);
681                         sta->mpm_close_reason = reason;
682                         mesh_mpm_send_plink_action(wpa_s, sta,
683                                                    PLINK_CLOSE, reason);
684                         break;
685                 case OPN_ACPT:
686                         mesh_mpm_send_plink_action(wpa_s, sta,
687                                                    PLINK_CONFIRM, 0);
688                         break;
689                 case CNF_ACPT:
690                         if (conf->security & MESH_CONF_SEC_AMPE)
691                                 mesh_rsn_derive_mtk(wpa_s, sta);
692                         mesh_mpm_plink_estab(wpa_s, sta);
693                         break;
694                 default:
695                         break;
696                 }
697                 break;
698         case PLINK_CNF_RCVD:
699                 switch (event) {
700                 case OPN_RJCT:
701                 case CNF_RJCT:
702                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
703                         /* fall-through */
704                 case CLS_ACPT:
705                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
706                         if (!reason)
707                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
708                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
709                                                plink_timer, wpa_s, sta);
710                         sta->mpm_close_reason = reason;
711                         mesh_mpm_send_plink_action(wpa_s, sta,
712                                                    PLINK_CLOSE, reason);
713                         break;
714                 case OPN_ACPT:
715                         mesh_mpm_plink_estab(wpa_s, sta);
716                         mesh_mpm_send_plink_action(wpa_s, sta,
717                                                    PLINK_CONFIRM, 0);
718                         break;
719                 default:
720                         break;
721                 }
722                 break;
723         case PLINK_ESTAB:
724                 switch (event) {
725                 case CLS_ACPT:
726                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
727                         reason = WLAN_REASON_MESH_CLOSE_RCVD;
728
729                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
730                                                plink_timer, wpa_s, sta);
731                         sta->mpm_close_reason = reason;
732
733                         wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
734                                 " closed with reason %d",
735                                 MAC2STR(sta->addr), reason);
736
737                         wpa_msg_ctrl(wpa_s, MSG_INFO,
738                                      MESH_PEER_DISCONNECTED MACSTR,
739                                      MAC2STR(sta->addr));
740
741                         hapd->num_plinks--;
742
743                         mesh_mpm_send_plink_action(wpa_s, sta,
744                                                    PLINK_CLOSE, reason);
745                         break;
746                 case OPN_ACPT:
747                         mesh_mpm_send_plink_action(wpa_s, sta,
748                                                    PLINK_CONFIRM, 0);
749                         break;
750                 default:
751                         break;
752                 }
753                 break;
754         case PLINK_HOLDING:
755                 switch (event) {
756                 case CLS_ACPT:
757                         mesh_mpm_fsm_restart(wpa_s, sta);
758                         break;
759                 case OPN_ACPT:
760                 case CNF_ACPT:
761                 case OPN_RJCT:
762                 case CNF_RJCT:
763                         reason = sta->mpm_close_reason;
764                         mesh_mpm_send_plink_action(wpa_s, sta,
765                                                    PLINK_CLOSE, reason);
766                         break;
767                 default:
768                         break;
769                 }
770                 break;
771         default:
772                 wpa_msg(wpa_s, MSG_DEBUG,
773                         "Unsupported MPM event %s for state %s",
774                         mplevent[event], mplstate[sta->plink_state]);
775                 break;
776         }
777 }
778
779
780 void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
781                         const struct ieee80211_mgmt *mgmt, size_t len)
782 {
783         u8 action_field;
784         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
785         struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
786         struct sta_info *sta;
787         u16 plid = 0, llid = 0;
788         enum plink_event event;
789         struct ieee802_11_elems elems;
790         struct mesh_peer_mgmt_ie peer_mgmt_ie;
791         const u8 *ies;
792         size_t ie_len;
793         int ret;
794
795         if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
796                 return;
797
798         action_field = mgmt->u.action.u.slf_prot_action.action;
799
800         ies = mgmt->u.action.u.slf_prot_action.variable;
801         ie_len = (const u8 *) mgmt + len -
802                 mgmt->u.action.u.slf_prot_action.variable;
803
804         /* at least expect mesh id and peering mgmt */
805         if (ie_len < 2 + 2)
806                 return;
807
808         if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
809                 ies += 2;       /* capability */
810                 ie_len -= 2;
811         }
812         if (action_field == PLINK_CONFIRM) {
813                 ies += 2;       /* aid */
814                 ie_len -= 2;
815         }
816
817         /* check for mesh peering, mesh id and mesh config IEs */
818         if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed)
819                 return;
820         if (!elems.peer_mgmt)
821                 return;
822         if ((action_field != PLINK_CLOSE) &&
823             (!elems.mesh_id || !elems.mesh_config))
824                 return;
825
826         if (action_field != PLINK_CLOSE && !matches_local(wpa_s, &elems))
827                 return;
828
829         ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
830                                        elems.peer_mgmt,
831                                        elems.peer_mgmt_len,
832                                        &peer_mgmt_ie);
833         if (ret)
834                 return;
835
836         /* the sender's llid is our plid and vice-versa */
837         plid = WPA_GET_LE16(peer_mgmt_ie.llid);
838         if (peer_mgmt_ie.plid)
839                 llid = WPA_GET_LE16(peer_mgmt_ie.plid);
840
841         sta = ap_get_sta(hapd, mgmt->sa);
842         if (!sta)
843                 return;
844
845 #ifdef CONFIG_SAE
846         /* peer is in sae_accepted? */
847         if (sta->sae && sta->sae->state != SAE_ACCEPTED)
848                 return;
849 #endif /* CONFIG_SAE */
850
851         if (!sta->my_lid)
852                 mesh_mpm_init_link(wpa_s, sta);
853
854         if (mconf->security & MESH_CONF_SEC_AMPE)
855                 if (mesh_rsn_process_ampe(wpa_s, sta, &elems,
856                                           &mgmt->u.action.category,
857                                           ies, ie_len))
858                         return;
859
860         if (sta->plink_state == PLINK_BLOCKED)
861                 return;
862
863         /* Now we will figure out the appropriate event... */
864         switch (action_field) {
865         case PLINK_OPEN:
866                 if (!plink_free_count(hapd) ||
867                     (sta->peer_lid && sta->peer_lid != plid)) {
868                         event = OPN_IGNR;
869                 } else {
870                         sta->peer_lid = plid;
871                         event = OPN_ACPT;
872                 }
873                 break;
874         case PLINK_CONFIRM:
875                 if (!plink_free_count(hapd) ||
876                     sta->my_lid != llid ||
877                     (sta->peer_lid && sta->peer_lid != plid)) {
878                         event = CNF_IGNR;
879                 } else {
880                         if (!sta->peer_lid)
881                                 sta->peer_lid = plid;
882                         event = CNF_ACPT;
883                 }
884                 break;
885         case PLINK_CLOSE:
886                 if (sta->plink_state == PLINK_ESTAB)
887                         /* Do not check for llid or plid. This does not
888                          * follow the standard but since multiple plinks
889                          * per cand are not supported, it is necessary in
890                          * order to avoid a livelock when MP A sees an
891                          * establish peer link to MP B but MP B does not
892                          * see it. This can be caused by a timeout in
893                          * B's peer link establishment or B being
894                          * restarted.
895                          */
896                         event = CLS_ACPT;
897                 else if (sta->peer_lid != plid)
898                         event = CLS_IGNR;
899                 else if (peer_mgmt_ie.plid && sta->my_lid != llid)
900                         event = CLS_IGNR;
901                 else
902                         event = CLS_ACPT;
903                 break;
904         default:
905                 wpa_msg(wpa_s, MSG_ERROR,
906                         "Mesh plink: unknown frame subtype");
907                 return;
908         }
909         mesh_mpm_fsm(wpa_s, sta, event);
910 }
911
912
913 /* called by ap_free_sta */
914 void mesh_mpm_free_sta(struct sta_info *sta)
915 {
916         eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
917         eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
918 }