Compare commits

...

4 Commits

Author SHA1 Message Date
Venkat Chimata
7f99a4d8eb hostapd: store RADIUS Class per STA instead of
EAPOL SM;  preserve Class for ACL/MAC auth and accounting

Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.

This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.

Signed-off-by: Venkat Chimata <venkat@nearhop.com>
2026-03-17 11:49:13 +05:30
Venkat Chimata
f3086d4bb9 ipq807x_v5.4 / hostapd: store RADIUS Class per STA instead of EAPOL SM;
preserve Class for ACL/MAC auth and accounting

Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.

This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.

Signed-off-by: Venkat Chimata <venkat@nearhop.com>
2026-03-17 11:49:13 +05:30
Venkat Chimata
1013cd9241 hostapd: store RADIUS Class per STA instead of EAPOL SM;
preserve Class for ACL/MAC auth and accounting

Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.

This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.

Fixes WIFI-15318

Signed-off-by: Venkat Chimata <venkat@nearhop.com>
2026-03-17 11:49:13 +05:30
Arif Alam
74261d1e9f hostapd: fix session-timeout with radius-psk
backport hostapd commit e6ec62aa2d68e9436daeb4470260a101a06c9213

fixes WIFI-15317

Signed-off-by: Arif Alam <arif.alam@netexperience.com>
2026-03-17 11:49:08 +05:30
5 changed files with 1195 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
From e6ec62aa2d68e9436daeb4470260a101a06c9213 Mon Sep 17 00:00:00 2001
From: Lee Harding <somerandomstring@gmail.com>
Date: Tue, 9 Apr 2024 15:06:38 -0700
Subject: [PATCH] Allow Session-Timeout with PSK RADIUS during 4-way handshake
When the RADIUS response included a Session-Timeout attribute, but is
otherwise valid (an Access-Accept with a valid Tunnel-Password), the
association still failed due to the strict comparison of the accepted
value with HOSTAPD_ACL_ACCEPT. Apparently this combination wasn't
previously tested.
Extend this to allow a packet containing a valid Session-Timeout
attribute to be accepted by extending the "success" comparison to
include HOSTAPD_ACL_ACCEPT_TIMEOUT.
Fixes: 1c3438fec4ba ("RADIUS ACL/PSK check during 4-way handshake")
Signed-off-by: Lee Harding <somerandomstring@gmail.com>
---
src/ap/ieee802_11_auth.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index e723ae74b..98a877dec 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -596,7 +596,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (query->radius_psk) {
struct sta_info *sta;
- bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+ bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
+ cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
sta = ap_get_sta(hapd, query->addr);
if (!sta || !sta->wpa_sm) {
--
2.52.0

View File

@@ -0,0 +1,358 @@
From ff647b3a490692e23ec804e123be1f6f945dee14 Mon Sep 17 00:00:00 2001
From: Venkat Chimata <venkat@nearhop.com>
Date: Mon, 2 Feb 2026 14:42:02 +0530
Subject: [PATCH] hostapd: store RADIUS Class per STA instead of EAPOL SM;
preserve Class for ACL/MAC auth and accounting
Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.
This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.
Signed-off-by: Venkat Chimata <venkat@nearhop.com>
---
src/ap/accounting.c | 3 +-
src/ap/ieee802_11.c | 63 ++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 5 +++
src/ap/ieee802_11_auth.c | 3 ++
src/ap/ieee802_1x.c | 70 +-------------------------------
src/ap/ieee802_1x.h | 2 -
src/ap/pmksa_cache_auth.c | 10 ++---
src/ap/sta_info.c | 1 +
src/ap/sta_info.h | 2 +
src/eapol_auth/eapol_auth_sm_i.h | 1 -
10 files changed, 83 insertions(+), 77 deletions(-)
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 9fc1886..99f8ac9 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -15,6 +15,7 @@
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
+#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ap_config.h"
#include "sta_info.h"
@@ -102,7 +103,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (sta) {
for (i = 0; ; i++) {
- val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
+ val = radius_get_class(sta, &len,
i);
if (val == NULL)
break;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1015100..a414248 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -7996,4 +7996,67 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
return _hostapd_eid_rnr(hapd, eid, type, 1);
}
+void radius_store_class(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u8 *attr_class;
+ size_t class_len;
+ int count, i;
+ struct radius_attr_data *nclass;
+ size_t nclass_count;
+
+ if (!hapd->conf->radius->acct_server || !hapd->radius)
+ return;
+
+ radius_free_class(&sta->radius_class);
+ count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+ if (count <= 0)
+ return;
+
+ nclass = os_calloc(count, sizeof(struct radius_attr_data));
+ if (!nclass)
+ return;
+
+ nclass_count = 0;
+
+ attr_class = NULL;
+ for (i = 0; i < count; i++) {
+ do {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+ &attr_class, &class_len,
+ attr_class) < 0) {
+ i = count;
+ break;
+ }
+ } while (class_len < 1);
+
+ nclass[nclass_count].data = os_memdup(attr_class, class_len);
+ if (!nclass[nclass_count].data)
+ break;
+
+ nclass[nclass_count].len = class_len;
+ nclass_count++;
+ }
+
+ sta->radius_class.attr = nclass;
+ sta->radius_class.count = nclass_count;
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
+ (unsigned long) sta->radius_class.count,
+ MAC2STR(sta->addr));
+}
+
+u8 * radius_get_class(struct sta_info *sta, size_t *len,
+ int idx)
+{
+ if (!sta || !sta->radius_class.attr ||
+ idx >= (int) sta->radius_class.count)
+ return NULL;
+
+ *len = sta->radius_class.attr[idx].len;
+ return sta->radius_class.attr[idx].data;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 953e8b9..e77b2c9 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -230,4 +230,9 @@ u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len);
u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len);
int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
int res, struct radius_sta *info);
+void radius_store_class(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg);
+u8 * radius_get_class(struct sta_info *sta, size_t *len,
+ int idx);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 5a9c138..cf2451b 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -498,6 +498,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_cached_radius_acl *cache;
struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ struct sta_info *sta;
query = hapd->acl_queries;
prev = NULL;
@@ -535,6 +536,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
info = &cache->info;
+ sta = ap_get_sta(hapd, query->addr);
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
@@ -570,6 +572,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (info->identity)
os_memcpy(info->identity, buf, len);
}
+ radius_store_class(hapd, sta, msg);
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d29df98..295b3ca 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1399,7 +1399,7 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
- radius_free_class(&sm->radius_class);
+ radius_free_class(&sta->radius_class);
#endif /* CONFIG_NO_RADIUS */
eapol_auth_free(sm);
@@ -1547,60 +1547,6 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
}
-static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
- struct sta_info *sta,
- struct radius_msg *msg)
-{
- u8 *attr_class;
- size_t class_len;
- struct eapol_state_machine *sm = sta->eapol_sm;
- int count, i;
- struct radius_attr_data *nclass;
- size_t nclass_count;
-
- if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
- return;
-
- radius_free_class(&sm->radius_class);
- count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
- if (count <= 0)
- return;
-
- nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (!nclass)
- return;
-
- nclass_count = 0;
-
- attr_class = NULL;
- for (i = 0; i < count; i++) {
- do {
- if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
- &attr_class, &class_len,
- attr_class) < 0) {
- i = count;
- break;
- }
- } while (class_len < 1);
-
- nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (!nclass[nclass_count].data)
- break;
-
- nclass[nclass_count].len = class_len;
- nclass_count++;
- }
-
- sm->radius_class.attr = nclass;
- sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG,
- "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
- MACSTR,
- (unsigned long) sm->radius_class.count,
- MAC2STR(sta->addr));
-}
-
-
/* Update sta->identity based on User-Name attribute in Access-Accept */
static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
struct sta_info *sta,
@@ -2046,7 +1992,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
- ieee802_1x_store_radius_class(hapd, sta, msg);
+ radius_store_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
ieee802_1x_update_sta_cui(hapd, sta, msg);
ieee802_1x_check_hs20(hapd, sta, msg,
@@ -2656,18 +2602,6 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
}
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
- int idx)
-{
- if (!sm || !sm->radius_class.attr ||
- idx >= (int) sm->radius_class.count)
- return NULL;
-
- *len = sm->radius_class.attr[idx].len;
- return sm->radius_class.attr[idx].data;
-}
-
-
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
if (!sm)
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 70dc11a..bd6ccf2 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -35,8 +35,6 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *data, int len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
- int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index fe5f817..1ef0ee1 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -159,7 +159,7 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
entry->cui = wpabuf_dup(eapol->radius_cui);
#ifndef CONFIG_NO_RADIUS
- radius_copy_class(&entry->radius_class, &eapol->radius_class);
+ radius_copy_class(&entry->radius_class, &((struct sta_info *) eapol->sta)->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
@@ -202,12 +202,12 @@ void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
}
#ifndef CONFIG_NO_RADIUS
- radius_free_class(&eapol->radius_class);
- radius_copy_class(&eapol->radius_class, &entry->radius_class);
+ radius_free_class(&((struct sta_info *) eapol->sta)->radius_class);
+ radius_copy_class(&((struct sta_info *) eapol->sta)->radius_class, &entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
- if (eapol->radius_class.attr) {
+ if (((struct sta_info *) eapol->sta)->radius_class.attr) {
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
- "PMKSA", (unsigned long) eapol->radius_class.count);
+ "PMKSA", (unsigned long) ((struct sta_info *) eapol->sta)->radius_class.count);
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 235ed89..4d69472 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -303,6 +303,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
if (hapd->radius)
radius_client_flush_auth(hapd->radius, sta->addr);
+ radius_free_class(&sta->radius_class);
#endif /* CONFIG_NO_RADIUS */
#ifndef CONFIG_NO_VLAN
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 942bb3b..c22deac 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -16,6 +16,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha384.h"
+#include "radius/radius.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -337,6 +338,7 @@ struct sta_info {
struct pasn_data *pasn;
#endif /* CONFIG_PASN */
int signal_mgmt;
+ struct radius_class_data radius_class;
};
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index 3c68983..1026472 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -156,7 +156,6 @@ struct eapol_state_machine {
u8 eap_type_authsrv; /* EAP type of the last EAP packet from
* Authentication server */
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
- struct radius_class_data radius_class;
struct wpabuf *radius_cui; /* Chargeable-User-Identity */
struct eap_sm *eap;
--
2.34.1

View File

@@ -0,0 +1,38 @@
From e6ec62aa2d68e9436daeb4470260a101a06c9213 Mon Sep 17 00:00:00 2001
From: Lee Harding <somerandomstring@gmail.com>
Date: Tue, 9 Apr 2024 15:06:38 -0700
Subject: [PATCH] Allow Session-Timeout with PSK RADIUS during 4-way handshake
When the RADIUS response included a Session-Timeout attribute, but is
otherwise valid (an Access-Accept with a valid Tunnel-Password), the
association still failed due to the strict comparison of the accepted
value with HOSTAPD_ACL_ACCEPT. Apparently this combination wasn't
previously tested.
Extend this to allow a packet containing a valid Session-Timeout
attribute to be accepted by extending the "success" comparison to
include HOSTAPD_ACL_ACCEPT_TIMEOUT.
Fixes: 1c3438fec4ba ("RADIUS ACL/PSK check during 4-way handshake")
Signed-off-by: Lee Harding <somerandomstring@gmail.com>
---
src/ap/ieee802_11_auth.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index e723ae74b..98a877dec 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -596,7 +596,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (query->radius_psk) {
struct sta_info *sta;
- bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+ bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
+ cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
sta = ap_get_sta(hapd, query->addr);
if (!sta || !sta->wpa_sm) {
--
2.52.0

View File

@@ -0,0 +1,361 @@
From b48e9bb427e1b85ca9adaed9895c8b3721600ead Mon Sep 17 00:00:00 2001
From: Venkat Chimata <venkat@nearhop.com>
Date: Mon, 2 Feb 2026 14:02:24 +0530
Subject: [PATCH] hostapd: store RADIUS Class per STA instead of EAPOL SM;
preserve Class for ACL/MAC auth and accounting
Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.
This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.
Signed-off-by: Venkat Chimata <venkat@nearhop.com>
---
src/ap/accounting.c | 3 +-
src/ap/ieee802_11.c | 63 ++++++++++++++++++++++++++++
src/ap/ieee802_11.h | 5 +++
src/ap/ieee802_11_auth.c | 4 ++
src/ap/ieee802_1x.c | 71 +-------------------------------
src/ap/ieee802_1x.h | 2 -
src/ap/pmksa_cache_auth.c | 10 ++---
src/ap/sta_info.c | 1 +
src/ap/sta_info.h | 2 +
src/eapol_auth/eapol_auth_sm_i.h | 1 -
10 files changed, 84 insertions(+), 78 deletions(-)
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 9fc1886..99f8ac9 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -15,6 +15,7 @@
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
+#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ap_config.h"
#include "sta_info.h"
@@ -102,7 +103,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
if (sta) {
for (i = 0; ; i++) {
- val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
+ val = radius_get_class(sta, &len,
i);
if (val == NULL)
break;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 615fb32..fc26caf 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -10028,4 +10028,67 @@ void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
}
}
+void radius_store_class(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u8 *attr_class;
+ size_t class_len;
+ int count, i;
+ struct radius_attr_data *nclass;
+ size_t nclass_count;
+
+ if (!hapd->conf->radius->acct_server || !hapd->radius)
+ return;
+
+ radius_free_class(&sta->radius_class);
+ count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+ if (count <= 0)
+ return;
+
+ nclass = os_calloc(count, sizeof(struct radius_attr_data));
+ if (!nclass)
+ return;
+
+ nclass_count = 0;
+
+ attr_class = NULL;
+ for (i = 0; i < count; i++) {
+ do {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+ &attr_class, &class_len,
+ attr_class) < 0) {
+ i = count;
+ break;
+ }
+ } while (class_len < 1);
+
+ nclass[nclass_count].data = os_memdup(attr_class, class_len);
+ if (!nclass[nclass_count].data)
+ break;
+
+ nclass[nclass_count].len = class_len;
+ nclass_count++;
+ }
+
+ sta->radius_class.attr = nclass;
+ sta->radius_class.count = nclass_count;
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
+ (unsigned long) sta->radius_class.count,
+ MAC2STR(sta->addr));
+}
+
+u8* radius_get_class(struct sta_info *sta, size_t *len,
+ int idx)
+{
+ if (!sta || !sta->radius_class.attr ||
+ idx >= (int) sta->radius_class.count)
+ return NULL;
+
+ *len = sta->radius_class.attr[idx].len;
+ return sta->radius_class.attr[idx].data;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 83f4884..f140fe0 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -286,5 +286,10 @@ bool hostapd_is_mld_ap(struct hostapd_data *hapd);
void hostapd_eid_update_cu_info(struct hostapd_data *hapd, u16 *elemid_modified,
const u8 *eid_pos, size_t eid_len,
enum elemid_cu eid_cu);
+void radius_store_class(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg);
+u8* radius_get_class(struct sta_info *sta, size_t *len,
+ int idx);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index d461d2b..9e8d004 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -498,6 +498,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_cached_radius_acl *cache;
struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ struct sta_info *sta;
query = hapd->acl_queries;
prev = NULL;
@@ -537,6 +538,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
info = &cache->info;
+ sta = ap_get_sta(hapd, query->addr);
+
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
@@ -573,6 +576,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (info->identity)
os_memcpy(info->identity, buf, len);
}
+ radius_store_class(hapd, sta, msg);
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 91c537f..4b20278 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1486,7 +1486,7 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
- radius_free_class(&sm->radius_class);
+ radius_free_class(&sta->radius_class);
#endif /* CONFIG_NO_RADIUS */
eapol_auth_free(sm);
@@ -1633,61 +1633,6 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
}
}
-
-static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
- struct sta_info *sta,
- struct radius_msg *msg)
-{
- u8 *attr_class;
- size_t class_len;
- struct eapol_state_machine *sm = sta->eapol_sm;
- int count, i;
- struct radius_attr_data *nclass;
- size_t nclass_count;
-
- if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
- return;
-
- radius_free_class(&sm->radius_class);
- count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
- if (count <= 0)
- return;
-
- nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (!nclass)
- return;
-
- nclass_count = 0;
-
- attr_class = NULL;
- for (i = 0; i < count; i++) {
- do {
- if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
- &attr_class, &class_len,
- attr_class) < 0) {
- i = count;
- break;
- }
- } while (class_len < 1);
-
- nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (!nclass[nclass_count].data)
- break;
-
- nclass[nclass_count].len = class_len;
- nclass_count++;
- }
-
- sm->radius_class.attr = nclass;
- sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG,
- "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
- MACSTR,
- (unsigned long) sm->radius_class.count,
- MAC2STR(sta->addr));
-}
-
-
/* Update sta->identity based on User-Name attribute in Access-Accept */
static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
struct sta_info *sta,
@@ -2146,7 +2091,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
- ieee802_1x_store_radius_class(hapd, sta, msg);
+ radius_store_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
ieee802_1x_update_sta_cui(hapd, sta, msg);
ieee802_1x_check_hs20(hapd, sta, msg,
@@ -2792,18 +2737,6 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
}
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
- int idx)
-{
- if (!sm || !sm->radius_class.attr ||
- idx >= (int) sm->radius_class.count)
- return NULL;
-
- *len = sm->radius_class.attr[idx].len;
- return sm->radius_class.attr[idx].data;
-}
-
-
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
if (!sm)
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 1469351..60af508 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -35,8 +35,6 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *data, int len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
- int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 32d291d..251f668 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -160,7 +160,7 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
entry->cui = wpabuf_dup(eapol->radius_cui);
#ifndef CONFIG_NO_RADIUS
- radius_copy_class(&entry->radius_class, &eapol->radius_class);
+ radius_copy_class(&entry->radius_class, &((struct sta_info *) eapol->sta)->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
@@ -203,12 +203,12 @@ void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
}
#ifndef CONFIG_NO_RADIUS
- radius_free_class(&eapol->radius_class);
- radius_copy_class(&eapol->radius_class, &entry->radius_class);
+ radius_free_class(&((struct sta_info *) eapol->sta)->radius_class);
+ radius_copy_class(&((struct sta_info *) eapol->sta)->radius_class, &entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
- if (eapol->radius_class.attr) {
+ if (((struct sta_info *) eapol->sta)->radius_class.attr) {
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
- "PMKSA", (unsigned long) eapol->radius_class.count);
+ "PMKSA", (unsigned long) ((struct sta_info *) eapol->sta)->radius_class.count);
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 6011980..d46cc1f 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -493,6 +493,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
if (hapd->radius)
radius_client_flush_auth(hapd->radius, sta->addr);
+ radius_free_class(&sta->radius_class);
#endif /* CONFIG_NO_RADIUS */
#ifndef CONFIG_NO_VLAN
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index e3aab48..23d441b 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -17,6 +17,7 @@
#include "common/sae.h"
#include "crypto/sha384.h"
#include "pasn/pasn_common.h"
+#include "radius/radius.h"
#define HOSTAPD_SCS_MAX_SIZE 10
/* STA flags */
@@ -365,6 +366,7 @@ struct sta_info {
struct hostapd_scs_resp *scs_resp;
u8 session_cnt;
#endif
+ struct radius_class_data radius_class;
};
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index a0cef0f..7e1d6bc 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -156,7 +156,6 @@ struct eapol_state_machine {
u8 eap_type_authsrv; /* EAP type of the last EAP packet from
* Authentication server */
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
- struct radius_class_data radius_class;
struct wpabuf *radius_cui; /* Chargeable-User-Identity */
struct eap_sm *eap;
--
2.34.1

View File

@@ -0,0 +1,400 @@
From 22893342533ed81864cf4161bb54001b7eed5366 Mon Sep 17 00:00:00 2001
From: Venkat Chimata <venkat@nearhop.com>
Date: Tue, 17 Mar 2026 11:02:15 +0530
Subject: [PATCH] hostapd / radius / class: store RADIUS Class per STA instead
of EAPOL SM; preserve Class for ACL/MAC auth and accounting
Move storage of RADIUS Class attributes from the EAPOL state machine to
struct sta_info and update all users accordingly. Previously, Class was
kept only in eapol_state_machine->radius_class, which caused Class to be
lost for authentication paths where eapol_sm is not created. As a result,
Accounting messages and PMKSA cache operations could miss the
Class attribute.
This change makes sta_info->radius_class the single source of truth for
RADIUS Class attributes and ensures they are preserved and echoed in
Accounting regardless of whether an EAPOL state machine exists.
Signed-off-by: Venkat Chimata <venkat@nearhop.com>
---
...tore-RADIUS-Class-per-STA-instead-of.patch | 368 ++++++++++++++++++
1 file changed, 368 insertions(+)
create mode 100644 package/network/services/hostapd/patches/zzz-0019-radius-class-store-RADIUS-Class-per-STA-instead-of.patch
diff --git a/package/network/services/hostapd/patches/zzz-0019-radius-class-store-RADIUS-Class-per-STA-instead-of.patch b/package/network/services/hostapd/patches/zzz-0019-radius-class-store-RADIUS-Class-per-STA-instead-of.patch
new file mode 100644
index 0000000000..28524066d8
--- /dev/null
+++ b/package/network/services/hostapd/patches/zzz-0019-radius-class-store-RADIUS-Class-per-STA-instead-of.patch
@@ -0,0 +1,368 @@
+From f554c855229c9078174e18fa0b71161162b7160b Mon Sep 17 00:00:00 2001
+From: Venkat Chimata <venkat@nearhop.com>
+Date: Tue, 17 Mar 2026 10:58:41 +0530
+Subject: [PATCH] radius / class: store RADIUS Class per STA instead of EAPOL
+ SM; preserve Class for ACL/MAC auth and accounting
+
+Move storage of RADIUS Class attributes from the EAPOL state machine to
+struct sta_info and update all users accordingly. Previously, Class was
+kept only in eapol_state_machine->radius_class, which caused Class to be
+lost for authentication paths where eapol_sm is not created. As a result,
+Accounting messages and PMKSA cache operations could miss the
+Class attribute.
+
+This change makes sta_info->radius_class the single source of truth for
+RADIUS Class attributes and ensures they are preserved and echoed in
+Accounting regardless of whether an EAPOL state machine exists.
+
+Signed-off-by: Venkat Chimata <venkat@nearhop.com>
+---
+ src/ap/accounting.c | 3 +-
+ src/ap/ieee802_11.c | 65 ++++++++++++++++++++++++++++++
+ src/ap/ieee802_11.h | 5 +++
+ src/ap/ieee802_11_auth.c | 3 ++
+ src/ap/ieee802_1x.c | 69 +-------------------------------
+ src/ap/ieee802_1x.h | 2 -
+ src/ap/pmksa_cache_auth.c | 10 ++---
+ src/ap/sta_info.c | 2 +
+ src/ap/sta_info.h | 3 +-
+ src/eapol_auth/eapol_auth_sm_i.h | 1 -
+ 10 files changed, 86 insertions(+), 77 deletions(-)
+
+diff --git a/src/ap/accounting.c b/src/ap/accounting.c
+index 9fc1886..99f8ac9 100644
+--- a/src/ap/accounting.c
++++ b/src/ap/accounting.c
+@@ -15,6 +15,7 @@
+ #include "radius/radius.h"
+ #include "radius/radius_client.h"
+ #include "hostapd.h"
++#include "ieee802_11.h"
+ #include "ieee802_1x.h"
+ #include "ap_config.h"
+ #include "sta_info.h"
+@@ -102,7 +103,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
+
+ if (sta) {
+ for (i = 0; ; i++) {
+- val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
++ val = radius_get_class(sta, &len,
+ i);
+ if (val == NULL)
+ break;
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index 8538670..ed5f1fb 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -10,6 +10,7 @@
+
+ #ifndef CONFIG_NATIVE_WINDOWS
+
++#include<stdint.h>
+ #include "utils/common.h"
+ #include "utils/eloop.h"
+ #include "crypto/crypto.h"
+@@ -9001,4 +9002,68 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+ return eid;
+ }
+
++void radius_store_class(struct hostapd_data *hapd,
++ struct sta_info *sta,
++ struct radius_msg *msg)
++{
++ u8 *attr_class;
++ size_t class_len;
++ int count, i;
++ struct radius_attr_data *nclass;
++ size_t nclass_count;
++
++ if (!hapd->conf->radius->acct_server || !hapd->radius)
++ return;
++
++ radius_free_class(&sta->radius_class);
++ count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
++ if (count <= 0)
++ return;
++
++ nclass = os_calloc(count, sizeof(struct radius_attr_data));
++ if (!nclass)
++ return;
++
++ nclass_count = 0;
++
++ attr_class = NULL;
++ for (i = 0; i < count; i++) {
++ do {
++ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
++ &attr_class, &class_len,
++ attr_class) < 0) {
++ i = count;
++ break;
++ }
++ } while (class_len < 1);
++
++ nclass[nclass_count].data = os_memdup(attr_class, class_len);
++ if (!nclass[nclass_count].data)
++ break;
++
++ nclass[nclass_count].len = class_len;
++ nclass_count++;
++ }
++
++ sta->radius_class.attr = nclass;
++ sta->radius_class.count = nclass_count;
++ wpa_printf(MSG_DEBUG,
++ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
++ MACSTR,
++ (unsigned long) sta->radius_class.count,
++ MAC2STR(sta->addr));
++}
++
++u8* radius_get_class(struct sta_info *sta, size_t *len,
++ int idx)
++{
++ if (!sta || !sta->radius_class.attr ||
++ idx >= (int) sta->radius_class.count)
++ return NULL;
++
++ *len = sta->radius_class.attr[idx].len;
++ return sta->radius_class.attr[idx].data;
++}
++
++
+ #endif /* CONFIG_NATIVE_WINDOWS */
+diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
+index 930be67..5d45e21 100644
+--- a/src/ap/ieee802_11.h
++++ b/src/ap/ieee802_11.h
+@@ -324,4 +324,9 @@ void hostapd_link_reconf_resp_tx_status(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok);
+
++void radius_store_class(struct hostapd_data *hapd,
++ struct sta_info *sta,
++ struct radius_msg *msg);
++u8* radius_get_class(struct sta_info *sta, size_t *len, int idx);
++
+ #endif /* IEEE802_11_H */
+diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
+index fa3895a..10fff2e 100644
+--- a/src/ap/ieee802_11_auth.c
++++ b/src/ap/ieee802_11_auth.c
+@@ -500,6 +500,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+ struct hostapd_cached_radius_acl *cache;
+ struct radius_sta *info;
+ struct radius_hdr *hdr = radius_msg_get_hdr(msg);
++ struct sta_info *sta;
+
+ query = hapd->acl_queries;
+ prev = NULL;
+@@ -541,6 +542,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+ os_get_reltime(&cache->timestamp);
+ os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+ info = &cache->info;
++ sta = ap_get_sta(hapd, query->addr);
+ if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+ u8 *buf;
+ size_t len;
+@@ -577,6 +579,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+ if (info->identity)
+ os_memcpy(info->identity, buf, len);
+ }
++ radius_store_class(hapd, sta, msg);
+ if (radius_msg_get_attr_ptr(
+ msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
+index ab20478..73f5e17 100644
+--- a/src/ap/ieee802_1x.c
++++ b/src/ap/ieee802_1x.c
+@@ -1513,7 +1513,7 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
+
+ #ifndef CONFIG_NO_RADIUS
+ radius_msg_free(sm->last_recv_radius);
+- radius_free_class(&sm->radius_class);
++ radius_free_class(&sta->radius_class);
+ #endif /* CONFIG_NO_RADIUS */
+
+ eapol_auth_free(sm);
+@@ -1661,59 +1661,6 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
+ }
+
+
+-static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
+- struct sta_info *sta,
+- struct radius_msg *msg)
+-{
+- u8 *attr_class;
+- size_t class_len;
+- struct eapol_state_machine *sm = sta->eapol_sm;
+- int count, i;
+- struct radius_attr_data *nclass;
+- size_t nclass_count;
+-
+- if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
+- return;
+-
+- radius_free_class(&sm->radius_class);
+- count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+- if (count <= 0)
+- return;
+-
+- nclass = os_calloc(count, sizeof(struct radius_attr_data));
+- if (!nclass)
+- return;
+-
+- nclass_count = 0;
+-
+- attr_class = NULL;
+- for (i = 0; i < count; i++) {
+- do {
+- if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+- &attr_class, &class_len,
+- attr_class) < 0) {
+- i = count;
+- break;
+- }
+- } while (class_len < 1);
+-
+- nclass[nclass_count].data = os_memdup(attr_class, class_len);
+- if (!nclass[nclass_count].data)
+- break;
+-
+- nclass[nclass_count].len = class_len;
+- nclass_count++;
+- }
+-
+- sm->radius_class.attr = nclass;
+- sm->radius_class.count = nclass_count;
+- wpa_printf(MSG_DEBUG,
+- "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+- MACSTR,
+- (unsigned long) sm->radius_class.count,
+- MAC2STR(sta->addr));
+-}
+-
+
+ /* Update sta->identity based on User-Name attribute in Access-Accept */
+ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
+@@ -2134,7 +2081,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
+ override_eapReq = 1;
+ ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
+ shared_secret_len);
+- ieee802_1x_store_radius_class(hapd, sta, msg);
++ radius_store_class(hapd, sta, msg);
+ ieee802_1x_update_sta_identity(hapd, sta, msg);
+ ieee802_1x_update_sta_cui(hapd, sta, msg);
+ ieee802_1x_check_hs20(hapd, sta, msg,
+@@ -2780,18 +2727,6 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
+ }
+
+
+-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+- int idx)
+-{
+- if (!sm || !sm->radius_class.attr ||
+- idx >= (int) sm->radius_class.count)
+- return NULL;
+-
+- *len = sm->radius_class.attr[idx].len;
+- return sm->radius_class.attr[idx].data;
+-}
+-
+-
+ struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+ {
+ if (!sm)
+diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
+index 1469351..60af508 100644
+--- a/src/ap/ieee802_1x.h
++++ b/src/ap/ieee802_1x.h
+@@ -35,8 +35,6 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *data, int len, int ack);
+ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
+-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+- int idx);
+ struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
+ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
+ const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
+diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
+index 0715540..bc8d742 100644
+--- a/src/ap/pmksa_cache_auth.c
++++ b/src/ap/pmksa_cache_auth.c
+@@ -162,7 +162,7 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
+ entry->cui = wpabuf_dup(eapol->radius_cui);
+
+ #ifndef CONFIG_NO_RADIUS
+- radius_copy_class(&entry->radius_class, &eapol->radius_class);
++ radius_copy_class(&entry->radius_class, &((struct sta_info *) eapol->sta)->radius_class);
+ #endif /* CONFIG_NO_RADIUS */
+
+ entry->eap_type_authsrv = eapol->eap_type_authsrv;
+@@ -205,12 +205,12 @@ void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ }
+
+ #ifndef CONFIG_NO_RADIUS
+- radius_free_class(&eapol->radius_class);
+- radius_copy_class(&eapol->radius_class, &entry->radius_class);
++ radius_free_class(&((struct sta_info *) eapol->sta)->radius_class);
++ radius_copy_class(&((struct sta_info *) eapol->sta)->radius_class, &entry->radius_class);
+ #endif /* CONFIG_NO_RADIUS */
+- if (eapol->radius_class.attr) {
++ if (((struct sta_info *) eapol->sta)->radius_class.attr) {
+ wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
+- "PMKSA", (unsigned long) eapol->radius_class.count);
++ "PMKSA", (unsigned long) ((struct sta_info *) eapol->sta)->radius_class.count);
+ }
+
+ eapol->eap_type_authsrv = entry->eap_type_authsrv;
+diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
+index d60d8d3..ee76e6e 100644
+--- a/src/ap/sta_info.c
++++ b/src/ap/sta_info.c
+@@ -361,6 +361,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
+ #ifndef CONFIG_NO_RADIUS
+ if (hapd->radius)
+ radius_client_flush_auth(hapd->radius, sta->addr);
++
++ radius_free_class(&sta->radius_class);
+ #endif /* CONFIG_NO_RADIUS */
+
+ #ifndef CONFIG_NO_VLAN
+diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
+index 7df6eb2..ae76212 100644
+--- a/src/ap/sta_info.h
++++ b/src/ap/sta_info.h
+@@ -18,6 +18,7 @@
+ #include "crypto/sha384.h"
+ #include "pasn/pasn_common.h"
+ #include "hostapd.h"
++#include "radius/radius.h"
+
+ /* STA flags */
+ #define WLAN_STA_AUTH BIT(0)
+@@ -321,7 +322,7 @@ struct sta_info {
+ u8 mld_assoc_link_id;
+ struct link_reconf_req_list *reconf_req;
+ #endif /* CONFIG_IEEE80211BE */
+-
++ struct radius_class_data radius_class;
+ u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
+ * units of 1000 TUs */
+
+diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
+index c970e73..65f1f26 100644
+--- a/src/eapol_auth/eapol_auth_sm_i.h
++++ b/src/eapol_auth/eapol_auth_sm_i.h
+@@ -156,7 +156,6 @@ struct eapol_state_machine {
+ u8 eap_type_authsrv; /* EAP type of the last EAP packet from
+ * Authentication server */
+ u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
+- struct radius_class_data radius_class;
+ struct wpabuf *radius_cui; /* Chargeable-User-Identity */
+
+ struct eap_sm *eap;
+--
+2.34.1
+
--
2.34.1