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