developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame] | 1 | From 11cfbaf42eaadf0fd7b50d13f0b7664c1675dc11 Mon Sep 17 00:00:00 2001 |
| 2 | From: Rameshkumar Sundaram <quic_ramess@quicinc.com> |
| 3 | Date: Thu, 28 Mar 2024 23:46:46 +0530 |
| 4 | Subject: [PATCH 016/104] hostapd: MLO: Enhance wpa state machine |
| 5 | |
| 6 | Add required ML Specific members in wpa_authenticator and struct |
| 7 | wpa_state_machine to maintain self and partner link information. |
| 8 | |
| 9 | Maintain state machine object in all associated link stations and |
| 10 | destroy/remove references from the same whenever link stations are getting |
| 11 | removed. |
| 12 | |
| 13 | Increase the wpa_group object reference count for all links in which ML |
| 14 | station is getting associated and release the same whenever link stations |
| 15 | are getting removed. |
| 16 | |
| 17 | Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com> |
| 18 | Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com> |
| 19 | --- |
| 20 | src/ap/ieee802_11.c | 9 ++-- |
| 21 | src/ap/sta_info.c | 35 ++++++++++++++- |
| 22 | src/ap/wpa_auth.c | 101 +++++++++++++++++++++++++++++++++++++++++--- |
| 23 | src/ap/wpa_auth.h | 16 +++++++ |
| 24 | src/ap/wpa_auth_i.h | 8 ++++ |
| 25 | 5 files changed, 159 insertions(+), 10 deletions(-) |
| 26 | |
| 27 | diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
| 28 | index 39c63f29b..9d04bdf43 100644 |
| 29 | --- a/src/ap/ieee802_11.c |
| 30 | +++ b/src/ap/ieee802_11.c |
| 31 | @@ -4467,6 +4467,8 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd, |
| 32 | } |
| 33 | |
| 34 | sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK; |
| 35 | + sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id; |
| 36 | + |
| 37 | status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true); |
| 38 | if (status != WLAN_STATUS_SUCCESS) { |
| 39 | wpa_printf(MSG_DEBUG, "MLD: link: Element check failed"); |
| 40 | @@ -4474,7 +4476,6 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd, |
| 41 | } |
| 42 | |
| 43 | ap_sta_set_mld(sta, true); |
| 44 | - sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id; |
| 45 | |
| 46 | os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info)); |
| 47 | for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { |
| 48 | @@ -4501,9 +4502,11 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd, |
| 49 | ieee802_11_update_beacons(hapd->iface); |
| 50 | } |
| 51 | |
| 52 | - /* RSN Authenticator should always be the one on the original station */ |
| 53 | + /* Maintain state machine reference on all link STAs, this is needed |
| 54 | + * during Group rekey handling. |
| 55 | + */ |
| 56 | wpa_auth_sta_deinit(sta->wpa_sm); |
| 57 | - sta->wpa_sm = NULL; |
| 58 | + sta->wpa_sm = origin_sta->wpa_sm; |
| 59 | |
| 60 | /* |
| 61 | * Do not initialize the EAPOL state machine. |
| 62 | diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c |
| 63 | index 2423ff189..d483aa9d3 100644 |
| 64 | --- a/src/ap/sta_info.c |
| 65 | +++ b/src/ap/sta_info.c |
| 66 | @@ -199,6 +199,26 @@ static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) |
| 67 | hostapd_drv_sta_remove(hapd, sta->addr); |
| 68 | } |
| 69 | |
| 70 | +#ifdef CONFIG_IEEE80211BE |
| 71 | +static void set_for_each_partner_link_sta(struct hostapd_data *hapd, |
| 72 | + struct sta_info *psta, void *data) |
| 73 | +{ |
| 74 | + struct sta_info *lsta; |
| 75 | + struct hostapd_data *lhapd; |
| 76 | + |
| 77 | + if (!ap_sta_is_mld(hapd, psta)) |
| 78 | + return; |
| 79 | + |
| 80 | + for_each_mld_link(lhapd, hapd) { |
| 81 | + if (lhapd == hapd) |
| 82 | + continue; |
| 83 | + |
| 84 | + lsta = ap_get_sta(lhapd, psta->addr); |
| 85 | + if (lsta) |
| 86 | + lsta->wpa_sm = data; |
| 87 | + } |
| 88 | +} |
| 89 | +#endif /* CONFIG_IEEE80211BE */ |
| 90 | |
| 91 | void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) |
| 92 | { |
| 93 | @@ -317,8 +337,17 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) |
| 94 | |
| 95 | #ifdef CONFIG_IEEE80211BE |
| 96 | if (!ap_sta_is_mld(hapd, sta) || |
| 97 | - hapd->mld_link_id == sta->mld_assoc_link_id) |
| 98 | + hapd->mld_link_id == sta->mld_assoc_link_id) { |
| 99 | wpa_auth_sta_deinit(sta->wpa_sm); |
| 100 | + /* Remove refrences from partner links. */ |
| 101 | + set_for_each_partner_link_sta(hapd, sta, NULL); |
| 102 | + } |
| 103 | + |
| 104 | + /* Release group references in case non assoc link STA is removed |
| 105 | + * before assoc link STA |
| 106 | + */ |
| 107 | + if (hostapd_sta_is_link_sta(hapd, sta)) |
| 108 | + wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id); |
| 109 | #else |
| 110 | wpa_auth_sta_deinit(sta->wpa_sm); |
| 111 | #endif /* CONFIG_IEEE80211BE */ |
| 112 | @@ -903,8 +932,10 @@ static void ap_sta_disconnect_common(struct hostapd_data *hapd, |
| 113 | ieee802_1x_free_station(hapd, sta); |
| 114 | #ifdef CONFIG_IEEE80211BE |
| 115 | if (!hapd->conf->mld_ap || |
| 116 | - hapd->mld_link_id == sta->mld_assoc_link_id) |
| 117 | + hapd->mld_link_id == sta->mld_assoc_link_id) { |
| 118 | wpa_auth_sta_deinit(sta->wpa_sm); |
| 119 | + set_for_each_partner_link_sta(hapd, sta, NULL); |
| 120 | + } |
| 121 | #else |
| 122 | wpa_auth_sta_deinit(sta->wpa_sm); |
| 123 | #endif /* CONFIG_IEEE80211BE */ |
| 124 | diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c |
| 125 | index 0d15c4209..8c1052c25 100644 |
| 126 | --- a/src/ap/wpa_auth.c |
| 127 | +++ b/src/ap/wpa_auth.c |
| 128 | @@ -102,6 +102,59 @@ static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm) |
| 129 | return sm->addr; |
| 130 | } |
| 131 | |
| 132 | +#ifdef CONFIG_IEEE80211BE |
| 133 | +void wpa_release_link_auth_ref(struct wpa_state_machine *sm, int release_link_id) |
| 134 | +{ |
| 135 | + int link_id; |
| 136 | + |
| 137 | + if (!sm || release_link_id >= MAX_NUM_MLD_LINKS) |
| 138 | + return; |
| 139 | + |
| 140 | + for_each_sm_auth(sm, link_id) |
| 141 | + if (link_id == release_link_id) { |
| 142 | + wpa_group_put(sm->mld_links[link_id].wpa_auth, |
| 143 | + sm->mld_links[link_id].wpa_auth->group); |
| 144 | + sm->mld_links[link_id].wpa_auth = NULL; |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +static int wpa_get_link_sta_auth(struct wpa_authenticator *wpa_auth, void *data) |
| 149 | +{ |
| 150 | + struct wpa_get_link_auth_ctx *ctx = data; |
| 151 | + |
| 152 | + if (os_memcmp(wpa_auth->addr, ctx->addr, ETH_ALEN) != 0) |
| 153 | + return 0; |
| 154 | + ctx->wpa_auth = wpa_auth; |
| 155 | + return 1; |
| 156 | +} |
| 157 | + |
| 158 | +static int wpa_get_primary_wpa_auth_cb(struct wpa_authenticator *wpa_auth, void *data) |
| 159 | +{ |
| 160 | + struct wpa_get_link_auth_ctx *ctx = data; |
| 161 | + |
| 162 | + if (!wpa_auth->is_ml || os_memcmp(wpa_auth->mld_addr, ctx->addr, ETH_ALEN) != 0 || |
| 163 | + !wpa_auth->primary_auth) |
| 164 | + return 0; |
| 165 | + |
| 166 | + ctx->wpa_auth = wpa_auth; |
| 167 | + return 1; |
| 168 | +} |
| 169 | + |
| 170 | +static struct wpa_authenticator * |
| 171 | +wpa_get_primary_wpa_auth(struct wpa_authenticator *wpa_auth) |
| 172 | +{ |
| 173 | + struct wpa_get_link_auth_ctx ctx; |
| 174 | + |
| 175 | + if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth) |
| 176 | + return wpa_auth; |
| 177 | + |
| 178 | + ctx.addr = wpa_auth->mld_addr; |
| 179 | + ctx.wpa_auth = NULL; |
| 180 | + wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_wpa_auth_cb, &ctx); |
| 181 | + |
| 182 | + return ctx.wpa_auth; |
| 183 | +} |
| 184 | +#endif /* CONFIG_IEEE80211BE */ |
| 185 | |
| 186 | static inline int wpa_auth_mic_failure_report( |
| 187 | struct wpa_authenticator *wpa_auth, const u8 *addr) |
| 188 | @@ -798,6 +851,10 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) |
| 189 | |
| 190 | static void wpa_free_sta_sm(struct wpa_state_machine *sm) |
| 191 | { |
| 192 | +#ifdef CONFIG_IEEE80211BE |
| 193 | + int link_id; |
| 194 | +#endif /* CONFIG_IEEE80211BE */ |
| 195 | + |
| 196 | #ifdef CONFIG_P2P |
| 197 | if (WPA_GET_BE32(sm->ip_addr)) { |
| 198 | wpa_printf(MSG_DEBUG, |
| 199 | @@ -821,6 +878,13 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) |
| 200 | os_free(sm->last_rx_eapol_key); |
| 201 | os_free(sm->wpa_ie); |
| 202 | os_free(sm->rsnxe); |
| 203 | +#ifdef CONFIG_IEEE80211BE |
| 204 | + for_each_sm_auth(sm, link_id) { |
| 205 | + wpa_group_put(sm->mld_links[link_id].wpa_auth, |
| 206 | + sm->mld_links[link_id].wpa_auth->group); |
| 207 | + sm->mld_links[link_id].wpa_auth = NULL; |
| 208 | + } |
| 209 | +#endif /* CONFIG_IEEE80211BE */ |
| 210 | wpa_group_put(sm->wpa_auth, sm->group); |
| 211 | #ifdef CONFIG_DPP2 |
| 212 | wpabuf_clear_free(sm->dpp_z); |
| 213 | @@ -831,7 +895,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) |
| 214 | |
| 215 | void wpa_auth_sta_deinit(struct wpa_state_machine *sm) |
| 216 | { |
| 217 | - struct wpa_authenticator *wpa_auth; |
| 218 | + struct wpa_authenticator *wpa_auth, *primary_wpa_auth; |
| 219 | |
| 220 | if (!sm) |
| 221 | return; |
| 222 | @@ -840,10 +904,18 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) |
| 223 | if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { |
| 224 | wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, |
| 225 | "strict rekeying - force GTK rekey since STA is leaving"); |
| 226 | + |
| 227 | +#ifdef CONFIG_IEEE80211BE |
| 228 | + if (wpa_auth->is_ml && !wpa_auth->primary_auth) |
| 229 | + primary_wpa_auth = wpa_get_primary_wpa_auth(wpa_auth); |
| 230 | + else |
| 231 | +#endif /* CONFIG_IEEE80211BE */ |
| 232 | + primary_wpa_auth = wpa_auth; |
| 233 | + |
| 234 | if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk, |
| 235 | - wpa_auth, NULL) == -1) |
| 236 | + primary_wpa_auth, NULL) == -1) |
| 237 | eloop_register_timeout(0, 500000, wpa_rekey_gtk, |
| 238 | - wpa_auth, NULL); |
| 239 | + primary_wpa_auth, NULL); |
| 240 | } |
| 241 | |
| 242 | eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); |
| 243 | @@ -6835,6 +6907,7 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr, |
| 244 | for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { |
| 245 | struct mld_link_info *link = &info->links[link_id]; |
| 246 | struct mld_link *sm_link = &sm->mld_links[link_id]; |
| 247 | + struct wpa_get_link_auth_ctx ctx; |
| 248 | |
| 249 | sm_link->valid = link->valid; |
| 250 | if (!link->valid) |
| 251 | @@ -6849,10 +6922,28 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr, |
| 252 | MAC2STR(sm_link->own_addr), |
| 253 | MAC2STR(sm_link->peer_addr)); |
| 254 | |
| 255 | - if (link_id != mld_assoc_link_id) |
| 256 | + ml_rsn_info.links[i++].link_id = link_id; |
| 257 | + |
| 258 | + if (link_id != mld_assoc_link_id) { |
| 259 | sm->n_mld_affiliated_links++; |
| 260 | + ctx.addr = link->local_addr; |
| 261 | + ctx.wpa_auth = NULL; |
| 262 | + wpa_auth_for_each_auth(sm->wpa_auth, wpa_get_link_sta_auth, &ctx); |
| 263 | + |
| 264 | + if (ctx.wpa_auth) { |
| 265 | + sm_link->wpa_auth = ctx.wpa_auth; |
| 266 | + wpa_group_get(sm_link->wpa_auth, |
| 267 | + sm_link->wpa_auth->group); |
| 268 | + } |
| 269 | + } else { |
| 270 | + sm_link->wpa_auth = sm->wpa_auth; |
| 271 | + } |
| 272 | |
| 273 | - ml_rsn_info.links[i++].link_id = link_id; |
| 274 | + if (!sm_link->wpa_auth) |
| 275 | + wpa_printf(MSG_ERROR, "Unable to find authenticator object for " |
| 276 | + "ML STA " MACSTR " on link " MACSTR " link id %d", |
| 277 | + MAC2STR(sm->own_mld_addr), MAC2STR(sm_link->own_addr), |
| 278 | + link_id); |
| 279 | } |
| 280 | |
| 281 | ml_rsn_info.n_mld_links = i; |
| 282 | diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h |
| 283 | index c74862307..1446872f3 100644 |
| 284 | --- a/src/ap/wpa_auth.h |
| 285 | +++ b/src/ap/wpa_auth.h |
| 286 | @@ -647,4 +647,20 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a, |
| 287 | struct wpa_auth_ml_link_key_info *info, |
| 288 | bool mgmt_frame_prot, bool beacon_prot); |
| 289 | |
| 290 | +#ifdef CONFIG_IEEE80211BE |
| 291 | +void wpa_release_link_auth_ref(struct wpa_state_machine *sm, |
| 292 | + int release_link_id); |
| 293 | + |
| 294 | +#define for_each_sm_auth(sm, link_id) \ |
| 295 | + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) \ |
| 296 | + if (sm->mld_links[link_id].valid && \ |
| 297 | + sm->mld_links[link_id].wpa_auth && \ |
| 298 | + sm->wpa_auth != sm->mld_links[link_id].wpa_auth) \ |
| 299 | + |
| 300 | +struct wpa_get_link_auth_ctx { |
| 301 | + u8 *addr; |
| 302 | + struct wpa_authenticator *wpa_auth; |
| 303 | +}; |
| 304 | +#endif /* CONFIG_IEEE80211BE */ |
| 305 | + |
| 306 | #endif /* WPA_AUTH_H */ |
| 307 | diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h |
| 308 | index 9ba830415..9ba90749d 100644 |
| 309 | --- a/src/ap/wpa_auth_i.h |
| 310 | +++ b/src/ap/wpa_auth_i.h |
| 311 | @@ -186,6 +186,7 @@ struct wpa_state_machine { |
| 312 | size_t rsne_len; |
| 313 | const u8 *rsnxe; |
| 314 | size_t rsnxe_len; |
| 315 | + struct wpa_authenticator *wpa_auth; |
| 316 | } mld_links[MAX_NUM_MLD_LINKS]; |
| 317 | #endif /* CONFIG_IEEE80211BE */ |
| 318 | }; |
| 319 | @@ -262,6 +263,13 @@ struct wpa_authenticator { |
| 320 | #ifdef CONFIG_P2P |
| 321 | struct bitfield *ip_pool; |
| 322 | #endif /* CONFIG_P2P */ |
| 323 | + |
| 324 | +#ifdef CONFIG_IEEE80211BE |
| 325 | + bool is_ml; |
| 326 | + u8 mld_addr[ETH_ALEN]; |
| 327 | + u8 link_id; |
| 328 | + bool primary_auth; |
| 329 | +#endif /* CONFIG_IEEE80211BE */ |
| 330 | }; |
| 331 | |
| 332 | |
| 333 | -- |
| 334 | 2.39.2 |
| 335 | |