2 * WPA Supplicant - Basic mesh peer management
3 * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
21 /* TODO make configurable */
22 #define dot11MeshMaxRetries 10
23 #define dot11MeshRetryTimeout 1
24 #define dot11MeshConfirmTimeout 1
25 #define dot11MeshHoldingTimeout 1
27 struct mesh_peer_mgmt_ie {
35 static void plink_timer(void *eloop_ctx, void *user_data);
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"
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"
73 static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
75 const u8 *ie, size_t len,
76 struct mesh_peer_mgmt_ie *mpm_ie)
78 os_memset(mpm_ie, 0, sizeof(*mpm_ie));
80 /* remove optional PMK at end */
83 mpm_ie->pmk = ie + len - 16;
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");
96 mpm_ie->proto_id = ie;
97 mpm_ie->llid = ie + 2;
101 /* close reason is always present at end for close */
102 if (action_field == PLINK_CLOSE) {
105 mpm_ie->reason = ie + len - 2;
109 /* plid, present for confirm, and possibly close */
117 static int plink_free_count(struct hostapd_data *hapd)
119 if (hapd->max_plinks > hapd->num_plinks)
120 return hapd->max_plinks - hapd->num_plinks;
125 static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
126 struct sta_info *sta,
127 struct ieee802_11_elems *elems)
129 if (!elems->supp_rates) {
130 wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
132 return WLAN_STATUS_UNSPECIFIED_FAILURE;
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;
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);
149 return WLAN_STATUS_SUCCESS;
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)
157 struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
159 if (elems->mesh_config_len < 5)
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]);
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)
176 struct sta_info *sta;
177 struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
179 for (sta = hapd->sta_list; sta; sta = sta->next) {
180 if (sta->my_lid == llid)
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)
195 if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
197 } while (!llid || llid_in_use(wpa_s, llid));
201 sta->plink_state = PLINK_LISTEN;
205 static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
206 struct sta_info *sta,
207 enum plink_action_field type,
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];
216 u8 ie_len, add_plid = 0;
218 int ampe = conf->security & MESH_CONF_SEC_AMPE;
223 buf = wpabuf_alloc(2 + /* capability info */
225 2 + 8 + /* supported rates */
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 */
237 wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
238 wpabuf_put_u8(buf, type);
240 if (type != PLINK_CLOSE) {
241 /* capability info */
242 wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
244 if (type == PLINK_CONFIRM)
245 wpabuf_put_le16(buf, sta->peer_lid);
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);
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);
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 */
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);
276 /* IE: Mesh Peering Management element */
290 ie_len += 2; /* reason code */
294 wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
295 wpabuf_put_u8(buf, ie_len);
296 /* peering protocol */
298 wpabuf_put_le16(buf, 1);
300 wpabuf_put_le16(buf, 0);
301 wpabuf_put_le16(buf, sta->my_lid);
303 wpabuf_put_le16(buf, sta->peer_lid);
304 if (type == PLINK_CLOSE)
305 wpabuf_put_le16(buf, close_reason);
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);
313 wpa_msg(wpa_s, MSG_INFO,
314 "Mesh MPM: failed to send peering frame");
320 /* configure peering state in ours and driver's station entry */
322 wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
323 enum mesh_plink_state state)
325 struct hostapd_sta_add_params params;
328 sta->plink_state = state;
330 os_memset(¶ms, 0, sizeof(params));
331 params.addr = sta->addr;
332 params.plink_state = state;
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, ¶ms);
339 wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
340 ": %d", MAC2STR(sta->addr), ret);
345 static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
346 struct sta_info *sta)
348 struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
350 eloop_cancel_timeout(plink_timer, wpa_s, sta);
352 if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
353 ap_free_sta(hapd, sta);
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;
363 static void plink_timer(void *eloop_ctx, void *user_data)
365 struct wpa_supplicant *wpa_s = eloop_ctx;
366 struct sta_info *sta = user_data;
369 switch (sta->plink_state) {
370 case PLINK_OPEN_RCVD:
371 case PLINK_OPEN_SENT:
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);
380 reason = WLAN_REASON_MESH_MAX_RETRIES;
381 /* fall through on else */
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);
394 mesh_mpm_fsm_restart(wpa_s, sta);
402 /* initiate peering with station */
404 mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
405 enum mesh_plink_state next_state)
407 eloop_cancel_timeout(plink_timer, wpa_s, sta);
408 eloop_register_timeout(dot11MeshRetryTimeout, 0, plink_timer,
410 mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
411 wpa_mesh_set_plink_state(wpa_s, sta, next_state);
415 int mesh_mpm_plink_close(struct hostapd_data *hapd,
416 struct sta_info *sta, void *ctx)
418 struct wpa_supplicant *wpa_s = ctx;
419 int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
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,
426 eloop_cancel_timeout(plink_timer, wpa_s, sta);
434 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
436 struct hostapd_data *hapd = ifmsh->bss[0];
438 /* notify peers we're leaving */
439 ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s);
441 hapd->num_plinks = 0;
442 hostapd_free_stas(hapd);
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)
450 struct hostapd_data *data = wpa_s->ifmsh->bss[0];
451 struct hostapd_sta_add_params params;
452 struct sta_info *sta;
455 sta = ap_get_sta(data, addr);
457 wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer");
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;
465 os_memset(¶ms, 0, sizeof(params));
466 params.addr = sta->addr;
467 params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
470 wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
472 ret = wpa_drv_sta_add(wpa_s, ¶ms);
474 wpa_msg(wpa_s, MSG_ERROR,
475 "Driver failed to set " MACSTR ": %d",
476 MAC2STR(sta->addr), ret);
480 mesh_mpm_init_link(wpa_s, sta);
482 mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
486 void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
487 struct ieee802_11_elems *elems)
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;
495 sta = ap_get_sta(data, addr);
497 sta = ap_sta_add(data, addr);
503 if (copy_supp_rates(wpa_s, sta, elems))
506 mesh_mpm_init_link(wpa_s, sta);
508 /* insert into driver */
509 os_memset(¶ms, 0, sizeof(params));
510 params.supp_rates = sta->supported_rates;
511 params.supp_rates_len = sta->supported_rates_len;
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;
523 sta->flags |= WLAN_STA_MFP;
524 params.flags |= WPA_STA_MFP;
527 ret = wpa_drv_sta_add(wpa_s, ¶ms);
529 wpa_msg(wpa_s, MSG_ERROR,
530 "Driver failed to insert " MACSTR ": %d",
535 mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
539 void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
541 struct hostapd_frame_info fi;
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);
551 static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
552 struct sta_info *sta)
554 struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
556 wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
559 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
562 sta->flags |= WLAN_STA_ASSOC;
564 eloop_cancel_timeout(plink_timer, wpa_s, sta);
566 /* Send ctrl event */
567 wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
572 static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
573 enum plink_event event)
575 struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
578 wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
579 MAC2STR(sta->addr), mplstate[sta->plink_state],
582 switch (sta->plink_state) {
586 mesh_mpm_fsm_restart(wpa_s, sta);
589 mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
590 mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
597 case PLINK_OPEN_SENT:
601 reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
604 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
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);
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,
619 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
620 eloop_register_timeout(dot11MeshConfirmTimeout, 0,
621 plink_timer, wpa_s, sta);
627 case PLINK_OPEN_RCVD:
631 reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
634 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
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);
644 mesh_mpm_send_plink_action(wpa_s, sta,
648 mesh_mpm_plink_estab(wpa_s, sta);
658 reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
661 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
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);
671 mesh_mpm_plink_estab(wpa_s, sta);
672 mesh_mpm_send_plink_action(wpa_s, sta,
682 wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
683 reason = WLAN_REASON_MESH_CLOSE_RCVD;
685 eloop_register_timeout(dot11MeshHoldingTimeout, 0,
686 plink_timer, wpa_s, sta);
687 sta->mpm_close_reason = reason;
689 wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
690 " closed with reason %d",
691 MAC2STR(sta->addr), reason);
693 wpa_msg_ctrl(wpa_s, MSG_INFO,
694 MESH_PEER_DISCONNECTED MACSTR,
699 mesh_mpm_send_plink_action(wpa_s, sta,
700 PLINK_CLOSE, reason);
703 mesh_mpm_send_plink_action(wpa_s, sta,
713 mesh_mpm_fsm_restart(wpa_s, sta);
719 reason = sta->mpm_close_reason;
720 mesh_mpm_send_plink_action(wpa_s, sta,
721 PLINK_CLOSE, reason);
728 wpa_msg(wpa_s, MSG_DEBUG,
729 "Unsupported MPM event %s for state %s",
730 mplevent[event], mplstate[sta->plink_state]);
736 void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
737 const struct ieee80211_mgmt *mgmt, size_t len)
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;
750 if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
753 action_field = mgmt->u.action.u.slf_prot_action.action;
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;
759 /* at least expect mesh id and peering mgmt */
763 if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
764 ies += 2; /* capability */
767 if (action_field == PLINK_CONFIRM) {
772 /* check for mesh peering, mesh id and mesh config IEs */
773 if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed)
775 if (!elems.peer_mgmt)
777 if ((action_field != PLINK_CLOSE) &&
778 (!elems.mesh_id || !elems.mesh_config))
781 if (action_field != PLINK_CLOSE && !matches_local(wpa_s, &elems))
784 ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
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);
796 sta = ap_get_sta(hapd, mgmt->sa);
801 mesh_mpm_init_link(wpa_s, sta);
803 if (sta->plink_state == PLINK_BLOCKED)
806 /* Now we will figure out the appropriate event... */
807 switch (action_field) {
809 if (!plink_free_count(hapd) ||
810 (sta->peer_lid && sta->peer_lid != plid)) {
813 sta->peer_lid = plid;
818 if (!plink_free_count(hapd) ||
819 sta->my_lid != llid ||
820 (sta->peer_lid && sta->peer_lid != plid)) {
824 sta->peer_lid = plid;
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
840 else if (sta->peer_lid != plid)
842 else if (peer_mgmt_ie.plid && sta->my_lid != llid)
848 wpa_msg(wpa_s, MSG_ERROR,
849 "Mesh plink: unknown frame subtype");
852 mesh_mpm_fsm(wpa_s, sta, event);