1289284Srpaulo/*
2289284Srpaulo * FST module implementation
3289284Srpaulo * Copyright (c) 2014, Qualcomm Atheros, Inc.
4289284Srpaulo *
5289284Srpaulo * This software may be distributed under the terms of the BSD license.
6289284Srpaulo * See README for more details.
7289284Srpaulo */
8289284Srpaulo
9289284Srpaulo#include "utils/includes.h"
10289284Srpaulo
11289284Srpaulo#include "utils/common.h"
12289284Srpaulo#include "utils/eloop.h"
13289284Srpaulo#include "fst/fst.h"
14289284Srpaulo#include "fst/fst_internal.h"
15289284Srpaulo#include "fst/fst_defs.h"
16289284Srpaulo#include "fst/fst_ctrl_iface.h"
17289284Srpaulo
18337817Scystatic int fst_global_initialized = 0;
19289284Srpaulostruct dl_list fst_global_ctrls_list;
20289284Srpaulo
21289284Srpaulo
22289284Srpaulostatic void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
23289284Srpaulo						    Boolean connected,
24289284Srpaulo						    const u8 *peer_addr)
25289284Srpaulo{
26289284Srpaulo	union fst_event_extra extra;
27289284Srpaulo
28289284Srpaulo	extra.peer_state.connected = connected;
29289284Srpaulo	os_strlcpy(extra.peer_state.ifname, fst_iface_get_name(iface),
30289284Srpaulo		   sizeof(extra.peer_state.ifname));
31289284Srpaulo	os_memcpy(extra.peer_state.addr, peer_addr, ETH_ALEN);
32289284Srpaulo
33289284Srpaulo	foreach_fst_ctrl_call(on_event, EVENT_PEER_STATE_CHANGED,
34289284Srpaulo			      iface, NULL, &extra);
35289284Srpaulo}
36289284Srpaulo
37289284Srpaulo
38289284Srpaulostruct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
39289284Srpaulo			      const struct fst_wpa_obj *iface_obj,
40289284Srpaulo			      const struct fst_iface_cfg *cfg)
41289284Srpaulo{
42289284Srpaulo	struct fst_group *g;
43289284Srpaulo	struct fst_group *group = NULL;
44289284Srpaulo	struct fst_iface *iface = NULL;
45289284Srpaulo	Boolean new_group = FALSE;
46289284Srpaulo
47289284Srpaulo	WPA_ASSERT(ifname != NULL);
48289284Srpaulo	WPA_ASSERT(iface_obj != NULL);
49289284Srpaulo	WPA_ASSERT(cfg != NULL);
50289284Srpaulo
51289284Srpaulo	foreach_fst_group(g) {
52289284Srpaulo		if (os_strcmp(cfg->group_id, fst_group_get_id(g)) == 0) {
53289284Srpaulo			group = g;
54289284Srpaulo			break;
55289284Srpaulo		}
56289284Srpaulo	}
57289284Srpaulo
58289284Srpaulo	if (!group) {
59289284Srpaulo		group = fst_group_create(cfg->group_id);
60289284Srpaulo		if (!group) {
61289284Srpaulo			fst_printf(MSG_ERROR, "%s: FST group cannot be created",
62289284Srpaulo				   cfg->group_id);
63289284Srpaulo			return NULL;
64289284Srpaulo		}
65289284Srpaulo		new_group = TRUE;
66289284Srpaulo	}
67289284Srpaulo
68289284Srpaulo	iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
69289284Srpaulo	if (!iface) {
70289284Srpaulo		fst_printf_group(group, MSG_ERROR, "cannot create iface for %s",
71289284Srpaulo				 ifname);
72289284Srpaulo		if (new_group)
73289284Srpaulo			fst_group_delete(group);
74289284Srpaulo		return NULL;
75289284Srpaulo	}
76289284Srpaulo
77289284Srpaulo	fst_group_attach_iface(group, iface);
78289284Srpaulo	fst_group_update_ie(group);
79289284Srpaulo
80289284Srpaulo	foreach_fst_ctrl_call(on_iface_added, iface);
81289284Srpaulo
82289284Srpaulo	fst_printf_iface(iface, MSG_DEBUG,
83289284Srpaulo			 "iface attached to group %s (prio=%d, llt=%d)",
84289284Srpaulo			 cfg->group_id, cfg->priority, cfg->llt);
85289284Srpaulo
86289284Srpaulo	return iface;
87289284Srpaulo}
88289284Srpaulo
89289284Srpaulo
90289284Srpaulovoid fst_detach(struct fst_iface *iface)
91289284Srpaulo{
92289284Srpaulo	struct fst_group *group = fst_iface_get_group(iface);
93289284Srpaulo
94289284Srpaulo	fst_printf_iface(iface, MSG_DEBUG, "iface detached from group %s",
95289284Srpaulo			 fst_group_get_id(group));
96289284Srpaulo	fst_session_global_on_iface_detached(iface);
97289284Srpaulo	foreach_fst_ctrl_call(on_iface_removed, iface);
98289284Srpaulo	fst_group_detach_iface(group, iface);
99289284Srpaulo	fst_iface_delete(iface);
100289284Srpaulo	fst_group_update_ie(group);
101289284Srpaulo	fst_group_delete_if_empty(group);
102289284Srpaulo}
103289284Srpaulo
104289284Srpaulo
105289284Srpauloint fst_global_init(void)
106289284Srpaulo{
107289284Srpaulo	dl_list_init(&fst_global_groups_list);
108289284Srpaulo	dl_list_init(&fst_global_ctrls_list);
109289284Srpaulo	fst_session_global_init();
110337817Scy	fst_global_initialized = 1;
111289284Srpaulo	return 0;
112289284Srpaulo}
113289284Srpaulo
114289284Srpaulo
115289284Srpaulovoid fst_global_deinit(void)
116289284Srpaulo{
117289284Srpaulo	struct fst_group *group;
118289284Srpaulo	struct fst_ctrl_handle *h;
119289284Srpaulo
120337817Scy	if (!fst_global_initialized)
121337817Scy		return;
122337817Scy
123289284Srpaulo	fst_session_global_deinit();
124289284Srpaulo	while ((group = fst_first_group()) != NULL)
125289284Srpaulo		fst_group_delete(group);
126289284Srpaulo	while ((h = dl_list_first(&fst_global_ctrls_list,
127289284Srpaulo				  struct fst_ctrl_handle,
128289284Srpaulo				  global_ctrls_lentry)))
129289284Srpaulo		fst_global_del_ctrl(h);
130337817Scy	fst_global_initialized = 0;
131289284Srpaulo}
132289284Srpaulo
133289284Srpaulo
134289284Srpaulostruct fst_ctrl_handle * fst_global_add_ctrl(const struct fst_ctrl *ctrl)
135289284Srpaulo{
136289284Srpaulo	struct fst_ctrl_handle *h;
137289284Srpaulo
138289284Srpaulo	if (!ctrl)
139289284Srpaulo		return NULL;
140289284Srpaulo
141289284Srpaulo	h = os_zalloc(sizeof(*h));
142289284Srpaulo	if (!h)
143289284Srpaulo		return NULL;
144289284Srpaulo
145289284Srpaulo	if (ctrl->init && ctrl->init()) {
146289284Srpaulo		os_free(h);
147289284Srpaulo		return NULL;
148289284Srpaulo	}
149289284Srpaulo
150289284Srpaulo	h->ctrl = *ctrl;
151289284Srpaulo	dl_list_add_tail(&fst_global_ctrls_list, &h->global_ctrls_lentry);
152289284Srpaulo
153289284Srpaulo	return h;
154289284Srpaulo}
155289284Srpaulo
156289284Srpaulo
157289284Srpaulovoid fst_global_del_ctrl(struct fst_ctrl_handle *h)
158289284Srpaulo{
159289284Srpaulo	dl_list_del(&h->global_ctrls_lentry);
160289284Srpaulo	if (h->ctrl.deinit)
161289284Srpaulo		h->ctrl.deinit();
162289284Srpaulo	os_free(h);
163289284Srpaulo}
164289284Srpaulo
165289284Srpaulo
166289284Srpaulovoid fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
167289284Srpaulo		   size_t len)
168289284Srpaulo{
169337817Scy	if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
170289284Srpaulo		fst_session_on_action_rx(iface, mgmt, len);
171289284Srpaulo	else
172289284Srpaulo		wpa_printf(MSG_DEBUG,
173289284Srpaulo			   "FST: Ignore FST Action frame - no FST connection with "
174289284Srpaulo			   MACSTR, MAC2STR(mgmt->sa));
175289284Srpaulo}
176289284Srpaulo
177289284Srpaulo
178289284Srpaulovoid fst_notify_peer_connected(struct fst_iface *iface, const u8 *addr)
179289284Srpaulo{
180289284Srpaulo	if (is_zero_ether_addr(addr))
181289284Srpaulo		return;
182289284Srpaulo
183289284Srpaulo#ifndef HOSTAPD
184289284Srpaulo	fst_group_update_ie(fst_iface_get_group(iface));
185289284Srpaulo#endif /* HOSTAPD */
186289284Srpaulo
187289284Srpaulo	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
188289284Srpaulo			 MAC2STR(addr));
189289284Srpaulo
190289284Srpaulo	fst_ctrl_iface_notify_peer_state_change(iface, TRUE, addr);
191289284Srpaulo}
192289284Srpaulo
193289284Srpaulo
194289284Srpaulovoid fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr)
195289284Srpaulo{
196289284Srpaulo	if (is_zero_ether_addr(addr))
197289284Srpaulo		return;
198289284Srpaulo
199289284Srpaulo#ifndef HOSTAPD
200289284Srpaulo	fst_group_update_ie(fst_iface_get_group(iface));
201289284Srpaulo#endif /* HOSTAPD */
202289284Srpaulo
203289284Srpaulo	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
204289284Srpaulo			 MAC2STR(addr));
205289284Srpaulo
206289284Srpaulo	fst_ctrl_iface_notify_peer_state_change(iface, FALSE, addr);
207289284Srpaulo}
208289284Srpaulo
209289284Srpaulo
210289284SrpauloBoolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
211289284Srpaulo				  struct fst_iface *iface2)
212289284Srpaulo{
213289284Srpaulo	return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
214289284Srpaulo}
215289284Srpaulo
216289284Srpaulo
217289284Srpauloenum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
218289284Srpaulo{
219289284Srpaulo	switch (mode) {
220289284Srpaulo	case HOSTAPD_MODE_IEEE80211B:
221289284Srpaulo	case HOSTAPD_MODE_IEEE80211G:
222289284Srpaulo		return MB_BAND_ID_WIFI_2_4GHZ;
223289284Srpaulo	case HOSTAPD_MODE_IEEE80211A:
224289284Srpaulo		return MB_BAND_ID_WIFI_5GHZ;
225289284Srpaulo	case HOSTAPD_MODE_IEEE80211AD:
226289284Srpaulo		return MB_BAND_ID_WIFI_60GHZ;
227289284Srpaulo	default:
228289284Srpaulo		WPA_ASSERT(0);
229289284Srpaulo		return MB_BAND_ID_WIFI_2_4GHZ;
230289284Srpaulo	}
231289284Srpaulo}
232