1 /*
2  * FST module implementation
3  * Copyright (c) 2014, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "fst/fst.h"
14 #include "fst/fst_internal.h"
15 #include "fst/fst_defs.h"
16 #include "fst/fst_ctrl_iface.h"
17 
18 struct dl_list fst_global_ctrls_list;
19 
20 
fst_ctrl_iface_notify_peer_state_change(struct fst_iface * iface,Boolean connected,const u8 * peer_addr)21 static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
22 						    Boolean connected,
23 						    const u8 *peer_addr)
24 {
25 	union fst_event_extra extra;
26 
27 	extra.peer_state.connected = connected;
28 	os_strlcpy(extra.peer_state.ifname, fst_iface_get_name(iface),
29 		   sizeof(extra.peer_state.ifname));
30 	os_memcpy(extra.peer_state.addr, peer_addr, ETH_ALEN);
31 
32 	foreach_fst_ctrl_call(on_event, EVENT_PEER_STATE_CHANGED,
33 			      iface, NULL, &extra);
34 }
35 
36 
fst_attach(const char * ifname,const u8 * own_addr,const struct fst_wpa_obj * iface_obj,const struct fst_iface_cfg * cfg)37 struct fst_iface * fst_attach(const char *ifname, const u8 *own_addr,
38 			      const struct fst_wpa_obj *iface_obj,
39 			      const struct fst_iface_cfg *cfg)
40 {
41 	struct fst_group *g;
42 	struct fst_group *group = NULL;
43 	struct fst_iface *iface = NULL;
44 	Boolean new_group = FALSE;
45 
46 	WPA_ASSERT(ifname != NULL);
47 	WPA_ASSERT(iface_obj != NULL);
48 	WPA_ASSERT(cfg != NULL);
49 
50 	foreach_fst_group(g) {
51 		if (os_strcmp(cfg->group_id, fst_group_get_id(g)) == 0) {
52 			group = g;
53 			break;
54 		}
55 	}
56 
57 	if (!group) {
58 		group = fst_group_create(cfg->group_id);
59 		if (!group) {
60 			fst_printf(MSG_ERROR, "%s: FST group cannot be created",
61 				   cfg->group_id);
62 			return NULL;
63 		}
64 		new_group = TRUE;
65 	}
66 
67 	iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
68 	if (!iface) {
69 		fst_printf_group(group, MSG_ERROR, "cannot create iface for %s",
70 				 ifname);
71 		if (new_group)
72 			fst_group_delete(group);
73 		return NULL;
74 	}
75 
76 	fst_group_attach_iface(group, iface);
77 	fst_group_update_ie(group);
78 
79 	foreach_fst_ctrl_call(on_iface_added, iface);
80 
81 	fst_printf_iface(iface, MSG_DEBUG,
82 			 "iface attached to group %s (prio=%d, llt=%d)",
83 			 cfg->group_id, cfg->priority, cfg->llt);
84 
85 	return iface;
86 }
87 
88 
fst_detach(struct fst_iface * iface)89 void fst_detach(struct fst_iface *iface)
90 {
91 	struct fst_group *group = fst_iface_get_group(iface);
92 
93 	fst_printf_iface(iface, MSG_DEBUG, "iface detached from group %s",
94 			 fst_group_get_id(group));
95 	fst_session_global_on_iface_detached(iface);
96 	foreach_fst_ctrl_call(on_iface_removed, iface);
97 	fst_group_detach_iface(group, iface);
98 	fst_iface_delete(iface);
99 	fst_group_update_ie(group);
100 	fst_group_delete_if_empty(group);
101 }
102 
103 
fst_global_init(void)104 int fst_global_init(void)
105 {
106 	dl_list_init(&fst_global_groups_list);
107 	dl_list_init(&fst_global_ctrls_list);
108 	fst_session_global_init();
109 	return 0;
110 }
111 
112 
fst_global_deinit(void)113 void fst_global_deinit(void)
114 {
115 	struct fst_group *group;
116 	struct fst_ctrl_handle *h;
117 
118 	fst_session_global_deinit();
119 	while ((group = fst_first_group()) != NULL)
120 		fst_group_delete(group);
121 	while ((h = dl_list_first(&fst_global_ctrls_list,
122 				  struct fst_ctrl_handle,
123 				  global_ctrls_lentry)))
124 		fst_global_del_ctrl(h);
125 }
126 
127 
fst_global_add_ctrl(const struct fst_ctrl * ctrl)128 struct fst_ctrl_handle * fst_global_add_ctrl(const struct fst_ctrl *ctrl)
129 {
130 	struct fst_ctrl_handle *h;
131 
132 	if (!ctrl)
133 		return NULL;
134 
135 	h = os_zalloc(sizeof(*h));
136 	if (!h)
137 		return NULL;
138 
139 	if (ctrl->init && ctrl->init()) {
140 		os_free(h);
141 		return NULL;
142 	}
143 
144 	h->ctrl = *ctrl;
145 	dl_list_add_tail(&fst_global_ctrls_list, &h->global_ctrls_lentry);
146 
147 	return h;
148 }
149 
150 
fst_global_del_ctrl(struct fst_ctrl_handle * h)151 void fst_global_del_ctrl(struct fst_ctrl_handle *h)
152 {
153 	dl_list_del(&h->global_ctrls_lentry);
154 	if (h->ctrl.deinit)
155 		h->ctrl.deinit();
156 	os_free(h);
157 }
158 
159 
fst_rx_action(struct fst_iface * iface,const struct ieee80211_mgmt * mgmt,size_t len)160 void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
161 		   size_t len)
162 {
163 	if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
164 		fst_session_on_action_rx(iface, mgmt, len);
165 	else
166 		wpa_printf(MSG_DEBUG,
167 			   "FST: Ignore FST Action frame - no FST connection with "
168 			   MACSTR, MAC2STR(mgmt->sa));
169 }
170 
171 
fst_notify_peer_connected(struct fst_iface * iface,const u8 * addr)172 void fst_notify_peer_connected(struct fst_iface *iface, const u8 *addr)
173 {
174 	if (is_zero_ether_addr(addr))
175 		return;
176 
177 #ifndef HOSTAPD
178 	fst_group_update_ie(fst_iface_get_group(iface));
179 #endif /* HOSTAPD */
180 
181 	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
182 			 MAC2STR(addr));
183 
184 	fst_ctrl_iface_notify_peer_state_change(iface, TRUE, addr);
185 }
186 
187 
fst_notify_peer_disconnected(struct fst_iface * iface,const u8 * addr)188 void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr)
189 {
190 	if (is_zero_ether_addr(addr))
191 		return;
192 
193 #ifndef HOSTAPD
194 	fst_group_update_ie(fst_iface_get_group(iface));
195 #endif /* HOSTAPD */
196 
197 	fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
198 			 MAC2STR(addr));
199 
200 	fst_ctrl_iface_notify_peer_state_change(iface, FALSE, addr);
201 }
202 
203 
fst_are_ifaces_aggregated(struct fst_iface * iface1,struct fst_iface * iface2)204 Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
205 				  struct fst_iface *iface2)
206 {
207 	return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
208 }
209 
210 
fst_hw_mode_to_band(enum hostapd_hw_mode mode)211 enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
212 {
213 	switch (mode) {
214 	case HOSTAPD_MODE_IEEE80211B:
215 	case HOSTAPD_MODE_IEEE80211G:
216 		return MB_BAND_ID_WIFI_2_4GHZ;
217 	case HOSTAPD_MODE_IEEE80211A:
218 		return MB_BAND_ID_WIFI_5GHZ;
219 	case HOSTAPD_MODE_IEEE80211AD:
220 		return MB_BAND_ID_WIFI_60GHZ;
221 	default:
222 		WPA_ASSERT(0);
223 		return MB_BAND_ID_WIFI_2_4GHZ;
224 	}
225 }
226