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 18struct dl_list fst_global_ctrls_list; 19 20 21static 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 37struct 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 89void 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 104int 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 113void 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 128struct 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 151void 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 160void 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 172void 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 188void 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 204Boolean 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 211enum 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