Home | History | Annotate | Download | only in fst
      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 
     22 static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
     23 						    Boolean 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 
     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 	Boolean 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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    210 Boolean 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 
    217 enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
    218 {
    219 	switch (mode) {
    220 	case HOSTAPD_MODE_IEEE80211B:
    221 	case HOSTAPD_MODE_IEEE80211G:
    222 		return MB_BAND_ID_WIFI_2_4GHZ;
    223 	case HOSTAPD_MODE_IEEE80211A:
    224 		return MB_BAND_ID_WIFI_5GHZ;
    225 	case HOSTAPD_MODE_IEEE80211AD:
    226 		return MB_BAND_ID_WIFI_60GHZ;
    227 	default:
    228 		WPA_ASSERT(0);
    229 		return MB_BAND_ID_WIFI_2_4GHZ;
    230 	}
    231 }
    232