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 | |
Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 18 | static int fst_global_initialized = 0; |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 19 | struct dl_list fst_global_ctrls_list; |
| 20 | |
| 21 | |
| 22 | static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface, |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 23 | bool connected, |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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; |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 45 | bool new_group = false; |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | } |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 65 | new_group = true; |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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(); |
Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 110 | fst_global_initialized = 1; |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | |
Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 120 | if (!fst_global_initialized) |
| 121 | return; |
| 122 | |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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); |
Dmitry Shmidt | d5ab1b5 | 2016-06-21 12:38:41 -0700 | [diff] [blame] | 130 | fst_global_initialized = 0; |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | { |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 169 | if (fst_iface_is_connected(iface, mgmt->sa, false)) |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 190 | fst_ctrl_iface_notify_peer_state_change(iface, true, addr); |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 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 | |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 206 | fst_ctrl_iface_notify_peer_state_change(iface, false, addr); |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | |
Hai Shalom | e21d4e8 | 2020-04-29 16:34:06 -0700 | [diff] [blame^] | 210 | bool fst_are_ifaces_aggregated(struct fst_iface *iface1, |
| 211 | struct fst_iface *iface2) |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 212 | { |
| 213 | return fst_iface_get_group(iface1) == fst_iface_get_group(iface2); |
| 214 | } |
| 215 | |
| 216 | |
Hai Shalom | c356592 | 2019-10-28 11:58:20 -0700 | [diff] [blame] | 217 | void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr) |
| 218 | { |
| 219 | fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR, |
| 220 | MAC2STR(addr)); |
| 221 | os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr)); |
| 222 | fst_group_update_ie(fst_iface_get_group(iface)); |
| 223 | } |
| 224 | |
| 225 | |
Dmitry Shmidt | d80a401 | 2015-11-05 16:35:40 -0800 | [diff] [blame] | 226 | enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode) |
| 227 | { |
| 228 | switch (mode) { |
| 229 | case HOSTAPD_MODE_IEEE80211B: |
| 230 | case HOSTAPD_MODE_IEEE80211G: |
| 231 | return MB_BAND_ID_WIFI_2_4GHZ; |
| 232 | case HOSTAPD_MODE_IEEE80211A: |
| 233 | return MB_BAND_ID_WIFI_5GHZ; |
| 234 | case HOSTAPD_MODE_IEEE80211AD: |
| 235 | return MB_BAND_ID_WIFI_60GHZ; |
| 236 | default: |
| 237 | WPA_ASSERT(0); |
| 238 | return MB_BAND_ID_WIFI_2_4GHZ; |
| 239 | } |
| 240 | } |