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