HS 2.0: CoA-Request processing for Terms and Conditions filtering
Extend RADIUS DAS to support CoA-Request packets for the case where the HS 2.0 Terms And Conditions filtering VSA is used to remove filtering. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
d239ab3962
commit
f456940ef3
7 changed files with 276 additions and 21 deletions
|
@ -49,6 +49,7 @@
|
||||||
#include "rrm.h"
|
#include "rrm.h"
|
||||||
#include "fils_hlp.h"
|
#include "fils_hlp.h"
|
||||||
#include "acs.h"
|
#include "acs.h"
|
||||||
|
#include "hs20.h"
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||||
|
@ -900,6 +901,48 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||||
return RADIUS_DAS_SUCCESS;
|
return RADIUS_DAS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_HS20
|
||||||
|
static enum radius_das_res
|
||||||
|
hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = ctx;
|
||||||
|
struct sta_info *sta;
|
||||||
|
int multi;
|
||||||
|
|
||||||
|
if (hostapd_das_nas_mismatch(hapd, attr))
|
||||||
|
return RADIUS_DAS_NAS_MISMATCH;
|
||||||
|
|
||||||
|
sta = hostapd_das_find_sta(hapd, attr, &multi);
|
||||||
|
if (!sta) {
|
||||||
|
if (multi) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS DAS: Multiple sessions match - not supported");
|
||||||
|
return RADIUS_DAS_MULTI_SESSION_MATCH;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
|
||||||
|
return RADIUS_DAS_SESSION_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
|
||||||
|
" - CoA", MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
if (attr->hs20_t_c_filtering) {
|
||||||
|
if (attr->hs20_t_c_filtering[0] & BIT(0)) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
|
||||||
|
return RADIUS_DAS_COA_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
hs20_t_c_filtering(hapd, sta, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RADIUS_DAS_SUCCESS;
|
||||||
|
}
|
||||||
|
#else /* CONFIG_HS20 */
|
||||||
|
#define hostapd_das_coa NULL
|
||||||
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
#endif /* CONFIG_NO_RADIUS */
|
#endif /* CONFIG_NO_RADIUS */
|
||||||
|
|
||||||
|
|
||||||
|
@ -1074,6 +1117,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||||
conf->radius_das_require_message_authenticator;
|
conf->radius_das_require_message_authenticator;
|
||||||
das_conf.ctx = hapd;
|
das_conf.ctx = hapd;
|
||||||
das_conf.disconnect = hostapd_das_disconnect;
|
das_conf.disconnect = hostapd_das_disconnect;
|
||||||
|
das_conf.coa = hostapd_das_coa;
|
||||||
hapd->radius_das = radius_das_init(&das_conf);
|
hapd->radius_das = radius_das_init(&das_conf);
|
||||||
if (hapd->radius_das == NULL) {
|
if (hapd->radius_das == NULL) {
|
||||||
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
|
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
|
#include "common/wpa_ctrl.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ap_config.h"
|
#include "ap_config.h"
|
||||||
#include "ap_drv_ops.h"
|
#include "ap_drv_ops.h"
|
||||||
|
#include "sta_info.h"
|
||||||
#include "hs20.h"
|
#include "hs20.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,3 +220,26 @@ int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int enabled)
|
||||||
|
{
|
||||||
|
if (enabled) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"HS 2.0: Terms and Conditions filtering required for "
|
||||||
|
MACSTR, MAC2STR(sta->addr));
|
||||||
|
sta->hs20_t_c_filtering = 1;
|
||||||
|
/* TODO: Enable firewall filtering for the STA */
|
||||||
|
wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"HS 2.0: Terms and Conditions filtering not required for "
|
||||||
|
MACSTR, MAC2STR(sta->addr));
|
||||||
|
sta->hs20_t_c_filtering = 0;
|
||||||
|
/* TODO: Disable firewall filtering for the STA */
|
||||||
|
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||||
|
HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,5 +20,7 @@ int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
|
||||||
const struct wpabuf *payload);
|
const struct wpabuf *payload);
|
||||||
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||||
const u8 *addr);
|
const u8 *addr);
|
||||||
|
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int enabled);
|
||||||
|
|
||||||
#endif /* HS20_H */
|
#endif /* HS20_H */
|
||||||
|
|
|
@ -1632,14 +1632,7 @@ static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
|
"HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
|
||||||
pos[0], pos[1], pos[2], pos[3]);
|
pos[0], pos[1], pos[2], pos[3]);
|
||||||
if (pos[0] & BIT(0)) {
|
hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
|
||||||
wpa_printf(MSG_DEBUG,
|
|
||||||
"HS 2.0: Terms and Conditions filtering required");
|
|
||||||
sta->hs20_t_c_filtering = 1;
|
|
||||||
/* TODO: Enable firewall filtering for the STA */
|
|
||||||
} else {
|
|
||||||
sta->hs20_t_c_filtering = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
|
@ -298,6 +298,9 @@ extern "C" {
|
||||||
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
|
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
|
||||||
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
|
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
|
||||||
|
|
||||||
|
#define HS20_T_C_FILTERING_ADD "HS20-T-C-FILTERING-ADD "
|
||||||
|
#define HS20_T_C_FILTERING_REMOVE "HS20-T-C-FILTERING-REMOVE "
|
||||||
|
|
||||||
#define AP_EVENT_ENABLED "AP-ENABLED "
|
#define AP_EVENT_ENABLED "AP-ENABLED "
|
||||||
#define AP_EVENT_DISABLED "AP-DISABLED "
|
#define AP_EVENT_DISABLED "AP-DISABLED "
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct radius_das_data {
|
||||||
void *ctx;
|
void *ctx;
|
||||||
enum radius_das_res (*disconnect)(void *ctx,
|
enum radius_das_res (*disconnect)(void *ctx,
|
||||||
struct radius_das_attrs *attr);
|
struct radius_das_attrs *attr);
|
||||||
|
enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,6 +162,10 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
|
||||||
abuf, from_port);
|
abuf, from_port);
|
||||||
error = 508;
|
error = 508;
|
||||||
break;
|
break;
|
||||||
|
case RADIUS_DAS_COA_FAILED:
|
||||||
|
/* not used with Disconnect-Request */
|
||||||
|
error = 405;
|
||||||
|
break;
|
||||||
case RADIUS_DAS_SUCCESS:
|
case RADIUS_DAS_SUCCESS:
|
||||||
error = 0;
|
error = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -184,6 +189,195 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct radius_msg * radius_das_coa(struct radius_das_data *das,
|
||||||
|
struct radius_msg *msg,
|
||||||
|
const char *abuf, int from_port)
|
||||||
|
{
|
||||||
|
struct radius_hdr *hdr;
|
||||||
|
struct radius_msg *reply;
|
||||||
|
u8 allowed[] = {
|
||||||
|
RADIUS_ATTR_USER_NAME,
|
||||||
|
RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||||
|
RADIUS_ATTR_CALLING_STATION_ID,
|
||||||
|
RADIUS_ATTR_NAS_IDENTIFIER,
|
||||||
|
RADIUS_ATTR_ACCT_SESSION_ID,
|
||||||
|
RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
|
||||||
|
RADIUS_ATTR_EVENT_TIMESTAMP,
|
||||||
|
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
|
||||||
|
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
|
||||||
|
#ifdef CONFIG_HS20
|
||||||
|
RADIUS_ATTR_VENDOR_SPECIFIC,
|
||||||
|
#endif /* CONFIG_HS20 */
|
||||||
|
#ifdef CONFIG_IPV6
|
||||||
|
RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
int error = 405;
|
||||||
|
u8 attr;
|
||||||
|
enum radius_das_res res;
|
||||||
|
struct radius_das_attrs attrs;
|
||||||
|
u8 *buf;
|
||||||
|
size_t len;
|
||||||
|
char tmp[100];
|
||||||
|
u8 sta_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
hdr = radius_msg_get_hdr(msg);
|
||||||
|
|
||||||
|
if (!das->coa) {
|
||||||
|
wpa_printf(MSG_INFO, "DAS: CoA not supported");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = radius_msg_find_unlisted_attr(msg, allowed);
|
||||||
|
if (attr) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"DAS: Unsupported attribute %u in CoA-Request from %s:%d",
|
||||||
|
attr, abuf, from_port);
|
||||||
|
error = 401;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&attrs, 0, sizeof(attrs));
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
if (len != 4) {
|
||||||
|
wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 407;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
attrs.nas_ip_addr = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
if (len != 16) {
|
||||||
|
wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 407;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
attrs.nas_ipv6_addr = buf;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
attrs.nas_identifier = buf;
|
||||||
|
attrs.nas_identifier_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
if (len >= sizeof(tmp))
|
||||||
|
len = sizeof(tmp) - 1;
|
||||||
|
os_memcpy(tmp, buf, len);
|
||||||
|
tmp[len] = '\0';
|
||||||
|
if (hwaddr_aton2(tmp, sta_addr) < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
|
||||||
|
"'%s' from %s:%d", tmp, abuf, from_port);
|
||||||
|
error = 407;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
attrs.sta_addr = sta_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
attrs.user_name = buf;
|
||||||
|
attrs.user_name_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
attrs.acct_session_id = buf;
|
||||||
|
attrs.acct_session_id_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
attrs.acct_multi_session_id = buf;
|
||||||
|
attrs.acct_multi_session_id_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
attrs.cui = buf;
|
||||||
|
attrs.cui_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HS20
|
||||||
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
|
||||||
|
&buf, &len, NULL) == 0) {
|
||||||
|
if (len < 10 || WPA_GET_BE32(buf) != RADIUS_VENDOR_ID_WFA ||
|
||||||
|
buf[4] != RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING ||
|
||||||
|
buf[5] < 6) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"DAS: Unsupported attribute %u in CoA-Request from %s:%d",
|
||||||
|
attr, abuf, from_port);
|
||||||
|
error = 401;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
attrs.hs20_t_c_filtering = &buf[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!attrs.hs20_t_c_filtering) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"DAS: No supported authorization change attribute in CoA-Request from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 402;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
|
res = das->coa(das->ctx, &attrs);
|
||||||
|
switch (res) {
|
||||||
|
case RADIUS_DAS_NAS_MISMATCH:
|
||||||
|
wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 403;
|
||||||
|
break;
|
||||||
|
case RADIUS_DAS_SESSION_NOT_FOUND:
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"DAS: Session not found for request from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 503;
|
||||||
|
break;
|
||||||
|
case RADIUS_DAS_MULTI_SESSION_MATCH:
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"DAS: Multiple sessions match for request from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 508;
|
||||||
|
break;
|
||||||
|
case RADIUS_DAS_COA_FAILED:
|
||||||
|
wpa_printf(MSG_INFO, "DAS: CoA failed for request from %s:%d",
|
||||||
|
abuf, from_port);
|
||||||
|
error = 407;
|
||||||
|
break;
|
||||||
|
case RADIUS_DAS_SUCCESS:
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
reply = radius_msg_new(error ? RADIUS_CODE_COA_NAK :
|
||||||
|
RADIUS_CODE_COA_ACK, hdr->identifier);
|
||||||
|
if (!reply)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (error &&
|
||||||
|
!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) {
|
||||||
|
radius_msg_free(reply);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
{
|
{
|
||||||
struct radius_das_data *das = eloop_ctx;
|
struct radius_das_data *das = eloop_ctx;
|
||||||
|
@ -270,19 +464,7 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
reply = radius_das_disconnect(das, msg, abuf, from_port);
|
reply = radius_das_disconnect(das, msg, abuf, from_port);
|
||||||
break;
|
break;
|
||||||
case RADIUS_CODE_COA_REQUEST:
|
case RADIUS_CODE_COA_REQUEST:
|
||||||
/* TODO */
|
reply = radius_das_coa(das, msg, abuf, from_port);
|
||||||
reply = radius_msg_new(RADIUS_CODE_COA_NAK,
|
|
||||||
hdr->identifier);
|
|
||||||
if (reply == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Unsupported Service */
|
|
||||||
if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
|
|
||||||
405)) {
|
|
||||||
radius_msg_free(reply);
|
|
||||||
reply = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
|
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
|
||||||
|
@ -369,6 +551,7 @@ radius_das_init(struct radius_das_conf *conf)
|
||||||
conf->require_message_authenticator;
|
conf->require_message_authenticator;
|
||||||
das->ctx = conf->ctx;
|
das->ctx = conf->ctx;
|
||||||
das->disconnect = conf->disconnect;
|
das->disconnect = conf->disconnect;
|
||||||
|
das->coa = conf->coa;
|
||||||
|
|
||||||
os_memcpy(&das->client_addr, conf->client_addr,
|
os_memcpy(&das->client_addr, conf->client_addr,
|
||||||
sizeof(das->client_addr));
|
sizeof(das->client_addr));
|
||||||
|
|
|
@ -16,6 +16,7 @@ enum radius_das_res {
|
||||||
RADIUS_DAS_NAS_MISMATCH,
|
RADIUS_DAS_NAS_MISMATCH,
|
||||||
RADIUS_DAS_SESSION_NOT_FOUND,
|
RADIUS_DAS_SESSION_NOT_FOUND,
|
||||||
RADIUS_DAS_MULTI_SESSION_MATCH,
|
RADIUS_DAS_MULTI_SESSION_MATCH,
|
||||||
|
RADIUS_DAS_COA_FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radius_das_attrs {
|
struct radius_das_attrs {
|
||||||
|
@ -35,6 +36,9 @@ struct radius_das_attrs {
|
||||||
size_t acct_multi_session_id_len;
|
size_t acct_multi_session_id_len;
|
||||||
const u8 *cui;
|
const u8 *cui;
|
||||||
size_t cui_len;
|
size_t cui_len;
|
||||||
|
|
||||||
|
/* Authorization changes */
|
||||||
|
const u8 *hs20_t_c_filtering;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radius_das_conf {
|
struct radius_das_conf {
|
||||||
|
@ -48,6 +52,7 @@ struct radius_das_conf {
|
||||||
void *ctx;
|
void *ctx;
|
||||||
enum radius_das_res (*disconnect)(void *ctx,
|
enum radius_das_res (*disconnect)(void *ctx,
|
||||||
struct radius_das_attrs *attr);
|
struct radius_das_attrs *attr);
|
||||||
|
enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radius_das_data *
|
struct radius_das_data *
|
||||||
|
|
Loading…
Reference in a new issue