From 8047a958099516f570eca35dc6f3885a5809633a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 17 Jun 2012 19:30:01 +0300 Subject: RADIUS DAS: Add support for Disconnect-Request Calling-Station-Id, Acct-Session-Id, and User-Name attributes in a Disconnect-Request message can now be used to indicate which station is to be disconnected. Signed-hostap: Jouni Malinen --- src/radius/radius_das.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++--- src/radius/radius_das.h | 17 +++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) (limited to 'src/radius') diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c index d3c144a..61e3518 100644 --- a/src/radius/radius_das.c +++ b/src/radius/radius_das.c @@ -26,6 +26,9 @@ struct radius_das_data { struct hostapd_ip_addr client_addr; unsigned int time_window; int require_event_timestamp; + void *ctx; + enum radius_das_res (*disconnect)(void *ctx, + struct radius_das_attrs *attr); }; @@ -47,6 +50,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das, }; 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); @@ -59,16 +68,63 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das, goto fail; } - /* TODO */ + os_memset(&attrs, 0, sizeof(attrs)); + + 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; + } - goto fail; + res = das->disconnect(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_SUCCESS: + error = 0; + break; + } fail: - reply = radius_msg_new(RADIUS_CODE_DISCONNECT_NAK, hdr->identifier); + reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : + RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); if (reply == NULL) return NULL; - radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error); + if (error) { + radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, + error); + } + return reply; } @@ -240,6 +296,8 @@ radius_das_init(struct radius_das_conf *conf) das->time_window = conf->time_window; das->require_event_timestamp = conf->require_event_timestamp; + das->ctx = conf->ctx; + das->disconnect = conf->disconnect; os_memcpy(&das->client_addr, conf->client_addr, sizeof(das->client_addr)); diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h index c3d501d..d0719ed 100644 --- a/src/radius/radius_das.h +++ b/src/radius/radius_das.h @@ -11,6 +11,20 @@ struct radius_das_data; +enum radius_das_res { + RADIUS_DAS_SUCCESS, + RADIUS_DAS_NAS_MISMATCH, + RADIUS_DAS_SESSION_NOT_FOUND +}; + +struct radius_das_attrs { + const u8 *sta_addr; + const u8 *user_name; + size_t user_name_len; + const u8 *acct_session_id; + size_t acct_session_id_len; +}; + struct radius_das_conf { int port; const u8 *shared_secret; @@ -18,6 +32,9 @@ struct radius_das_conf { const struct hostapd_ip_addr *client_addr; unsigned int time_window; int require_event_timestamp; + void *ctx; + enum radius_das_res (*disconnect)(void *ctx, + struct radius_das_attrs *attr); }; struct radius_das_data * -- cgit v1.1