Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | { |
Dmitry Shmidt | d7ff03d | 2015-12-04 14:49:35 -0800 | [diff] [blame] | 163 | if (fst_iface_is_connected(iface, mgmt->sa, FALSE)) |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | } |