xref: /freebsd/contrib/wpa/src/fst/fst.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
1325151a3SRui Paulo /*
2325151a3SRui Paulo  * FST module implementation
3325151a3SRui Paulo  * Copyright (c) 2014, Qualcomm Atheros, Inc.
4325151a3SRui Paulo  *
5325151a3SRui Paulo  * This software may be distributed under the terms of the BSD license.
6325151a3SRui Paulo  * See README for more details.
7325151a3SRui Paulo  */
8325151a3SRui Paulo 
9325151a3SRui Paulo #include "utils/includes.h"
10325151a3SRui Paulo 
11325151a3SRui Paulo #include "utils/common.h"
12325151a3SRui Paulo #include "utils/eloop.h"
13325151a3SRui Paulo #include "fst/fst.h"
14325151a3SRui Paulo #include "fst/fst_internal.h"
15325151a3SRui Paulo #include "fst/fst_defs.h"
16325151a3SRui Paulo #include "fst/fst_ctrl_iface.h"
17325151a3SRui Paulo 
18780fb4a2SCy Schubert static int fst_global_initialized = 0;
19325151a3SRui Paulo struct dl_list fst_global_ctrls_list;
20325151a3SRui Paulo 
21325151a3SRui Paulo 
fst_ctrl_iface_notify_peer_state_change(struct fst_iface * iface,bool connected,const u8 * peer_addr)22325151a3SRui Paulo static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
23*c1d255d3SCy Schubert 						    bool connected,
24325151a3SRui Paulo 						    const u8 *peer_addr)
25325151a3SRui Paulo {
26325151a3SRui Paulo 	union fst_event_extra extra;
27325151a3SRui Paulo 
28325151a3SRui Paulo 	extra.peer_state.connected = connected;
29325151a3SRui Paulo 	os_strlcpy(extra.peer_state.ifname, fst_iface_get_name(iface),
30325151a3SRui Paulo 		   sizeof(extra.peer_state.ifname));
31325151a3SRui Paulo 	os_memcpy(extra.peer_state.addr, peer_addr, ETH_ALEN);
32325151a3SRui Paulo 
33325151a3SRui Paulo 	foreach_fst_ctrl_call(on_event, EVENT_PEER_STATE_CHANGED,
34325151a3SRui Paulo 			      iface, NULL, &extra);
35325151a3SRui Paulo }
36325151a3SRui Paulo 
37325151a3SRui Paulo 
fst_attach(const char * ifname,const u8 * own_addr,const struct fst_wpa_obj * iface_obj,const struct fst_iface_cfg * cfg)38325151a3SRui Paulo struct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
39325151a3SRui Paulo 			      const struct fst_wpa_obj *iface_obj,
40325151a3SRui Paulo 			      const struct fst_iface_cfg *cfg)
41325151a3SRui Paulo {
42325151a3SRui Paulo 	struct fst_group *g;
43325151a3SRui Paulo 	struct fst_group *group = NULL;
44325151a3SRui Paulo 	struct fst_iface *iface = NULL;
45*c1d255d3SCy Schubert 	bool new_group = false;
46325151a3SRui Paulo 
47325151a3SRui Paulo 	WPA_ASSERT(ifname != NULL);
48325151a3SRui Paulo 	WPA_ASSERT(iface_obj != NULL);
49325151a3SRui Paulo 	WPA_ASSERT(cfg != NULL);
50325151a3SRui Paulo 
51325151a3SRui Paulo 	foreach_fst_group(g) {
52325151a3SRui Paulo 		if (os_strcmp(cfg->group_id, fst_group_get_id(g)) == 0) {
53325151a3SRui Paulo 			group = g;
54325151a3SRui Paulo 			break;
55325151a3SRui Paulo 		}
56325151a3SRui Paulo 	}
57325151a3SRui Paulo 
58325151a3SRui Paulo 	if (!group) {
59325151a3SRui Paulo 		group = fst_group_create(cfg->group_id);
60325151a3SRui Paulo 		if (!group) {
61325151a3SRui Paulo 			fst_printf(MSG_ERROR, "%s: FST group cannot be created",
62325151a3SRui Paulo 				   cfg->group_id);
63325151a3SRui Paulo 			return NULL;
64325151a3SRui Paulo 		}
65*c1d255d3SCy Schubert 		new_group = true;
66325151a3SRui Paulo 	}
67325151a3SRui Paulo 
68325151a3SRui Paulo 	iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
69325151a3SRui Paulo 	if (!iface) {
70325151a3SRui Paulo 		fst_printf_group(group, MSG_ERROR, "cannot create iface for %s",
71325151a3SRui Paulo 				 ifname);
72325151a3SRui Paulo 		if (new_group)
73325151a3SRui Paulo 			fst_group_delete(group);
74325151a3SRui Paulo 		return NULL;
75325151a3SRui Paulo 	}
76325151a3SRui Paulo 
77325151a3SRui Paulo 	fst_group_attach_iface(group, iface);
78325151a3SRui Paulo 	fst_group_update_ie(group);
79325151a3SRui Paulo 
80325151a3SRui Paulo 	foreach_fst_ctrl_call(on_iface_added, iface);
81325151a3SRui Paulo 
82325151a3SRui Paulo 	fst_printf_iface(iface, MSG_DEBUG,
83325151a3SRui Paulo 			 "iface attached to group %s (prio=%d, llt=%d)",
84325151a3SRui Paulo 			 cfg->group_id, cfg->priority, cfg->llt);
85325151a3SRui Paulo 
86325151a3SRui Paulo 	return iface;
87325151a3SRui Paulo }
88325151a3SRui Paulo 
89325151a3SRui Paulo 
fst_detach(struct fst_iface * iface)90325151a3SRui Paulo void fst_detach(struct fst_iface *iface)
91325151a3SRui Paulo {
92325151a3SRui Paulo 	struct fst_group *group = fst_iface_get_group(iface);
93325151a3SRui Paulo 
94325151a3SRui Paulo 	fst_printf_iface(iface, MSG_DEBUG, "iface detached from group %s",
95325151a3SRui Paulo 			 fst_group_get_id(group));
96325151a3SRui Paulo 	fst_session_global_on_iface_detached(iface);
97325151a3SRui Paulo 	foreach_fst_ctrl_call(on_iface_removed, iface);
98325151a3SRui Paulo 	fst_group_detach_iface(group, iface);
99325151a3SRui Paulo 	fst_iface_delete(iface);
100325151a3SRui Paulo 	fst_group_update_ie(group);
101325151a3SRui Paulo 	fst_group_delete_if_empty(group);
102325151a3SRui Paulo }
103325151a3SRui Paulo 
104325151a3SRui Paulo 
fst_global_init(void)105325151a3SRui Paulo int fst_global_init(void)
106325151a3SRui Paulo {
107325151a3SRui Paulo 	dl_list_init(&fst_global_groups_list);
108325151a3SRui Paulo 	dl_list_init(&fst_global_ctrls_list);
109325151a3SRui Paulo 	fst_session_global_init();
110780fb4a2SCy Schubert 	fst_global_initialized = 1;
111325151a3SRui Paulo 	return 0;
112325151a3SRui Paulo }
113325151a3SRui Paulo 
114325151a3SRui Paulo 
fst_global_deinit(void)115325151a3SRui Paulo void fst_global_deinit(void)
116325151a3SRui Paulo {
117325151a3SRui Paulo 	struct fst_group *group;
118325151a3SRui Paulo 	struct fst_ctrl_handle *h;
119325151a3SRui Paulo 
120780fb4a2SCy Schubert 	if (!fst_global_initialized)
121780fb4a2SCy Schubert 		return;
122780fb4a2SCy Schubert 
123325151a3SRui Paulo 	fst_session_global_deinit();
124325151a3SRui Paulo 	while ((group = fst_first_group()) != NULL)
125325151a3SRui Paulo 		fst_group_delete(group);
126325151a3SRui Paulo 	while ((h = dl_list_first(&fst_global_ctrls_list,
127325151a3SRui Paulo 				  struct fst_ctrl_handle,
128325151a3SRui Paulo 				  global_ctrls_lentry)))
129325151a3SRui Paulo 		fst_global_del_ctrl(h);
130780fb4a2SCy Schubert 	fst_global_initialized = 0;
131325151a3SRui Paulo }
132325151a3SRui Paulo 
133325151a3SRui Paulo 
fst_global_add_ctrl(const struct fst_ctrl * ctrl)134325151a3SRui Paulo struct fst_ctrl_handle * fst_global_add_ctrl(const struct fst_ctrl *ctrl)
135325151a3SRui Paulo {
136325151a3SRui Paulo 	struct fst_ctrl_handle *h;
137325151a3SRui Paulo 
138325151a3SRui Paulo 	if (!ctrl)
139325151a3SRui Paulo 		return NULL;
140325151a3SRui Paulo 
141325151a3SRui Paulo 	h = os_zalloc(sizeof(*h));
142325151a3SRui Paulo 	if (!h)
143325151a3SRui Paulo 		return NULL;
144325151a3SRui Paulo 
145325151a3SRui Paulo 	if (ctrl->init && ctrl->init()) {
146325151a3SRui Paulo 		os_free(h);
147325151a3SRui Paulo 		return NULL;
148325151a3SRui Paulo 	}
149325151a3SRui Paulo 
150325151a3SRui Paulo 	h->ctrl = *ctrl;
151325151a3SRui Paulo 	dl_list_add_tail(&fst_global_ctrls_list, &h->global_ctrls_lentry);
152325151a3SRui Paulo 
153325151a3SRui Paulo 	return h;
154325151a3SRui Paulo }
155325151a3SRui Paulo 
156325151a3SRui Paulo 
fst_global_del_ctrl(struct fst_ctrl_handle * h)157325151a3SRui Paulo void fst_global_del_ctrl(struct fst_ctrl_handle *h)
158325151a3SRui Paulo {
159325151a3SRui Paulo 	dl_list_del(&h->global_ctrls_lentry);
160325151a3SRui Paulo 	if (h->ctrl.deinit)
161325151a3SRui Paulo 		h->ctrl.deinit();
162325151a3SRui Paulo 	os_free(h);
163325151a3SRui Paulo }
164325151a3SRui Paulo 
165325151a3SRui Paulo 
fst_rx_action(struct fst_iface * iface,const struct ieee80211_mgmt * mgmt,size_t len)166325151a3SRui Paulo void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
167325151a3SRui Paulo 		   size_t len)
168325151a3SRui Paulo {
169*c1d255d3SCy Schubert 	if (fst_iface_is_connected(iface, mgmt->sa, false))
170325151a3SRui Paulo 		fst_session_on_action_rx(iface, mgmt, len);
171325151a3SRui Paulo 	else
172325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
173325151a3SRui Paulo 			   "FST: Ignore FST Action frame - no FST connection with "
174325151a3SRui Paulo 			   MACSTR, MAC2STR(mgmt->sa));
175325151a3SRui Paulo }
176325151a3SRui Paulo 
177325151a3SRui Paulo 
fst_notify_peer_connected(struct fst_iface * iface,const u8 * addr)178325151a3SRui Paulo void fst_notify_peer_connected(struct fst_iface *iface, const u8 *addr)
179325151a3SRui Paulo {
180325151a3SRui Paulo 	if (is_zero_ether_addr(addr))
181325151a3SRui Paulo 		return;
182325151a3SRui Paulo 
183325151a3SRui Paulo #ifndef HOSTAPD
184325151a3SRui Paulo 	fst_group_update_ie(fst_iface_get_group(iface));
185325151a3SRui Paulo #endif /* HOSTAPD */
186325151a3SRui Paulo 
187325151a3SRui Paulo 	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
188325151a3SRui Paulo 			 MAC2STR(addr));
189325151a3SRui Paulo 
190*c1d255d3SCy Schubert 	fst_ctrl_iface_notify_peer_state_change(iface, true, addr);
191325151a3SRui Paulo }
192325151a3SRui Paulo 
193325151a3SRui Paulo 
fst_notify_peer_disconnected(struct fst_iface * iface,const u8 * addr)194325151a3SRui Paulo void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr)
195325151a3SRui Paulo {
196325151a3SRui Paulo 	if (is_zero_ether_addr(addr))
197325151a3SRui Paulo 		return;
198325151a3SRui Paulo 
199325151a3SRui Paulo #ifndef HOSTAPD
200325151a3SRui Paulo 	fst_group_update_ie(fst_iface_get_group(iface));
201325151a3SRui Paulo #endif /* HOSTAPD */
202325151a3SRui Paulo 
203325151a3SRui Paulo 	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
204325151a3SRui Paulo 			 MAC2STR(addr));
205325151a3SRui Paulo 
206*c1d255d3SCy Schubert 	fst_ctrl_iface_notify_peer_state_change(iface, false, addr);
207325151a3SRui Paulo }
208325151a3SRui Paulo 
209325151a3SRui Paulo 
fst_are_ifaces_aggregated(struct fst_iface * iface1,struct fst_iface * iface2)210*c1d255d3SCy Schubert bool fst_are_ifaces_aggregated(struct fst_iface *iface1,
211325151a3SRui Paulo 			       struct fst_iface *iface2)
212325151a3SRui Paulo {
213325151a3SRui Paulo 	return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
214325151a3SRui Paulo }
215325151a3SRui Paulo 
216325151a3SRui Paulo 
fst_update_mac_addr(struct fst_iface * iface,const u8 * addr)217*c1d255d3SCy Schubert void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr)
218*c1d255d3SCy Schubert {
219*c1d255d3SCy Schubert 	fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR,
220*c1d255d3SCy Schubert 			 MAC2STR(addr));
221*c1d255d3SCy Schubert 	os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr));
222*c1d255d3SCy Schubert 	fst_group_update_ie(fst_iface_get_group(iface));
223*c1d255d3SCy Schubert }
224*c1d255d3SCy Schubert 
225*c1d255d3SCy Schubert 
fst_hw_mode_to_band(enum hostapd_hw_mode mode)226325151a3SRui Paulo enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
227325151a3SRui Paulo {
228325151a3SRui Paulo 	switch (mode) {
229325151a3SRui Paulo 	case HOSTAPD_MODE_IEEE80211B:
230325151a3SRui Paulo 	case HOSTAPD_MODE_IEEE80211G:
231325151a3SRui Paulo 		return MB_BAND_ID_WIFI_2_4GHZ;
232325151a3SRui Paulo 	case HOSTAPD_MODE_IEEE80211A:
233325151a3SRui Paulo 		return MB_BAND_ID_WIFI_5GHZ;
234325151a3SRui Paulo 	case HOSTAPD_MODE_IEEE80211AD:
235325151a3SRui Paulo 		return MB_BAND_ID_WIFI_60GHZ;
236325151a3SRui Paulo 	default:
237325151a3SRui Paulo 		WPA_ASSERT(0);
238325151a3SRui Paulo 		return MB_BAND_ID_WIFI_2_4GHZ;
239325151a3SRui Paulo 	}
240325151a3SRui Paulo }
241