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 struct dl_list fst_global_ctrls_list;
     19 
     20 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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