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