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