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