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