mesh: Add mesh peering manager
[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         int ret = 0;
494
495         sta = ap_get_sta(data, addr);
496         if (!sta) {
497                 sta = ap_sta_add(data, addr);
498                 if (!sta)
499                         return;
500         }
501
502         /* initialize sta */
503         if (copy_supp_rates(wpa_s, sta, elems))
504                 return;
505
506         mesh_mpm_init_link(wpa_s, sta);
507
508         /* insert into driver */
509         os_memset(&params, 0, sizeof(params));
510         params.supp_rates = sta->supported_rates;
511         params.supp_rates_len = sta->supported_rates_len;
512         params.addr = addr;
513         params.plink_state = sta->plink_state;
514         params.aid = sta->peer_lid;
515         params.listen_interval = 100;
516         /* TODO: HT capabilities */
517         params.flags |= WPA_STA_WMM;
518         params.flags_mask |= WPA_STA_AUTHENTICATED;
519         if (conf->security == MESH_CONF_SEC_NONE) {
520                 params.flags |= WPA_STA_AUTHORIZED;
521                 params.flags |= WPA_STA_AUTHENTICATED;
522         } else {
523                 sta->flags |= WLAN_STA_MFP;
524                 params.flags |= WPA_STA_MFP;
525         }
526
527         ret = wpa_drv_sta_add(wpa_s, &params);
528         if (ret) {
529                 wpa_msg(wpa_s, MSG_ERROR,
530                         "Driver failed to insert " MACSTR ": %d",
531                         MAC2STR(addr), ret);
532                 return;
533         }
534
535         mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
536 }
537
538
539 void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
540 {
541         struct hostapd_frame_info fi;
542
543         os_memset(&fi, 0, sizeof(fi));
544         fi.datarate = rx_mgmt->datarate;
545         fi.ssi_signal = rx_mgmt->ssi_signal;
546         ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
547                         rx_mgmt->frame_len, &fi);
548 }
549
550
551 static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
552                                  struct sta_info *sta)
553 {
554         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
555
556         wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
557                 MAC2STR(sta->addr));
558
559         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
560         hapd->num_plinks++;
561
562         sta->flags |= WLAN_STA_ASSOC;
563
564         eloop_cancel_timeout(plink_timer, wpa_s, sta);
565
566         /* Send ctrl event */
567         wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
568                      MAC2STR(sta->addr));
569 }
570
571
572 static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
573                          enum plink_event event)
574 {
575         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
576         u16 reason = 0;
577
578         wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
579                 MAC2STR(sta->addr), mplstate[sta->plink_state],
580                 mplevent[event]);
581
582         switch (sta->plink_state) {
583         case PLINK_LISTEN:
584                 switch (event) {
585                 case CLS_ACPT:
586                         mesh_mpm_fsm_restart(wpa_s, sta);
587                         break;
588                 case OPN_ACPT:
589                         mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
590                         mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
591                                                    0);
592                         break;
593                 default:
594                         break;
595                 }
596                 break;
597         case PLINK_OPEN_SENT:
598                 switch (event) {
599                 case OPN_RJCT:
600                 case CNF_RJCT:
601                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
602                         /* fall-through */
603                 case CLS_ACPT:
604                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
605                         if (!reason)
606                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
607                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
608                                                plink_timer, wpa_s, sta);
609                         mesh_mpm_send_plink_action(wpa_s, sta,
610                                                    PLINK_CLOSE, reason);
611                         break;
612                 case OPN_ACPT:
613                         /* retry timer is left untouched */
614                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
615                         mesh_mpm_send_plink_action(wpa_s, sta,
616                                                    PLINK_CONFIRM, 0);
617                         break;
618                 case CNF_ACPT:
619                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
620                         eloop_register_timeout(dot11MeshConfirmTimeout, 0,
621                                                plink_timer, wpa_s, sta);
622                         break;
623                 default:
624                         break;
625                 }
626                 break;
627         case PLINK_OPEN_RCVD:
628                 switch (event) {
629                 case OPN_RJCT:
630                 case CNF_RJCT:
631                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
632                         /* fall-through */
633                 case CLS_ACPT:
634                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
635                         if (!reason)
636                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
637                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
638                                                plink_timer, wpa_s, sta);
639                         sta->mpm_close_reason = reason;
640                         mesh_mpm_send_plink_action(wpa_s, sta,
641                                                    PLINK_CLOSE, reason);
642                         break;
643                 case OPN_ACPT:
644                         mesh_mpm_send_plink_action(wpa_s, sta,
645                                                    PLINK_CONFIRM, 0);
646                         break;
647                 case CNF_ACPT:
648                         mesh_mpm_plink_estab(wpa_s, sta);
649                         break;
650                 default:
651                         break;
652                 }
653                 break;
654         case PLINK_CNF_RCVD:
655                 switch (event) {
656                 case OPN_RJCT:
657                 case CNF_RJCT:
658                         reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
659                         /* fall-through */
660                 case CLS_ACPT:
661                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
662                         if (!reason)
663                                 reason = WLAN_REASON_MESH_CLOSE_RCVD;
664                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
665                                                plink_timer, wpa_s, sta);
666                         sta->mpm_close_reason = reason;
667                         mesh_mpm_send_plink_action(wpa_s, sta,
668                                                    PLINK_CLOSE, reason);
669                         break;
670                 case OPN_ACPT:
671                         mesh_mpm_plink_estab(wpa_s, sta);
672                         mesh_mpm_send_plink_action(wpa_s, sta,
673                                                    PLINK_CONFIRM, 0);
674                         break;
675                 default:
676                         break;
677                 }
678                 break;
679         case PLINK_ESTAB:
680                 switch (event) {
681                 case CLS_ACPT:
682                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
683                         reason = WLAN_REASON_MESH_CLOSE_RCVD;
684
685                         eloop_register_timeout(dot11MeshHoldingTimeout, 0,
686                                                plink_timer, wpa_s, sta);
687                         sta->mpm_close_reason = reason;
688
689                         wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
690                                 " closed with reason %d",
691                                 MAC2STR(sta->addr), reason);
692
693                         wpa_msg_ctrl(wpa_s, MSG_INFO,
694                                      MESH_PEER_DISCONNECTED MACSTR,
695                                      MAC2STR(sta->addr));
696
697                         hapd->num_plinks--;
698
699                         mesh_mpm_send_plink_action(wpa_s, sta,
700                                                    PLINK_CLOSE, reason);
701                         break;
702                 case OPN_ACPT:
703                         mesh_mpm_send_plink_action(wpa_s, sta,
704                                                    PLINK_CONFIRM, 0);
705                         break;
706                 default:
707                         break;
708                 }
709                 break;
710         case PLINK_HOLDING:
711                 switch (event) {
712                 case CLS_ACPT:
713                         mesh_mpm_fsm_restart(wpa_s, sta);
714                         break;
715                 case OPN_ACPT:
716                 case CNF_ACPT:
717                 case OPN_RJCT:
718                 case CNF_RJCT:
719                         reason = sta->mpm_close_reason;
720                         mesh_mpm_send_plink_action(wpa_s, sta,
721                                                    PLINK_CLOSE, reason);
722                         break;
723                 default:
724                         break;
725                 }
726                 break;
727         default:
728                 wpa_msg(wpa_s, MSG_DEBUG,
729                         "Unsupported MPM event %s for state %s",
730                         mplevent[event], mplstate[sta->plink_state]);
731                 break;
732         }
733 }
734
735
736 void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
737                         const struct ieee80211_mgmt *mgmt, size_t len)
738 {
739         u8 action_field;
740         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
741         struct sta_info *sta;
742         u16 plid = 0, llid = 0;
743         enum plink_event event;
744         struct ieee802_11_elems elems;
745         struct mesh_peer_mgmt_ie peer_mgmt_ie;
746         const u8 *ies;
747         size_t ie_len;
748         int ret;
749
750         if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
751                 return;
752
753         action_field = mgmt->u.action.u.slf_prot_action.action;
754
755         ies = mgmt->u.action.u.slf_prot_action.variable;
756         ie_len = (const u8 *) mgmt + len -
757                 mgmt->u.action.u.slf_prot_action.variable;
758
759         /* at least expect mesh id and peering mgmt */
760         if (ie_len < 2 + 2)
761                 return;
762
763         if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
764                 ies += 2;       /* capability */
765                 ie_len -= 2;
766         }
767         if (action_field == PLINK_CONFIRM) {
768                 ies += 2;       /* aid */
769                 ie_len -= 2;
770         }
771
772         /* check for mesh peering, mesh id and mesh config IEs */
773         if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed)
774                 return;
775         if (!elems.peer_mgmt)
776                 return;
777         if ((action_field != PLINK_CLOSE) &&
778             (!elems.mesh_id || !elems.mesh_config))
779                 return;
780
781         if (action_field != PLINK_CLOSE && !matches_local(wpa_s, &elems))
782                 return;
783
784         ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
785                                        elems.peer_mgmt,
786                                        elems.peer_mgmt_len,
787                                        &peer_mgmt_ie);
788         if (ret)
789                 return;
790
791         /* the sender's llid is our plid and vice-versa */
792         plid = WPA_GET_LE16(peer_mgmt_ie.llid);
793         if (peer_mgmt_ie.plid)
794                 llid = WPA_GET_LE16(peer_mgmt_ie.plid);
795
796         sta = ap_get_sta(hapd, mgmt->sa);
797         if (!sta)
798                 return;
799
800         if (!sta->my_lid)
801                 mesh_mpm_init_link(wpa_s, sta);
802
803         if (sta->plink_state == PLINK_BLOCKED)
804                 return;
805
806         /* Now we will figure out the appropriate event... */
807         switch (action_field) {
808         case PLINK_OPEN:
809                 if (!plink_free_count(hapd) ||
810                     (sta->peer_lid && sta->peer_lid != plid)) {
811                         event = OPN_IGNR;
812                 } else {
813                         sta->peer_lid = plid;
814                         event = OPN_ACPT;
815                 }
816                 break;
817         case PLINK_CONFIRM:
818                 if (!plink_free_count(hapd) ||
819                     sta->my_lid != llid ||
820                     (sta->peer_lid && sta->peer_lid != plid)) {
821                         event = CNF_IGNR;
822                 } else {
823                         if (!sta->peer_lid)
824                                 sta->peer_lid = plid;
825                         event = CNF_ACPT;
826                 }
827                 break;
828         case PLINK_CLOSE:
829                 if (sta->plink_state == PLINK_ESTAB)
830                         /* Do not check for llid or plid. This does not
831                          * follow the standard but since multiple plinks
832                          * per cand are not supported, it is necessary in
833                          * order to avoid a livelock when MP A sees an
834                          * establish peer link to MP B but MP B does not
835                          * see it. This can be caused by a timeout in
836                          * B's peer link establishment or B being
837                          * restarted.
838                          */
839                         event = CLS_ACPT;
840                 else if (sta->peer_lid != plid)
841                         event = CLS_IGNR;
842                 else if (peer_mgmt_ie.plid && sta->my_lid != llid)
843                         event = CLS_IGNR;
844                 else
845                         event = CLS_ACPT;
846                 break;
847         default:
848                 wpa_msg(wpa_s, MSG_ERROR,
849                         "Mesh plink: unknown frame subtype");
850                 return;
851         }
852         mesh_mpm_fsm(wpa_s, sta, event);
853 }