Cumulative patch from commit b3253ebb73d6d52ac636c5cc6d958955a5a98fca
b3253eb wpa_supplicant: Complete radio works on disable event
38ecb06 Convert RADIUS debug dumps to use wpa_printf()
a0ac572 EAP-SIM DB: Remove client socket file on connect() error
a1dd890 RADIUS: Add minimal accounting server support
22dd2d7 Fix MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding
9aab811 Fix nt_password_hash build
a9b08ad Remove unused crypto_bignum_rshift()
2dff9e8 Remove unused NFC_RX_HANDOVER_REQ
be24917 nl80211: Use nl80211_set_iface_id() to get hw features data
8a45811 hostapd: Add Operating Mode Notification support
d9dd86b Enable IEEE 802.11w in defconfig
Change-Id: I6bf13cd0b7e3cb3c3550b87a77a035340e9d0a6b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b4860a0..4631ca9 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -311,6 +311,7 @@
char *radius_server_clients;
int radius_server_auth_port;
+ int radius_server_acct_port;
int radius_server_ipv6;
char *test_socket; /* UNIX domain socket path for driver_test */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 893e6d9..e998fc6 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -346,7 +346,7 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo)
+ u32 flags, u8 qosinfo, u8 vht_opmode)
{
struct hostapd_sta_add_params params;
@@ -364,6 +364,8 @@
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
+ params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
+ params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 15a4b26..9edaf7d 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -40,7 +40,7 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo);
+ u32 flags, u8 qosinfo, u8 vht_opmode);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 8bb58a6..7183aba 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -92,6 +92,7 @@
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
+ srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c755265..9251ac3 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -895,6 +895,11 @@
elems.vht_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+
+ resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
!(sta->flags & WLAN_STA_VHT)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1937,7 +1942,7 @@
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
- sta->flags, sta->qosinfo)) {
+ sta->flags, sta->qosinfo, sta->vht_opmode)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"Could not add STA to kernel driver");
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 566a65a..809b4ca 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -61,6 +61,8 @@
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f2ab182..221d9c2 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -108,6 +108,35 @@
return WLAN_STATUS_SUCCESS;
}
+
+u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper_notif)
+{
+ u8 channel_width;
+
+ if (!vht_oper_notif) {
+ sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
+
+ if (channel_width != VHT_CHANWIDTH_USE_HT &&
+ channel_width != VHT_CHANWIDTH_80MHZ &&
+ channel_width != VHT_CHANWIDTH_160MHZ &&
+ channel_width != VHT_CHANWIDTH_80P80MHZ &&
+ ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >>
+ VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) {
+ sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
+ sta->vht_opmode = *vht_oper_notif;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap)
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9b77e06..240b926 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -27,6 +27,7 @@
#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
+#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -103,6 +104,7 @@
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 809089f..50bdc01 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -252,6 +252,11 @@
elems->vht_operation = pos;
elems->vht_operation_len = elen;
break;
+ case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+ if (elen != 1)
+ break;
+ elems->vht_opmode_notif = pos;
+ break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index b84dd9e..4fb2e84 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -30,6 +30,7 @@
const u8 *ht_operation;
const u8 *vht_capabilities;
const u8 *vht_operation;
+ const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
const u8 *p2p;
const u8 *wfd;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 6f7f777..0e39caf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -764,6 +764,13 @@
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
+#define VHT_OPMODE_CHANNEL_WIDTH_MASK ((u8) BIT(0) | BIT(1))
+#define VHT_OPMODE_CHANNEL_RxNSS_MASK ((u8) BIT(4) | BIT(5) | \
+ BIT(6))
+#define VHT_OPMODE_NOTIF_RX_NSS_SHIFT 4
+
+#define VHT_RX_NSS_MAX_STREAMS 8
+
/* VHT channel widths */
#define VHT_CHANWIDTH_USE_HT 0
#define VHT_CHANWIDTH_80MHZ 1
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 9bccaaa..4caa277 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -534,16 +534,6 @@
struct crypto_bignum *d);
/**
- * crypto_bignum_rshift - b = a >> n
- * @a: Bignum
- * @n: Number of bits to shift
- * @b: Bignum; used to store the result of a >> n
- * Returns: 0 on success, -1 on failure
- */
-int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
- struct crypto_bignum *b);
-
-/**
* crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
* @a: Bignum
* @b: Bignum
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 1da2b9f..817ee2d 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -916,13 +916,6 @@
}
-int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
- struct crypto_bignum *b)
-{
- return BN_rshift((BIGNUM *) b, (const BIGNUM *) a, n) ? 0 : -1;
-}
-
-
int crypto_bignum_inverse(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index b2bbab2..49a5c1c 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -58,6 +58,7 @@
WPA_PUT_LE16(ucs2_buffer + j,
((c & 0xF) << 12) |
((c2 & 0x3F) << 6) | (c3 & 0x3F));
+ j += 2;
}
}
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d4136d7..632ae3a 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1028,6 +1028,8 @@
u16 listen_interval;
const struct ieee80211_ht_capabilities *ht_capabilities;
const struct ieee80211_vht_capabilities *vht_capabilities;
+ int vht_opmode_enabled;
+ u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index f4bb31c..32a371d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6723,7 +6723,8 @@
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (nl80211_set_iface_id(msg, bss) < 0)
+ goto nla_put_failure;
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
nl80211_set_regulatory_flags(drv, &result);
@@ -7351,6 +7352,12 @@
params->vht_capabilities);
}
+ if (params->vht_opmode_enabled) {
+ wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
+ NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF,
+ params->vht_opmode);
+ }
+
wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index 45660ed..bc2cbe5 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -639,6 +639,11 @@
"/tmp/eap_sim_db_%d-%d", getpid(), counter++);
os_free(data->local_sock);
data->local_sock = os_strdup(addr.sun_path);
+ if (data->local_sock == NULL) {
+ close(data->sock);
+ data->sock = -1;
+ return -1;
+ }
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
close(data->sock);
@@ -657,6 +662,9 @@
os_strlen(addr.sun_path));
close(data->sock);
data->sock = -1;
+ unlink(data->local_sock);
+ os_free(data->local_sock);
+ data->local_sock = NULL;
return -1;
}
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 494f92d..1070fc7 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -249,25 +249,17 @@
}
-static void print_char(char c)
-{
- if (c >= 32 && c < 127)
- printf("%c", c);
- else
- printf("<%02x>", c);
-}
-
-
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
struct radius_attr_type *attr;
- int i, len;
+ int len;
unsigned char *pos;
+ char buf[1000];
attr = radius_get_attr_type(hdr->type);
- printf(" Attribute %d (%s) length=%d\n",
- hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+ wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
+ hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
return;
@@ -277,47 +269,50 @@
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
- printf(" Value: '");
- for (i = 0; i < len; i++)
- print_char(pos[i]);
- printf("'\n");
+ printf_encode(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: '%s'", buf);
break;
case RADIUS_ATTR_IP:
if (len == 4) {
struct in_addr addr;
os_memcpy(&addr, pos, 4);
- printf(" Value: %s\n", inet_ntoa(addr));
- } else
- printf(" Invalid IP address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ inet_ntoa(addr));
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IP address length %d",
+ len);
+ }
break;
#ifdef CONFIG_IPV6
case RADIUS_ATTR_IPV6:
if (len == 16) {
- char buf[128];
const char *atxt;
struct in6_addr *addr = (struct in6_addr *) pos;
atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
- printf(" Value: %s\n", atxt ? atxt : "?");
- } else
- printf(" Invalid IPv6 address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ atxt ? atxt : "?");
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IPv6 address length %d",
+ len);
+ }
break;
#endif /* CONFIG_IPV6 */
case RADIUS_ATTR_HEXDUMP:
case RADIUS_ATTR_UNDIST:
- printf(" Value:");
- for (i = 0; i < len; i++)
- printf(" %02x", pos[i]);
- printf("\n");
+ wpa_snprintf_hex(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: %s", buf);
break;
case RADIUS_ATTR_INT32:
if (len == 4)
- printf(" Value: %u\n", WPA_GET_BE32(pos));
+ wpa_printf(MSG_INFO, " Value: %u",
+ WPA_GET_BE32(pos));
else
- printf(" Invalid INT32 length %d\n", len);
+ wpa_printf(MSG_INFO, " Invalid INT32 length %d",
+ len);
break;
default:
@@ -330,9 +325,9 @@
{
size_t i;
- printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
- msg->hdr->code, radius_code_string(msg->hdr->code),
- msg->hdr->identifier, be_to_host16(msg->hdr->length));
+ wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
+ msg->hdr->code, radius_code_string(msg->hdr->code),
+ msg->hdr->identifier, be_to_host16(msg->hdr->length));
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -384,7 +379,7 @@
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
if (attr == NULL) {
- printf("WARNING: Could not add Message-Authenticator\n");
+ wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
return -1;
}
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
@@ -473,6 +468,27 @@
}
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+ os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
+ addr[0] = wpabuf_head(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
+ addr[1] = secret;
+ len[1] = secret_len;
+ md5_vector(2, addr, len, msg->hdr->authenticator);
+
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
+ }
+}
+
+
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
@@ -585,7 +601,7 @@
struct radius_attr_hdr *attr;
if (data_len > RADIUS_MAX_ATTR_LEN) {
- printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+ wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
(unsigned long) data_len);
return NULL;
}
@@ -756,8 +772,7 @@
tmp = radius_get_attr_hdr(msg, i);
if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
if (attr != NULL) {
- printf("Multiple Message-Authenticator "
- "attributes in RADIUS message\n");
+ wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
return 1;
}
attr = tmp;
@@ -765,7 +780,7 @@
}
if (attr == NULL) {
- printf("No Message-Authenticator attribute found\n");
+ wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
return 1;
}
@@ -786,7 +801,7 @@
}
if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
- printf("Invalid Message-Authenticator!\n");
+ wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
return 1;
}
@@ -802,7 +817,7 @@
u8 hash[MD5_MAC_LEN];
if (sent_msg == NULL) {
- printf("No matching Access-Request message found\n");
+ wpa_printf(MSG_INFO, "No matching Access-Request message found");
return 1;
}
@@ -823,7 +838,7 @@
len[3] = secret_len;
md5_vector(4, addr, len, hash);
if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
- printf("Response Authenticator invalid!\n");
+ wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -962,7 +977,8 @@
pos = key + 2;
left = len - 2;
if (left % 16) {
- printf("Invalid ms key len %lu\n", (unsigned long) left);
+ wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+ (unsigned long) left);
return NULL;
}
@@ -996,7 +1012,7 @@
}
if (plain[0] == 0 || plain[0] > plen - 1) {
- printf("Failed to decrypt MPPE key\n");
+ wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
os_free(plain);
return NULL;
}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2031054..ad65b04 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -204,6 +204,9 @@
const struct radius_hdr *req_hdr);
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const u8 *req_authenticator);
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 1063d65..2904b2f 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -49,6 +49,13 @@
u32 bad_authenticators;
u32 packets_dropped;
u32 unknown_types;
+
+ u32 acct_requests;
+ u32 invalid_acct_requests;
+ u32 acct_responses;
+ u32 malformed_acct_requests;
+ u32 acct_bad_authenticators;
+ u32 unknown_acct_types;
};
/**
@@ -99,6 +106,11 @@
int auth_sock;
/**
+ * acct_sock - Socket for RADIUS accounting messages
+ */
+ int acct_sock;
+
+ /**
* clients - List of authorized RADIUS clients
*/
struct radius_client *clients;
@@ -979,6 +991,140 @@
}
+static void radius_server_receive_acct(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct radius_server_data *data = eloop_ctx;
+ u8 *buf = NULL;
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ socklen_t fromlen;
+ int len, res;
+ struct radius_client *client = NULL;
+ struct radius_msg *msg = NULL, *resp = NULL;
+ char abuf[50];
+ int from_port = 0;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
+
+ buf = os_malloc(RADIUS_MAX_MSG_LEN);
+ if (buf == NULL) {
+ goto fail;
+ }
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+#ifdef CONFIG_IPV6
+ if (data->ipv6) {
+ if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+ sizeof(abuf)) == NULL)
+ abuf[0] = '\0';
+ from_port = ntohs(from.sin6.sin6_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data,
+ (struct in_addr *)
+ &from.sin6.sin6_addr, 1);
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (!data->ipv6) {
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data, &from.sin.sin_addr, 0);
+ }
+
+ RADIUS_DUMP("Received data", buf, len);
+
+ if (client == NULL) {
+ RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+ data->counters.invalid_acct_requests++;
+ goto fail;
+ }
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+ data->counters.malformed_acct_requests++;
+ client->counters.malformed_acct_requests++;
+ goto fail;
+ }
+
+ os_free(buf);
+ buf = NULL;
+
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(msg);
+ }
+
+ if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
+ RADIUS_DEBUG("Unexpected RADIUS code %d",
+ radius_msg_get_hdr(msg)->code);
+ data->counters.unknown_acct_types++;
+ client->counters.unknown_acct_types++;
+ goto fail;
+ }
+
+ data->counters.acct_requests++;
+ client->counters.acct_requests++;
+
+ if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len)) {
+ RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
+ data->counters.acct_bad_authenticators++;
+ client->counters.acct_bad_authenticators++;
+ goto fail;
+ }
+
+ /* TODO: Write accounting information to a file or database */
+
+ hdr = radius_msg_get_hdr(msg);
+
+ resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
+ if (resp == NULL)
+ goto fail;
+
+ radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ hdr->authenticator);
+
+ RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(resp);
+ }
+ rbuf = radius_msg_get_buf(resp);
+ data->counters.acct_responses++;
+ client->counters.acct_responses++;
+ res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
+ (struct sockaddr *) &from.ss, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
+ }
+
+fail:
+ radius_msg_free(resp);
+ radius_msg_free(msg);
+ os_free(buf);
+}
+
+
static int radius_server_disable_pmtu_discovery(int s)
{
int r = -1;
@@ -1329,6 +1475,29 @@
return NULL;
}
+ if (conf->acct_port) {
+#ifdef CONFIG_IPV6
+ if (conf->ipv6)
+ data->acct_sock = radius_server_open_socket6(
+ conf->acct_port);
+ else
+#endif /* CONFIG_IPV6 */
+ data->acct_sock = radius_server_open_socket(conf->acct_port);
+ if (data->acct_sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
+ radius_server_deinit(data);
+ return NULL;
+ }
+ if (eloop_register_read_sock(data->acct_sock,
+ radius_server_receive_acct,
+ data, NULL)) {
+ radius_server_deinit(data);
+ return NULL;
+ }
+ } else {
+ data->acct_sock = -1;
+ }
+
return data;
}
@@ -1347,6 +1516,11 @@
close(data->auth_sock);
}
+ if (data->acct_sock >= 0) {
+ eloop_unregister_read_sock(data->acct_sock);
+ close(data->acct_sock);
+ }
+
radius_server_free_clients(data, data->clients);
os_free(data->pac_opaque_encr_key);
@@ -1410,7 +1584,13 @@
"radiusAuthServTotalMalformedAccessRequests=%u\n"
"radiusAuthServTotalBadAuthenticators=%u\n"
"radiusAuthServTotalPacketsDropped=%u\n"
- "radiusAuthServTotalUnknownTypes=%u\n",
+ "radiusAuthServTotalUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
data->counters.access_requests,
data->counters.invalid_requests,
data->counters.dup_access_requests,
@@ -1420,7 +1600,13 @@
data->counters.malformed_access_requests,
data->counters.bad_authenticators,
data->counters.packets_dropped,
- data->counters.unknown_types);
+ data->counters.unknown_types,
+ data->counters.acct_requests,
+ data->counters.invalid_acct_requests,
+ data->counters.acct_responses,
+ data->counters.malformed_acct_requests,
+ data->counters.acct_bad_authenticators,
+ data->counters.unknown_acct_types);
if (ret < 0 || ret >= end - pos) {
*pos = '\0';
return pos - buf;
@@ -1455,7 +1641,13 @@
"radiusAuthServMalformedAccessRequests=%u\n"
"radiusAuthServBadAuthenticators=%u\n"
"radiusAuthServPacketsDropped=%u\n"
- "radiusAuthServUnknownTypes=%u\n",
+ "radiusAuthServUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
idx,
abuf, mbuf,
cli->counters.access_requests,
@@ -1466,7 +1658,13 @@
cli->counters.malformed_access_requests,
cli->counters.bad_authenticators,
cli->counters.packets_dropped,
- cli->counters.unknown_types);
+ cli->counters.unknown_types,
+ cli->counters.acct_requests,
+ cli->counters.invalid_acct_requests,
+ cli->counters.acct_responses,
+ cli->counters.malformed_acct_requests,
+ cli->counters.acct_bad_authenticators,
+ cli->counters.unknown_acct_types);
if (ret < 0 || ret >= end - pos) {
*pos = '\0';
return pos - buf;
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 284bd59..78f5fc2 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -22,6 +22,11 @@
int auth_port;
/**
+ * acct_port - UDP port to listen to as an accounting server
+ */
+ int acct_port;
+
+ /**
* client_file - RADIUS client configuration file
*
* This file contains the RADIUS clients and the shared secret to be