From 3085bf3ccc53c62fb5688f34f007d9874be82141 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 13 Jul 2024 15:36:42 +0200 Subject: [PATCH] hostapd: add rate support to FT Signed-off-by: John Crispin --- .../hostapd/patches/751-wispr-ft.patch | 551 ++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 feeds/ipq807x_v5.4/hostapd/patches/751-wispr-ft.patch diff --git a/feeds/ipq807x_v5.4/hostapd/patches/751-wispr-ft.patch b/feeds/ipq807x_v5.4/hostapd/patches/751-wispr-ft.patch new file mode 100644 index 000000000..9090c2faa --- /dev/null +++ b/feeds/ipq807x_v5.4/hostapd/patches/751-wispr-ft.patch @@ -0,0 +1,551 @@ +--- a/src/ap/wpa_auth.h ++++ b/src/ap/wpa_auth.h +@@ -15,6 +15,10 @@ + #include "common/ieee802_11_defs.h" + + struct vlan_description; ++struct rate_description { ++ u32 rx; ++ u32 tx; ++}; + + #define MAX_OWN_IE_OVERRIDE 256 + +@@ -87,6 +91,7 @@ struct ft_rrb_frame { + #define FT_RRB_IDENTITY 15 + #define FT_RRB_RADIUS_CUI 16 + #define FT_RRB_SESSION_TIMEOUT 17 /* le32 seconds */ ++#define FT_RRB_RATE_LIMIT 18 + + struct ft_rrb_tlv { + le16 type; +@@ -327,6 +332,10 @@ struct wpa_auth_callbacks { + struct vlan_description *vlan); + int (*get_vlan)(void *ctx, const u8 *sta_addr, + struct vlan_description *vlan); ++ int (*set_rate_limit)(void *ctx, const u8 *sta_addr, ++ struct rate_description *rate); ++ int (*get_rate_limit)(void *ctx, const u8 *sta_addr, ++ struct rate_description *rate); + int (*set_identity)(void *ctx, const u8 *sta_addr, + const u8 *identity, size_t identity_len); + size_t (*get_identity)(void *ctx, const u8 *sta_addr, const u8 **buf); +@@ -479,7 +488,7 @@ int wpa_ft_fetch_pmk_r1(struct wpa_authe + struct vlan_description *vlan, + const u8 **identity, size_t *identity_len, + const u8 **radius_cui, size_t *radius_cui_len, +- int *session_timeout); ++ int *session_timeout, struct rate_description *rate); + + #endif /* CONFIG_IEEE80211R_AP */ + +--- a/src/ap/wpa_auth_glue.c ++++ b/src/ap/wpa_auth_glue.c +@@ -1172,6 +1172,40 @@ static int hostapd_wpa_auth_get_vlan(voi + } + + ++static int hostapd_wpa_auth_set_rate_limit(void *ctx, const u8 *sta_addr, ++ struct rate_description *rate) ++{ ++ struct hostapd_data *hapd = ctx; ++ struct sta_info *sta; ++ ++ sta = ap_get_sta(hapd, sta_addr); ++ if (!sta || !sta->wpa_sm) ++ return -1; ++ ++ memcpy(sta->bandwidth, rate, sizeof(*rate)); ++ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_INFO, "rate-limit %d %d", sta->bandwidth[0], sta->bandwidth[1]); ++ ++ return 0; ++} ++ ++ ++static int hostapd_wpa_auth_get_rate_limit(void *ctx, const u8 *sta_addr, ++ struct rate_description *rate) ++{ ++ struct hostapd_data *hapd = ctx; ++ struct sta_info *sta; ++ ++ sta = ap_get_sta(hapd, sta_addr); ++ if (!sta) ++ return -1; ++ ++ memcpy(rate, sta->bandwidth, sizeof(*rate)); ++ ++ return 0; ++} ++ ++ + static int + hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr, + const u8 *identity, size_t identity_len) +@@ -1490,6 +1524,8 @@ int hostapd_setup_wpa(struct hostapd_dat + .add_tspec = hostapd_wpa_auth_add_tspec, + .set_vlan = hostapd_wpa_auth_set_vlan, + .get_vlan = hostapd_wpa_auth_get_vlan, ++ .set_rate_limit = hostapd_wpa_auth_set_rate_limit, ++ .get_rate_limit = hostapd_wpa_auth_get_rate_limit, + .set_identity = hostapd_wpa_auth_set_identity, + .get_identity = hostapd_wpa_auth_get_identity, + .set_radius_cui = hostapd_wpa_auth_set_radius_cui, +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -3215,7 +3215,7 @@ static void handle_auth_pasn_1(struct ho + rsn_data.pmkid, + pmk_r1, &pmk_r1_len, NULL, + NULL, NULL, NULL, +- NULL, NULL, NULL); ++ NULL, NULL, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: FT: Failed getting PMK-R1"); +--- a/src/ap/wpa_auth_ft.c ++++ b/src/ap/wpa_auth_ft.c +@@ -375,6 +375,14 @@ static size_t wpa_ft_vlan_len(const stru + return tlv_len; + } + ++static size_t wpa_ft_rate_limit_len(const struct rate_description *rate) ++{ ++ if (!rate || (!rate->rx && !rate->tx)) ++ return 0; ++ ++ return (sizeof(struct ft_rrb_tlv) + 8); ++} ++ + + static size_t wpa_ft_vlan_lin(const struct vlan_description *vlan, + u8 *start, u8 *endpos) +@@ -430,10 +438,47 @@ static size_t wpa_ft_vlan_lin(const stru + } + + ++static size_t wpa_ft_rate_limit_lin(const struct rate_description *rate, ++ u8 *start, u8 *endpos) ++{ ++ size_t tlv_len; ++ int i, len; ++ struct ft_rrb_tlv *hdr; ++ u8 *pos = start; ++ ++ if (!rate) ++ return 0; ++ ++ tlv_len = 0; ++ if (rate->rx || rate->tx) { ++ tlv_len += sizeof(*hdr); ++ if (start + tlv_len > endpos) ++ return tlv_len; ++ hdr = (struct ft_rrb_tlv *) pos; ++ hdr->type = host_to_le16(FT_RRB_RATE_LIMIT); ++ hdr->len = host_to_le16(sizeof(le16)); ++ pos = start + tlv_len; ++ ++ tlv_len += sizeof(u32); ++ if (start + tlv_len > endpos) ++ return tlv_len; ++ WPA_PUT_LE32(pos, rate->rx); ++ tlv_len += sizeof(u32); ++ if (start + tlv_len > endpos) ++ return tlv_len; ++ WPA_PUT_LE32(pos, rate->tx); ++ pos = start + tlv_len; ++ } ++ ++ return tlv_len; ++} ++ ++ + static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1, + const struct tlv_list *tlvs2, + const struct vlan_description *vlan, +- u8 **plain, size_t *plain_len) ++ u8 **plain, size_t *plain_len, ++ const struct rate_description *rate) + { + u8 *pos, *endpos; + size_t tlv_len; +@@ -441,6 +486,7 @@ static int wpa_ft_rrb_lin(const struct t + tlv_len = wpa_ft_tlv_len(tlvs1); + tlv_len += wpa_ft_tlv_len(tlvs2); + tlv_len += wpa_ft_vlan_len(vlan); ++ tlv_len += wpa_ft_rate_limit_len(rate); + + *plain_len = tlv_len; + *plain = os_zalloc(tlv_len); +@@ -454,6 +500,7 @@ static int wpa_ft_rrb_lin(const struct t + pos += wpa_ft_tlv_lin(tlvs1, pos, endpos); + pos += wpa_ft_tlv_lin(tlvs2, pos, endpos); + pos += wpa_ft_vlan_lin(vlan, pos, endpos); ++ pos += wpa_ft_rate_limit_lin(rate, pos, endpos); + + /* sanity check */ + if (pos != endpos) { +@@ -522,7 +569,8 @@ static int wpa_ft_rrb_build(const u8 *ke + const struct tlv_list *tlvs_auth, + const struct vlan_description *vlan, + const u8 *src_addr, u8 type, +- u8 **packet, size_t *packet_len) ++ u8 **packet, size_t *packet_len, ++ const struct rate_description *rate) + { + u8 *plain = NULL, *auth = NULL, *pos, *tmp; + size_t plain_len = 0, auth_len = 0; +@@ -530,10 +578,10 @@ static int wpa_ft_rrb_build(const u8 *ke + size_t pad_len = 0; + + *packet = NULL; +- if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0) ++ if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len, rate) < 0) + goto out; + +- if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len) < 0) ++ if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len, NULL) < 0) + goto out; + + *packet_len = sizeof(u16) + auth_len + plain_len; +@@ -696,6 +744,24 @@ static int wpa_ft_get_vlan(struct wpa_au + } + + ++static int wpa_ft_get_rate_limit(struct wpa_authenticator *wpa_auth, ++ const u8 *sta_addr, struct rate_description *rate) ++{ ++ if (!wpa_auth->cb->get_rate_limit) ++ return -1; ++ return wpa_auth->cb->get_rate_limit(wpa_auth->cb_ctx, sta_addr, rate); ++} ++ ++ ++static int wpa_ft_set_rate_limit(struct wpa_authenticator *wpa_auth, ++ const u8 *sta_addr, struct rate_description *rate) ++{ ++ if (!wpa_auth->cb->set_rate_limit) ++ return -1; ++ return wpa_auth->cb->set_rate_limit(wpa_auth->cb_ctx, sta_addr, rate); ++} ++ ++ + static int + wpa_ft_set_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, + const u8 *identity, size_t identity_len) +@@ -991,7 +1057,7 @@ wpa_ft_rrb_seq_req(struct wpa_authentica + + if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth, NULL, + wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_REQ, +- &packet, &packet_len) < 0) { ++ &packet, &packet_len, NULL) < 0) { + item = NULL; /* some other seq resp might still accept this */ + goto err; + } +@@ -1174,6 +1240,7 @@ struct wpa_ft_pmk_r0_sa { + u8 spa[ETH_ALEN]; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ + struct vlan_description *vlan; ++ struct rate_description *rate; + os_time_t expiration; /* 0 for no expiration */ + u8 *identity; + size_t identity_len; +@@ -1192,6 +1259,7 @@ struct wpa_ft_pmk_r1_sa { + u8 spa[ETH_ALEN]; + int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ + struct vlan_description *vlan; ++ struct rate_description *rate; + u8 *identity; + size_t identity_len; + u8 *radius_cui; +@@ -1220,6 +1288,7 @@ static void wpa_ft_free_pmk_r0(struct wp + + os_memset(r0->pmk_r0, 0, PMK_LEN_MAX); + os_free(r0->vlan); ++ os_free(r0->rate); + os_free(r0->identity); + os_free(r0->radius_cui); + os_free(r0); +@@ -1273,6 +1342,7 @@ static void wpa_ft_free_pmk_r1(struct wp + eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL); + + os_memset(r1->pmk_r1, 0, PMK_LEN_MAX); ++ os_free(r1->rate); + os_free(r1->vlan); + os_free(r1->identity); + os_free(r1->radius_cui); +@@ -1326,7 +1396,8 @@ static int wpa_ft_store_pmk_r0(struct wp + const struct vlan_description *vlan, + int expires_in, int session_timeout, + const u8 *identity, size_t identity_len, +- const u8 *radius_cui, size_t radius_cui_len) ++ const u8 *radius_cui, size_t radius_cui_len, ++ struct rate_description *rate) + { + struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; + struct wpa_ft_pmk_r0_sa *r0; +@@ -1354,6 +1425,14 @@ static int wpa_ft_store_pmk_r0(struct wp + } + *r0->vlan = *vlan; + } ++ if (rate) { ++ r0->rate = os_zalloc(sizeof(*rate)); ++ if (!r0->rate) { ++ bin_clear_free(r0, sizeof(*r0)); ++ return -1; ++ } ++ *r0->rate = *rate; ++ } + if (identity) { + r0->identity = os_malloc(identity_len); + if (r0->identity) { +@@ -1413,7 +1492,8 @@ static int wpa_ft_store_pmk_r1(struct wp + const struct vlan_description *vlan, + int expires_in, int session_timeout, + const u8 *identity, size_t identity_len, +- const u8 *radius_cui, size_t radius_cui_len) ++ const u8 *radius_cui, size_t radius_cui_len, ++ struct rate_description *rate) + { + struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; + int max_expires_in = wpa_auth->conf.r1_max_key_lifetime; +@@ -1443,6 +1523,14 @@ static int wpa_ft_store_pmk_r1(struct wp + } + *r1->vlan = *vlan; + } ++ if (rate) { ++ r1->rate = os_zalloc(sizeof(*rate)); ++ if (!r1->rate) { ++ bin_clear_free(r1, sizeof(*r1)); ++ return -1; ++ } ++ *r1->rate = *rate; ++ } + if (identity) { + r1->identity = os_malloc(identity_len); + if (r1->identity) { +@@ -1479,7 +1567,7 @@ int wpa_ft_fetch_pmk_r1(struct wpa_authe + struct vlan_description *vlan, + const u8 **identity, size_t *identity_len, + const u8 **radius_cui, size_t *radius_cui_len, +- int *session_timeout) ++ int *session_timeout, struct rate_description *rate) + { + struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; + struct wpa_ft_pmk_r1_sa *r1; +@@ -1499,6 +1587,12 @@ int wpa_ft_fetch_pmk_r1(struct wpa_authe + *vlan = *r1->vlan; + if (vlan && !r1->vlan) + os_memset(vlan, 0, sizeof(*vlan)); ++ if (rate) { ++ if (r1->rate) ++ *rate = *r1->rate; ++ else ++ memset(rate, 0, sizeof(*rate)); ++ } + if (identity && identity_len) { + *identity = r1->identity; + *identity_len = r1->identity_len; +@@ -2025,7 +2119,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa + + if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth, NULL, + sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL, +- &packet, &packet_len) < 0) ++ &packet, &packet_len, NULL) < 0) + return -1; + + ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); +@@ -2054,6 +2148,7 @@ int wpa_ft_store_pmk_fils(struct wpa_sta + { + int expires_in = sm->wpa_auth->conf.r0_key_lifetime; + struct vlan_description vlan; ++ struct rate_description rate; + const u8 *identity, *radius_cui; + size_t identity_len, radius_cui_len; + int session_timeout; +@@ -2065,6 +2160,7 @@ int wpa_ft_store_pmk_fils(struct wpa_sta + MAC2STR(sm->addr)); + return -1; + } ++ wpa_ft_get_rate_limit(sm->wpa_auth, sm->addr, &rate); + + identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity); + radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr, +@@ -2074,7 +2170,7 @@ int wpa_ft_store_pmk_fils(struct wpa_sta + return wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len, + pmk_r0_name, sm->pairwise, &vlan, expires_in, + session_timeout, identity, identity_len, +- radius_cui, radius_cui_len); ++ radius_cui, radius_cui_len, &rate); + } + + +@@ -2095,6 +2191,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_st + int psk_local = sm->wpa_auth->conf.ft_psk_generate_local; + int expires_in = sm->wpa_auth->conf.r0_key_lifetime; + struct vlan_description vlan; ++ struct rate_description rate; + const u8 *identity, *radius_cui; + size_t identity_len, radius_cui_len; + int session_timeout; +@@ -2119,6 +2216,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_st + return -1; + } + ++ wpa_ft_get_rate_limit(sm->wpa_auth, sm->addr, &rate); ++ + identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity); + radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr, + &radius_cui); +@@ -2134,7 +2233,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_st + pmk_r0_name, + sm->pairwise, &vlan, expires_in, + session_timeout, identity, identity_len, +- radius_cui, radius_cui_len); ++ radius_cui, radius_cui_len, &rate); + + if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr, + pmk_r1, sm->pmk_r1_name) < 0) +@@ -2143,7 +2242,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_st + wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len, + sm->pmk_r1_name, sm->pairwise, &vlan, + expires_in, session_timeout, identity, +- identity_len, radius_cui, radius_cui_len); ++ identity_len, radius_cui, radius_cui_len, ++ &rate); + + return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce, + sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name, +@@ -2986,7 +3086,8 @@ static int wpa_ft_local_derive_pmk_r1(st + const u8 **identity, size_t *identity_len, + const u8 **radius_cui, + size_t *radius_cui_len, +- int *out_session_timeout) ++ int *out_session_timeout, ++ struct rate_description *rate) + { + struct wpa_auth_config *conf = &wpa_auth->conf; + const struct wpa_ft_pmk_r0_sa *r0; +@@ -3023,7 +3124,8 @@ static int wpa_ft_local_derive_pmk_r1(st + pmk_r1_name, + sm->pairwise, r0->vlan, expires_in, session_timeout, + r0->identity, r0->identity_len, +- r0->radius_cui, r0->radius_cui_len); ++ r0->radius_cui, r0->radius_cui_len, ++ r0->rate); + + *out_pairwise = sm->pairwise; + if (vlan) { +@@ -3033,6 +3135,13 @@ static int wpa_ft_local_derive_pmk_r1(st + os_memset(vlan, 0, sizeof(*vlan)); + } + ++ if (rate) { ++ if (r0->rate) ++ *rate = *r0->rate; ++ else ++ os_memset(rate, 0, sizeof(*rate)); ++ } ++ + if (identity && identity_len) { + *identity = r0->identity; + *identity_len = r0->identity_len; +@@ -3063,6 +3172,7 @@ static int wpa_ft_process_auth_req(struc + u8 *pos, *end; + int pairwise, session_timeout = 0; + struct vlan_description vlan; ++ struct rate_description rate = {}; + const u8 *identity, *radius_cui; + size_t identity_len = 0, radius_cui_len = 0; + int use_sha384; +@@ -3152,7 +3262,7 @@ static int wpa_ft_process_auth_req(struc + } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, + pmk_r1, &pmk_r1_len, &pairwise, &vlan, + &identity, &identity_len, &radius_cui, +- &radius_cui_len, &session_timeout) < 0) { ++ &radius_cui_len, &session_timeout, &rate) < 0) { + wpa_printf(MSG_DEBUG, + "FT: No PMK-R1 available in local cache for the requested PMKR1Name"); + if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm, +@@ -3161,7 +3271,7 @@ static int wpa_ft_process_auth_req(struc + pmk_r1_name, pmk_r1, &pairwise, + &vlan, &identity, &identity_len, + &radius_cui, &radius_cui_len, +- &session_timeout) == 0) { ++ &session_timeout, &rate) == 0) { + wpa_printf(MSG_DEBUG, + "FT: Generated PMK-R1 based on local PMK-R0"); + goto pmk_r1_derived; +@@ -3219,6 +3329,7 @@ pmk_r1_derived: + wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } ++ wpa_ft_set_rate_limit(sm->wpa_auth, sm->addr, &rate); + if (wpa_ft_set_identity(sm->wpa_auth, sm->addr, + identity, identity_len) < 0 || + wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr, +@@ -3791,7 +3902,7 @@ static int wpa_ft_rrb_build_r0(const u8 + + ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth, + pmk_r0->vlan, src_addr, type, +- packet, packet_len); ++ packet, packet_len, pmk_r0->rate); + + forced_memzero(pmk_r1, sizeof(pmk_r1)); + +@@ -3931,7 +4042,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa + ret = wpa_ft_rrb_build(key, key_len, resp, NULL, resp_auth, + NULL, wpa_auth->addr, + FT_PACKET_R0KH_R1KH_RESP, +- &packet, &packet_len); ++ &packet, &packet_len, NULL); + } else { + ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, + f_s1kh_id, resp_auth, wpa_auth->addr, +@@ -3983,11 +4094,15 @@ static int wpa_ft_rrb_rx_r1(struct wpa_a + size_t f_expires_in_len; + size_t f_identity_len, f_radius_cui_len; + size_t f_session_timeout_len; ++ size_t f_rate_len; ++ const u8 *f_rate; + int pairwise; + int ret = -1; + int expires_in; + int session_timeout; + struct vlan_description vlan; ++ struct rate_description rate; ++ int has_rate = 0; + size_t pmk_r1_len; + + RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1); +@@ -4096,6 +4211,13 @@ static int wpa_ft_rrb_rx_r1(struct wpa_a + wpa_printf(MSG_DEBUG, "FT: vlan %d%s", + le_to_host16(vlan.untagged), vlan.tagged[0] ? "+" : ""); + ++ RRB_GET_OPTIONAL(FT_RRB_RATE_LIMIT, rate, msgtype, 2 * sizeof(le32)); ++ if (f_rate) { ++ memcpy(&rate, f_rate, sizeof(rate)); ++ rate.rx = le_to_host32(rate.rx); ++ rate.tx = le_to_host32(rate.tx); ++ has_rate = 1; ++ }; + RRB_GET_OPTIONAL(FT_RRB_IDENTITY, identity, msgtype, -1); + if (f_identity) + wpa_hexdump_ascii(MSG_DEBUG, "FT: Identity", f_identity, +@@ -4118,7 +4240,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_a + f_pmk_r1_name, + pairwise, &vlan, expires_in, session_timeout, + f_identity, f_identity_len, f_radius_cui, +- f_radius_cui_len) < 0) ++ f_radius_cui_len, has_rate ? &rate : 0) < 0) + goto out; + + ret = 0; +@@ -4431,7 +4553,7 @@ static int wpa_ft_rrb_rx_seq_req(struct + + if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth, NULL, + wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_RESP, +- &packet, &packet_len) < 0) ++ &packet, &packet_len, NULL) < 0) + goto out; + + wpa_ft_rrb_oui_send(wpa_auth, src_addr,