wpa_supplicant: Update to 07-Jul-2012 TOT
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date: Sat Jul 7 13:01:45 2012 +0300
WPS SSDP: Fix socket leaks on error paths
Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 2a04560..2c3a6d9 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -1,6 +1,6 @@
/*
* hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -39,6 +39,8 @@
u8 *val;
size_t len;
int i;
+ struct wpabuf *b;
+ struct hostapd_radius_attr *attr;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -67,7 +69,9 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_ACCT_AUTHENTIC) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
@@ -91,7 +95,9 @@
}
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
@@ -99,7 +105,9 @@
}
#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
@@ -107,7 +115,9 @@
}
#endif /* CONFIG_IPV6 */
- if (hapd->conf->nas_identifier &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_IDENTIFIER) &&
+ hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
@@ -115,7 +125,9 @@
goto fail;
}
- if (sta &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ sta &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
@@ -123,7 +135,9 @@
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_CALLED_STATION_ID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
@@ -138,7 +152,10 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(
+ if (!hostapd_config_get_radius_attr(
+ hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(
msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
@@ -149,7 +166,10 @@
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ if (!hostapd_config_get_radius_attr(
+ hapd->conf->radius_acct_req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
@@ -167,6 +187,26 @@
goto fail;
}
}
+
+ b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (b &&
+ !radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ wpabuf_head(b), wpabuf_len(b))) {
+ wpa_printf(MSG_ERROR, "Could not add CUI");
+ goto fail;
+ }
+ }
+
+ for (attr = hapd->conf->radius_acct_req_attr; attr; attr = attr->next)
+ {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ goto fail;
+ }
}
return msg;
@@ -259,8 +299,9 @@
hapd, sta);
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
- if (msg)
- radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
+ if (msg &&
+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+ radius_msg_free(msg);
sta->acct_session_started = 1;
}
@@ -358,9 +399,10 @@
goto fail;
}
- radius_client_send(hapd->radius, msg,
- stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
- sta->addr);
+ if (radius_client_send(hapd->radius, msg,
+ stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+ sta->addr) < 0)
+ goto fail;
return;
fail:
@@ -463,7 +505,8 @@
return;
}
- radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+ if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+ radius_msg_free(msg);
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index b9f5994..811ffc1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -87,6 +87,8 @@
#ifdef CONFIG_IEEE80211R
bss->ft_over_ds = 1;
#endif /* CONFIG_IEEE80211R */
+
+ bss->radius_das_time_window = 300;
}
@@ -336,6 +338,30 @@
}
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+ for (; attr; attr = attr->next) {
+ if (attr->type == type)
+ return attr;
+ }
+ return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+ struct hostapd_radius_attr *prev;
+
+ while (attr) {
+ prev = attr;
+ attr = attr->next;
+ wpabuf_free(prev->val);
+ os_free(prev);
+ }
+}
+
+
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
os_free(user->identity);
@@ -392,6 +418,8 @@
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
+ hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+ hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
@@ -406,6 +434,7 @@
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
os_free(conf->radius);
+ os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
if (conf->ssid.dyn_vlan_keys) {
struct hostapd_ssid *ssid = &conf->ssid;
@@ -465,9 +494,13 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
+ wpabuf_free(conf->wps_nfc_dh_pubkey);
+ wpabuf_free(conf->wps_nfc_dh_privkey);
+ wpabuf_free(conf->wps_nfc_dev_pw);
#endif /* CONFIG_WPS */
os_free(conf->roaming_consortium);
+ os_free(conf->venue_name);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2ec25ad..13d5549 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -116,6 +116,12 @@
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
+struct hostapd_radius_attr {
+ u8 type;
+ struct wpabuf *val;
+ struct hostapd_radius_attr *next;
+};
+
#define NUM_TX_QUEUES 4
@@ -142,6 +148,12 @@
u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
};
+struct hostapd_venue_name {
+ u8 lang[3];
+ u8 name_len;
+ u8 name[252];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -171,6 +183,15 @@
char *nas_identifier;
struct hostapd_radius_servers *radius;
int acct_interim_interval;
+ int radius_request_cui;
+ struct hostapd_radius_attr *radius_auth_req_attr;
+ struct hostapd_radius_attr *radius_acct_req_attr;
+ int radius_das_port;
+ unsigned int radius_das_time_window;
+ int radius_das_require_event_timestamp;
+ struct hostapd_ip_addr radius_das_client_addr;
+ u8 *radius_das_shared_secret;
+ size_t radius_das_shared_secret_len;
struct hostapd_ssid ssid;
@@ -326,6 +347,10 @@
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int wps_nfc_dev_pw_id;
+ struct wpabuf *wps_nfc_dh_pubkey;
+ struct wpabuf *wps_nfc_dh_privkey;
+ struct wpabuf *wps_nfc_dev_pw;
#endif /* CONFIG_WPS */
int pbc_in_m1;
@@ -343,6 +368,7 @@
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
+ int disable_11ac;
/* IEEE 802.11v */
int time_advertisement;
@@ -364,6 +390,13 @@
unsigned int roaming_consortium_count;
struct hostapd_roaming_consortium *roaming_consortium;
+ /* IEEE 802.11u - Venue Name duples */
+ unsigned int venue_name_count;
+ struct hostapd_venue_name *venue_name;
+
+ u16 gas_comeback_delay;
+ int gas_frag_limit;
+
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
#ifdef CONFIG_RADIUS_TEST
@@ -423,6 +456,9 @@
int ieee80211n;
int secondary_channel;
int require_ht;
+ u32 vht_capab;
+ int ieee80211ac;
+ u8 vht_oper_chwidth;
};
@@ -444,5 +480,7 @@
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index d07cc6b..859b529 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -584,3 +584,15 @@
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
+
+
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *data,
+ size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+ return 0;
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, hapd->own_addr, data,
+ len, 0);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 8038fa2..169c91b 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -86,6 +86,9 @@
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason);
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *data,
+ size_t len);
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index b4252cf..933b158 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -289,10 +289,8 @@
ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
- if (fi) {
- ap->ssi_signal = fi->ssi_signal;
+ if (fi)
ap->datarate = fi->datarate;
- }
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -320,7 +318,7 @@
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
- ieee802_11_set_beacons(iface);
+ ieee802_11_update_beacons(iface);
}
@@ -375,7 +373,7 @@
}
if (set_beacon)
- ieee802_11_set_beacons(iface);
+ ieee802_11_update_beacons(iface);
}
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index 201f6ec..f0b4125 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -34,7 +34,6 @@
int channel;
int datarate; /* in 100 kbps */
- int ssi_signal;
int ht_support;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4ea8684..0f29ccd 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -262,6 +262,11 @@
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
+#ifdef CONFIG_IEEE80211AC
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211AC */
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -293,7 +298,8 @@
void handle_probe_req(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int ssi_signal)
{
u8 *resp;
struct ieee802_11_elems elems;
@@ -311,7 +317,7 @@
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
mgmt->sa, mgmt->da, mgmt->bssid,
- ie, ie_len) > 0)
+ ie, ie_len, ssi_signal) > 0)
return;
if (!hapd->iconf->send_probe_response)
@@ -594,6 +600,11 @@
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+#ifdef CONFIG_IEEE80211AC
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AC */
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -682,6 +693,7 @@
!is_zero_ether_addr(hapd->conf->hessid))
params.hessid = hapd->conf->hessid;
params.access_network_type = hapd->conf->access_network_type;
+ params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
if (hostapd_drv_set_ap(hapd, ¶ms))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
@@ -699,4 +711,14 @@
ieee802_11_set_beacon(iface->bss[i]);
}
+
+/* only update beacons if started */
+void ieee802_11_update_beacons(struct hostapd_iface *iface)
+{
+ size_t i;
+ for (i = 0; i < iface->num_bss; i++)
+ if (iface->bss[i]->beacon_set_done)
+ ieee802_11_set_beacon(iface->bss[i]);
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a944f5f..37f10d2 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -19,8 +19,10 @@
struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len);
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int ssi_signal);
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
+void ieee802_11_update_beacons(struct hostapd_iface *iface);
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index d76b381..ab9c83e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@@ -17,6 +18,7 @@
#include "wps_hostapd.h"
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
@@ -100,3 +102,170 @@
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
+
+
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+ u8 minor_reason_code, const u8 *addr)
+{
+ struct ieee80211_mgmt *mgmt;
+ int ret;
+ u8 *pos;
+
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+
+ mgmt = os_zalloc(sizeof(*mgmt) + 100);
+ if (mgmt == NULL)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+ " with minor reason code %u (stype=%u)",
+ MAC2STR(addr), minor_reason_code, stype);
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ if (stype == WLAN_FC_STYPE_DEAUTH) {
+ mgmt->u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+ } else {
+ mgmt->u.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+ }
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 3 + 1;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = P2P_OUI_TYPE;
+
+ *pos++ = P2P_ATTR_MINOR_REASON_CODE;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ *pos++ = minor_reason_code;
+
+ ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+ pos - (u8 *) mgmt, 1);
+ os_free(mgmt);
+
+ return ret < 0 ? -1 : 0;
+}
+#endif /* CONFIG_P2P_MANAGER */
+
+
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
+ return 0;
+ }
+
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+
+ return 0;
+}
+
+
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
+ return 0;
+ }
+
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_disassociate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+
+ return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index 0e4286d..e83f894 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -15,5 +15,9 @@
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+ const char *txtaddr);
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+ const char *txtaddr);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 820a903..cf06a4f 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -26,6 +26,7 @@
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "hw_features.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -78,10 +79,19 @@
sta = ap_get_sta(hapd, addr);
if (sta) {
accounting_sta_stop(hapd, sta);
+
+ /*
+ * Make sure that the previously registered inactivity timer
+ * will not remove the STA immediately.
+ */
+ sta->timeout_next = STA_NULLFUNC;
} else {
sta = ap_sta_add(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ hostapd_drv_sta_disassoc(hapd, addr,
+ WLAN_REASON_DISASSOC_AP_BUSY);
return -1;
+ }
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
@@ -264,8 +274,36 @@
}
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+ int offset)
+{
+#ifdef NEED_AP_MLME
+ int channel;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "driver had channel switch: "
+ "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+
+ hapd->iface->freq = freq;
+
+ channel = hostapd_hw_get_channel(hapd, freq);
+ if (!channel) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING, "driver switched to "
+ "bad channel!");
+ return;
+ }
+
+ hapd->iconf->channel = channel;
+ hapd->iconf->ieee80211n = ht;
+ hapd->iconf->secondary_channel = offset;
+#endif /* NEED_AP_MLME */
+}
+
+
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
size_t i;
int ret = 0;
@@ -276,7 +314,8 @@
random_add_randomness(sa, ETH_ALEN);
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
- sa, da, bssid, ie, ie_len) > 0) {
+ sa, da, bssid, ie, ie_len,
+ ssi_signal) > 0) {
ret = 1;
break;
}
@@ -541,7 +580,8 @@
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
- data->rx_probe_req.ie_len);
+ data->rx_probe_req.ie_len,
+ data->rx_probe_req.ssi_signal);
break;
case EVENT_NEW_STA:
hostapd_event_new_sta(hapd, data->new_sta.addr);
@@ -578,6 +618,13 @@
hostapd_rx_action(hapd, &data->rx_action);
break;
#endif /* NEED_AP_MLME */
+ case EVENT_CH_SWITCH:
+ if (!data)
+ break;
+ hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
new file mode 100644
index 0000000..2177b02
--- /dev/null
+++ b/src/ap/gas_serv.c
@@ -0,0 +1,673 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "gas_serv.h"
+
+
+static struct gas_dialog_info *
+gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
+{
+ struct sta_info *sta;
+ struct gas_dialog_info *dia = NULL;
+ int i, j;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ /*
+ * We need a STA entry to be able to maintain state for
+ * the GAS query.
+ */
+ wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
+ "GAS query");
+ sta = ap_sta_add(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
+ " for GAS query", MAC2STR(addr));
+ return NULL;
+ }
+ sta->flags |= WLAN_STA_GAS;
+ /*
+ * The default inactivity is 300 seconds. We don't need
+ * it to be that long.
+ */
+ ap_sta_session_timeout(hapd, sta, 5);
+ }
+
+ if (sta->gas_dialog == NULL) {
+ sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+ sizeof(struct gas_dialog_info));
+ if (sta->gas_dialog == NULL)
+ return NULL;
+ }
+
+ for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
+ if (i == GAS_DIALOG_MAX)
+ i = 0;
+ if (sta->gas_dialog[i].valid)
+ continue;
+ dia = &sta->gas_dialog[i];
+ dia->valid = 1;
+ dia->index = i;
+ dia->dialog_token = dialog_token;
+ sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
+ return dia;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
+ MACSTR " dialog_token %u. Consider increasing "
+ "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
+
+ return NULL;
+}
+
+
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+ u8 dialog_token)
+{
+ struct sta_info *sta;
+ int i;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+ for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
+ if (sta->gas_dialog[i].dialog_token != dialog_token ||
+ !sta->gas_dialog[i].valid)
+ continue;
+ return &sta->gas_dialog[i];
+ }
+ wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
+ MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
+ return NULL;
+}
+
+
+void gas_serv_dialog_clear(struct gas_dialog_info *dia)
+{
+ wpabuf_free(dia->sd_resp);
+ os_memset(dia, 0, sizeof(*dia));
+}
+
+
+static void gas_serv_free_dialogs(struct hostapd_data *hapd,
+ const u8 *sta_addr)
+{
+ struct sta_info *sta;
+ int i;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (sta == NULL || sta->gas_dialog == NULL)
+ return;
+
+ for (i = 0; i < GAS_DIALOG_MAX; i++) {
+ if (sta->gas_dialog[i].valid)
+ return;
+ }
+
+ os_free(sta->gas_dialog);
+ sta->gas_dialog = NULL;
+}
+
+
+static void anqp_add_capab_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
+ wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
+ if (hapd->conf->venue_name)
+ wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+ if (hapd->conf->roaming_consortium)
+ wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+ gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (hapd->conf->venue_name) {
+ u8 *len;
+ unsigned int i;
+ len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
+ wpabuf_put_u8(buf, hapd->conf->venue_group);
+ wpabuf_put_u8(buf, hapd->conf->venue_type);
+ for (i = 0; i < hapd->conf->venue_name_count; i++) {
+ struct hostapd_venue_name *vn;
+ vn = &hapd->conf->venue_name[i];
+ wpabuf_put_u8(buf, 3 + vn->name_len);
+ wpabuf_put_data(buf, vn->lang, 3);
+ wpabuf_put_data(buf, vn->name, vn->name_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ unsigned int i;
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
+ for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
+ struct hostapd_roaming_consortium *rc;
+ rc = &hapd->conf->roaming_consortium[i];
+ wpabuf_put_u8(buf, rc->len);
+ wpabuf_put_data(buf, rc->oi, rc->len);
+ }
+ gas_anqp_set_element_len(buf, len);
+}
+
+
+static struct wpabuf *
+gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+ unsigned int request,
+ struct gas_dialog_info *di)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(1400);
+ if (buf == NULL)
+ return NULL;
+
+ if (request & ANQP_REQ_CAPABILITY_LIST)
+ anqp_add_capab_list(hapd, buf);
+ if (request & ANQP_REQ_VENUE_NAME)
+ anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_ROAMING_CONSORTIUM)
+ anqp_add_roaming_consortium(hapd, buf);
+
+ return buf;
+}
+
+
+static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
+{
+ struct gas_dialog_info *dia = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
+ "dialog token %d", dia->dialog_token);
+
+ gas_serv_dialog_clear(dia);
+}
+
+
+struct anqp_query_info {
+ unsigned int request;
+ unsigned int remote_request;
+ const void *param;
+ u32 param_arg;
+ u16 remote_delay;
+};
+
+
+static void set_anqp_req(unsigned int bit, const char *name, int local,
+ unsigned int remote, u16 remote_delay,
+ struct anqp_query_info *qi)
+{
+ qi->request |= bit;
+ if (local) {
+ wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
+ } else if (bit & remote) {
+ wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
+ qi->remote_request |= bit;
+ if (remote_delay > qi->remote_delay)
+ qi->remote_delay = remote_delay;
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
+ }
+}
+
+
+static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+ struct anqp_query_info *qi)
+{
+ switch (info_id) {
+ case ANQP_CAPABILITY_LIST:
+ set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
+ 0, qi);
+ break;
+ case ANQP_VENUE_NAME:
+ set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
+ hapd->conf->venue_name != NULL, 0, 0, qi);
+ break;
+ case ANQP_ROAMING_CONSORTIUM:
+ set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
+ hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+ info_id);
+ break;
+ }
+}
+
+
+static void rx_anqp_query_list(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
+ (unsigned int) (end - pos) / 2);
+
+ while (pos + 2 <= end) {
+ rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
+ pos += 2;
+ }
+}
+
+
+static void gas_serv_req_local_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ struct anqp_query_info *qi)
+{
+ struct wpabuf *buf, *tx_buf;
+
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
+ buf);
+ if (!buf)
+ return;
+
+ if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+ hapd->conf->gas_comeback_delay) {
+ struct gas_dialog_info *di;
+ u16 comeback_delay = 1;
+
+ if (hapd->conf->gas_comeback_delay) {
+ /* Testing - allow overriding of the delay value */
+ comeback_delay = hapd->conf->gas_comeback_delay;
+ }
+
+ wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
+ "initial response - use GAS comeback");
+ di = gas_dialog_create(hapd, sa, dialog_token);
+ if (!di) {
+ wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
+ "for " MACSTR " (dialog token %u)",
+ MAC2STR(sa), dialog_token);
+ wpabuf_free(buf);
+ return;
+ }
+ di->sd_resp = buf;
+ di->sd_resp_pos = 0;
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
+ NULL);
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
+ tx_buf = gas_anqp_build_initial_resp_buf(
+ dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
+ wpabuf_free(buf);
+ }
+ if (!tx_buf)
+ return;
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+}
+
+
+static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
+ const u8 *sa,
+ const u8 *data, size_t len)
+{
+ const u8 *pos = data;
+ const u8 *end = data + len;
+ const u8 *next;
+ u8 dialog_token;
+ u16 slen;
+ struct anqp_query_info qi;
+ const u8 *adv_proto;
+
+ if (len < 1 + 2)
+ return;
+
+ os_memset(&qi, 0, sizeof(qi));
+
+ dialog_token = *pos++;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
+ MAC2STR(sa), dialog_token);
+
+ if (*pos != WLAN_EID_ADV_PROTO) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
+ return;
+ }
+ adv_proto = pos++;
+
+ slen = *pos++;
+ next = pos + slen;
+ if (next > end || slen < 2) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Invalid IE in GAS Initial Request");
+ return;
+ }
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
+ struct wpabuf *buf;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Unsupported GAS advertisement protocol id %u",
+ *pos);
+ if (sa[0] & 0x01)
+ return; /* Invalid source address - drop silently */
+ buf = gas_build_initial_resp(
+ dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
+ 0, 2 + slen + 2);
+ if (buf == NULL)
+ return;
+ wpabuf_put_data(buf, adv_proto, 2 + slen);
+ wpabuf_put_le16(buf, 0); /* Query Response Length */
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ return;
+ }
+
+ pos = next;
+ /* Query Request */
+ if (pos + 2 > end)
+ return;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (pos + slen > end)
+ return;
+ end = pos + slen;
+
+ /* ANQP Query Request */
+ while (pos < end) {
+ u16 info_id, elen;
+
+ if (pos + 4 > end)
+ return;
+
+ info_id = WPA_GET_LE16(pos);
+ pos += 2;
+ elen = WPA_GET_LE16(pos);
+ pos += 2;
+
+ if (pos + elen > end) {
+ wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
+ return;
+ }
+
+ switch (info_id) {
+ case ANQP_QUERY_LIST:
+ rx_anqp_query_list(hapd, pos, pos + elen, &qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
+ "Request element %u", info_id);
+ break;
+ }
+
+ pos += elen;
+ }
+
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+}
+
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+ struct gas_dialog_info *dialog)
+{
+ struct wpabuf *buf, *tx_buf;
+ u8 dialog_token = dialog->dialog_token;
+ size_t frag_len;
+
+ if (dialog->sd_resp == NULL) {
+ buf = gas_serv_build_gas_resp_payload(hapd,
+ dialog->all_requested,
+ dialog);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+ buf);
+ if (!buf)
+ goto tx_gas_response_done;
+ dialog->sd_resp = buf;
+ dialog->sd_resp_pos = 0;
+ }
+ frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+ if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
+ hapd->conf->gas_comeback_delay) {
+ u16 comeback_delay_tus = dialog->comeback_delay +
+ GAS_SERV_COMEBACK_DELAY_FUDGE;
+ u32 comeback_delay_secs, comeback_delay_usecs;
+
+ if (hapd->conf->gas_comeback_delay) {
+ /* Testing - allow overriding of the delay value */
+ comeback_delay_tus = hapd->conf->gas_comeback_delay;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
+ "%u) and comeback delay %u, "
+ "requesting comebacks", (unsigned int) frag_len,
+ (unsigned int) hapd->gas_frag_limit,
+ dialog->comeback_delay);
+ tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS,
+ comeback_delay_tus,
+ NULL);
+ if (tx_buf) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "GAS: Tx GAS Initial Resp (comeback = 10TU)");
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+ dst,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ }
+ wpabuf_free(tx_buf);
+
+ /* start a timer of 1.5 * comeback-delay */
+ comeback_delay_tus = comeback_delay_tus +
+ (comeback_delay_tus / 2);
+ comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
+ comeback_delay_usecs = (comeback_delay_tus * 1024) -
+ (comeback_delay_secs * 1000000);
+ eloop_register_timeout(comeback_delay_secs,
+ comeback_delay_usecs,
+ gas_serv_clear_cached_ies, dialog,
+ NULL);
+ goto tx_gas_response_done;
+ }
+
+ buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+ dialog->sd_resp_pos, frag_len);
+ if (buf == NULL) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
+ "failed");
+ goto tx_gas_response_done;
+ }
+ tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS, 0, buf);
+ wpabuf_free(buf);
+ if (tx_buf == NULL)
+ goto tx_gas_response_done;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
+ "Response (frag_id %d frag_len %d)",
+ dialog->sd_frag_id, (int) frag_len);
+ dialog->sd_frag_id++;
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+tx_gas_response_done:
+ gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
+ const u8 *sa,
+ const u8 *data, size_t len)
+{
+ struct gas_dialog_info *dialog;
+ struct wpabuf *buf, *tx_buf;
+ u8 dialog_token;
+ size_t frag_len;
+ int more = 0;
+
+ wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
+ if (len < 1)
+ return;
+ dialog_token = *data;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
+ dialog_token);
+
+ dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
+ if (!dialog) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
+ "response fragment for " MACSTR " dialog token %u",
+ MAC2STR(sa), dialog_token);
+
+ if (sa[0] & 0x01)
+ return; /* Invalid source address - drop silently */
+ tx_buf = gas_anqp_build_comeback_resp_buf(
+ dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
+ 0, NULL);
+ if (tx_buf == NULL)
+ return;
+ goto send_resp;
+ }
+
+ if (dialog->sd_resp == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
+ dialog->requested, dialog->received);
+ if ((dialog->requested & dialog->received) !=
+ dialog->requested) {
+ wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
+ "from remote processing");
+ gas_serv_dialog_clear(dialog);
+ tx_buf = gas_anqp_build_comeback_resp_buf(
+ dialog_token,
+ WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
+ NULL);
+ if (tx_buf == NULL)
+ return;
+ goto send_resp;
+ }
+
+ buf = gas_serv_build_gas_resp_payload(hapd,
+ dialog->all_requested,
+ dialog);
+ wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+ buf);
+ if (!buf)
+ goto rx_gas_comeback_req_done;
+ dialog->sd_resp = buf;
+ dialog->sd_resp_pos = 0;
+ }
+ frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+ if (frag_len > hapd->gas_frag_limit) {
+ frag_len = hapd->gas_frag_limit;
+ more = 1;
+ }
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
+ (unsigned int) frag_len);
+ buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+ dialog->sd_resp_pos, frag_len);
+ if (buf == NULL) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
+ "buffer");
+ goto rx_gas_comeback_req_done;
+ }
+ tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
+ WLAN_STATUS_SUCCESS,
+ dialog->sd_frag_id,
+ more, 0, buf);
+ wpabuf_free(buf);
+ if (tx_buf == NULL)
+ goto rx_gas_comeback_req_done;
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
+ "(frag_id %d more=%d frag_len=%d)",
+ dialog->sd_frag_id, more, (int) frag_len);
+ dialog->sd_frag_id++;
+ dialog->sd_resp_pos += frag_len;
+
+ if (more) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
+ "to be sent",
+ (int) (wpabuf_len(dialog->sd_resp) -
+ dialog->sd_resp_pos));
+ } else {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
+ "SD response sent");
+ gas_serv_dialog_clear(dialog);
+ gas_serv_free_dialogs(hapd, sa);
+ }
+
+send_resp:
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ wpabuf_free(tx_buf);
+ return;
+
+rx_gas_comeback_req_done:
+ gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
+ int freq)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ size_t hdr_len;
+ const u8 *sa, *data;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+ if (hdr_len > len)
+ return;
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ return;
+ sa = mgmt->sa;
+ len -= hdr_len;
+ data = &mgmt->u.action.u.public_action.action;
+ switch (data[0]) {
+ case WLAN_PA_GAS_INITIAL_REQ:
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+ break;
+ case WLAN_PA_GAS_COMEBACK_REQ:
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+ break;
+ }
+}
+
+
+int gas_serv_init(struct hostapd_data *hapd)
+{
+ hapd->public_action_cb = gas_serv_rx_public_action;
+ hapd->public_action_cb_ctx = hapd;
+ hapd->gas_frag_limit = 1400;
+ if (hapd->conf->gas_frag_limit > 0)
+ hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
+ return 0;
+}
+
+
+void gas_serv_deinit(struct hostapd_data *hapd)
+{
+}
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
new file mode 100644
index 0000000..0e2eaf6
--- /dev/null
+++ b/src/ap/gas_serv.h
@@ -0,0 +1,49 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERV_H
+#define GAS_SERV_H
+
+#define ANQP_REQ_CAPABILITY_LIST \
+ (1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
+#define ANQP_REQ_VENUE_NAME \
+ (1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_ROAMING_CONSORTIUM \
+ (1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+
+/* To account for latencies between hostapd and external ANQP processor */
+#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
+#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+
+struct gas_dialog_info {
+ u8 valid;
+ u8 index;
+ struct wpabuf *sd_resp; /* Fragmented response */
+ u8 dialog_token;
+ size_t sd_resp_pos; /* Offset in sd_resp */
+ u8 sd_frag_id;
+ u16 comeback_delay;
+
+ unsigned int requested;
+ unsigned int received;
+ unsigned int all_requested;
+};
+
+struct hostapd_data;
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+ struct gas_dialog_info *dialog);
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+ u8 dialog_token);
+void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
+
+int gas_serv_init(struct hostapd_data *hapd);
+void gas_serv_deinit(struct hostapd_data *hapd);
+
+#endif /* GAS_SERV_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index c5cbdf7..22c5e65 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "radius/radius_client.h"
+#include "radius/radius_das.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "authsrv.h"
@@ -30,15 +31,33 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
+#include "gas_serv.h"
-static int hostapd_flush_old_stations(struct hostapd_data *hapd);
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
extern int wpa_debug_level;
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < interfaces->count; i++) {
+ ret = cb(interfaces->iface[i], ctx);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
#ifndef CONFIG_NO_RADIUS
@@ -105,7 +124,8 @@
* allow them to use the BSS anymore.
*/
for (j = 0; j < iface->num_bss; j++) {
- hostapd_flush_old_stations(iface->bss[j]);
+ hostapd_flush_old_stations(iface->bss[j],
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_broadcast_wep_clear(iface->bss[j]);
#ifndef CONFIG_NO_RADIUS
@@ -210,21 +230,9 @@
return errors;
}
-/**
- * hostapd_cleanup - Per-BSS cleanup (deinitialization)
- * @hapd: Pointer to BSS data
- *
- * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
- */
-static void hostapd_cleanup(struct hostapd_data *hapd)
-{
- if (hapd->iface->ctrl_iface_deinit)
- hapd->iface->ctrl_iface_deinit(hapd);
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
accounting_deinit(hapd);
@@ -234,6 +242,8 @@
#ifndef CONFIG_NO_RADIUS
radius_client_deinit(hapd->radius);
hapd->radius = NULL;
+ radius_das_deinit(hapd->radius_das);
+ hapd->radius_das = NULL;
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
@@ -257,6 +267,28 @@
#endif /* CONFIG_P2P */
wpabuf_free(hapd->time_adv);
+
+#ifdef CONFIG_INTERWORKING
+ gas_serv_deinit(hapd);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+ if (hapd->iface->ctrl_iface_deinit)
+ hapd->iface->ctrl_iface_deinit(hapd);
+ hostapd_free_hapd_data(hapd);
}
@@ -272,6 +304,18 @@
}
+static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+{
+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+ iface->hw_features = NULL;
+ os_free(iface->current_rates);
+ iface->current_rates = NULL;
+ os_free(iface->basic_rates);
+ iface->basic_rates = NULL;
+ ap_list_deinit(iface);
+}
+
+
/**
* hostapd_cleanup_iface - Complete per-interface cleanup
* @iface: Pointer to interface data
@@ -281,13 +325,7 @@
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
- hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
- iface->hw_features = NULL;
- os_free(iface->current_rates);
- iface->current_rates = NULL;
- os_free(iface->basic_rates);
- iface->basic_rates = NULL;
- ap_list_deinit(iface);
+ hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -297,6 +335,15 @@
}
+static void hostapd_clear_wep(struct hostapd_data *hapd)
+{
+ if (hapd->drv_priv) {
+ hostapd_set_privacy(hapd, 0);
+ hostapd_broadcast_wep_clear(hapd);
+ }
+}
+
+
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
{
int i;
@@ -333,7 +380,7 @@
}
-static int hostapd_flush_old_stations(struct hostapd_data *hapd)
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
int ret = 0;
u8 addr[ETH_ALEN];
@@ -349,7 +396,7 @@
}
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_drv_sta_deauth(hapd, addr, reason);
hostapd_free_stas(hapd);
return ret;
@@ -464,6 +511,86 @@
}
+#ifndef CONFIG_NO_RADIUS
+
+static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ struct sta_info *sta = NULL;
+ char buf[128];
+
+ if (attr->sta_addr)
+ sta = ap_get_sta(hapd, attr->sta_addr);
+
+ if (sta == NULL && attr->acct_session_id &&
+ attr->acct_session_id_len == 17) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ os_snprintf(buf, sizeof(buf), "%08X-%08X",
+ sta->acct_session_id_hi,
+ sta->acct_session_id_lo);
+ if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
+ break;
+ }
+ }
+
+ if (sta == NULL && attr->cui) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ struct wpabuf *cui;
+ cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (cui && wpabuf_len(cui) == attr->cui_len &&
+ os_memcmp(wpabuf_head(cui), attr->cui,
+ attr->cui_len) == 0)
+ break;
+ }
+ }
+
+ if (sta == NULL && attr->user_name) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ u8 *identity;
+ size_t identity_len;
+ identity = ieee802_1x_get_identity(sta->eapol_sm,
+ &identity_len);
+ if (identity &&
+ identity_len == attr->user_name_len &&
+ os_memcmp(identity, attr->user_name, identity_len)
+ == 0)
+ break;
+ }
+ }
+
+ return sta;
+}
+
+
+static enum radius_das_res
+hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ if (hostapd_das_nas_mismatch(hapd, attr))
+ return RADIUS_DAS_NAS_MISMATCH;
+
+ sta = hostapd_das_find_sta(hapd, attr);
+ if (sta == NULL)
+ return RADIUS_DAS_SESSION_NOT_FOUND;
+
+ hostapd_drv_sta_deauth(hapd, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+ return RADIUS_DAS_SUCCESS;
+}
+
+#endif /* CONFIG_NO_RADIUS */
/**
@@ -519,7 +646,7 @@
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
- hostapd_flush_old_stations(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
@@ -583,6 +710,27 @@
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
return -1;
}
+
+ if (hapd->conf->radius_das_port) {
+ struct radius_das_conf das_conf;
+ os_memset(&das_conf, 0, sizeof(das_conf));
+ das_conf.port = hapd->conf->radius_das_port;
+ das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+ das_conf.shared_secret_len =
+ hapd->conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+ das_conf.time_window = hapd->conf->radius_das_time_window;
+ das_conf.require_event_timestamp =
+ hapd->conf->radius_das_require_event_timestamp;
+ das_conf.ctx = hapd;
+ das_conf.disconnect = hostapd_das_disconnect;
+ hapd->radius_das = radius_das_init(&das_conf);
+ if (hapd->radius_das == NULL) {
+ wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+ "failed.");
+ return -1;
+ }
+ }
#endif /* CONFIG_NO_RADIUS */
if (hostapd_acl_init(hapd)) {
@@ -615,6 +763,13 @@
return -1;
}
+#ifdef CONFIG_INTERWORKING
+ if (gas_serv_init(hapd)) {
+ wpa_printf(MSG_ERROR, "GAS server initialization failed");
+ return -1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
if (hapd->iface->ctrl_iface_init &&
hapd->iface->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Failed to setup control interface");
@@ -857,6 +1012,7 @@
hapd->conf = bss;
hapd->iface = hapd_iface;
hapd->driver = hapd->iconf->driver;
+ hapd->ctrl_sock = -1;
return hapd;
}
@@ -873,7 +1029,8 @@
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
hostapd_free_stas(hapd);
- hostapd_flush_old_stations(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
hostapd_cleanup(hapd);
}
}
@@ -937,4 +1094,12 @@
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(sta->addr),
+ hapd->conf->ap_max_inactivity);
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+ ap_handle_timer, hapd, sta);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bc28805..f7ed311 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -15,7 +15,6 @@
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
-struct hapd_interfaces;
struct hostapd_data;
struct sta_info;
struct hostap_sta_driver_data;
@@ -24,9 +23,15 @@
enum wps_event;
union wps_event_data;
+struct hapd_interfaces {
+ size_t count;
+ struct hostapd_iface **iface;
+};
+
+
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len, int ssi_signal);
void *ctx;
};
@@ -40,7 +45,7 @@
struct hostapd_frame_info {
u32 channel;
u32 datarate;
- u32 ssi_signal;
+ int ssi_signal; /* dBm */
};
@@ -80,6 +85,7 @@
struct radius_client_data *radius;
u32 acct_session_id_hi, acct_session_id_lo;
+ struct radius_das_data *radius_das;
struct iapp_data *iapp;
@@ -164,6 +170,9 @@
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
};
@@ -242,6 +251,9 @@
};
/* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
int hostapd_reload_config(struct hostapd_iface *iface);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
@@ -258,7 +270,8 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len),
+ const u8 *ie, size_t ie_len,
+ int ssi_signal),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
@@ -268,6 +281,9 @@
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
- const u8 *bssid, const u8 *ie, size_t ie_len);
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+ int offset);
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8c6fef2..76c4211 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -2,7 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -416,7 +416,7 @@
int res;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
- * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
+ * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
iface->scan_cb = NULL;
@@ -447,6 +447,46 @@
}
+static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
+ struct wpa_driver_scan_params *params)
+{
+ /* Scan only the affected frequency range */
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ int i, pos;
+ struct hostapd_hw_modes *mode;
+
+ if (iface->current_mode == NULL)
+ return;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ if (iface->conf->secondary_channel > 0)
+ sec_freq = pri_freq + 20;
+ else
+ sec_freq = pri_freq - 20;
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+
+ mode = iface->current_mode;
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ pos = 0;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (chan->freq < affected_start ||
+ chan->freq > affected_end)
+ continue;
+ params->freqs[pos++] = chan->freq;
+ }
+}
+
+
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
@@ -457,12 +497,15 @@
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(¶ms, 0, sizeof(params));
- /* TODO: scan only the needed frequency */
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, ¶ms);
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
+ os_free(params.freqs);
return -1;
}
+ os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 9c931ca..3996c90 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -876,6 +876,7 @@
#endif /* CONFIG_IEEE80211N */
p = hostapd_eid_ext_capab(hapd, p);
+ p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
@@ -1392,7 +1393,7 @@
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
- handle_probe_req(hapd, mgmt, len);
+ handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index d30e90f..9993bee 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -45,6 +45,8 @@
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
@@ -72,5 +74,6 @@
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 109c4bc..0c4c5f3 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -193,7 +193,8 @@
goto fail;
}
- radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
+ if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+ goto fail;
return 0;
fail:
@@ -492,7 +493,7 @@
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- cache->psk == NULL)
+ !cache->has_psk)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 0935cd5..b3fdf3d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -397,3 +397,31 @@
return 0;
}
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+ if (hapd->conf->ap_max_inactivity > 0) {
+ unsigned int val;
+ *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+ *pos++ = 3;
+ val = hapd->conf->ap_max_inactivity;
+ if (val > 68000)
+ val = 68000;
+ val *= 1000;
+ val /= 1024;
+ if (val == 0)
+ val = 1;
+ if (val > 65535)
+ val = 65535;
+ WPA_PUT_LE16(pos, val);
+ pos += 2;
+ *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+ }
+#endif /* CONFIG_WNM */
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
new file mode 100644
index 0000000..3ad33c8
--- /dev/null
+++ b/src/ap/ieee802_11_vht.c
@@ -0,0 +1,72 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of BSD license
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_vht_capabilities *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
+ hapd->conf->disable_11ac)
+ return eid;
+
+ *pos++ = WLAN_EID_VHT_CAP;
+ *pos++ = sizeof(*cap);
+
+ cap = (struct ieee80211_vht_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ cap->vht_capabilities_info = host_to_le32(
+ hapd->iface->current_mode->vht_capab);
+
+ /* Supported MCS set comes from hw */
+ os_memcpy(cap->vht_supported_mcs_set,
+ hapd->iface->current_mode->vht_mcs_set, 8);
+
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_vht_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
+ return eid;
+
+ *pos++ = WLAN_EID_VHT_OPERATION;
+ *pos++ = sizeof(*oper);
+
+ oper = (struct ieee80211_vht_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+
+ /* VHT Basic MCS set comes from hw */
+ /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
+ oper->vht_basic_mcs_set = 0xfffc;
+ pos += sizeof(*oper);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index a329777..dd0df1d 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -416,6 +416,7 @@
struct radius_msg *msg;
char buf[128];
struct eapol_state_machine *sm = sta->eapol_sm;
+ struct hostapd_radius_attr *attr;
if (sm == NULL)
return;
@@ -442,7 +443,9 @@
goto fail;
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
@@ -450,7 +453,9 @@
}
#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
@@ -458,7 +463,9 @@
}
#endif /* CONFIG_IPV6 */
- if (hapd->conf->nas_identifier &&
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_IDENTIFIER) &&
+ hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
@@ -466,7 +473,9 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
}
@@ -474,7 +483,9 @@
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
buf[sizeof(buf) - 1] = '\0';
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_CALLED_STATION_ID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
@@ -492,12 +503,16 @@
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_FRAMED_MTU) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
printf("Could not add Framed-MTU\n");
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
@@ -513,7 +528,9 @@
radius_mode_txt(hapd));
buf[sizeof(buf) - 1] = '\0';
}
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
@@ -541,6 +558,36 @@
}
}
+ if (hapd->conf->radius_request_cui) {
+ const u8 *cui;
+ size_t cui_len;
+ /* Add previously learned CUI or nul CUI to request CUI */
+ if (sm->radius_cui) {
+ cui = wpabuf_head(sm->radius_cui);
+ cui_len = wpabuf_len(sm->radius_cui);
+ } else {
+ cui = (const u8 *) "\0";
+ cui_len = 1;
+ }
+ if (!radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ cui, cui_len)) {
+ wpa_printf(MSG_ERROR, "Could not add CUI");
+ goto fail;
+ }
+ }
+
+ for (attr = hapd->conf->radius_auth_req_attr; attr; attr = attr->next)
+ {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ goto fail;
+ }
+ }
+
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
@@ -861,12 +908,22 @@
if (!force_1x && !hapd->conf->ieee802_1x) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
"802.1X not enabled or forced for WPS");
+ /*
+ * Clear any possible EAPOL authenticator state to support
+ * reassociation change from WPS to PSK.
+ */
+ ieee802_1x_free_station(sta);
return;
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
+ /*
+ * Clear any possible EAPOL authenticator state to support
+ * reassociation change from WPA-EAP to PSK.
+ */
+ ieee802_1x_free_station(sta);
return;
}
@@ -968,6 +1025,7 @@
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
radius_free_class(&sm->radius_class);
+ wpabuf_free(sm->radius_cui);
#endif /* CONFIG_NO_RADIUS */
os_free(sm->identity);
@@ -1189,6 +1247,32 @@
}
+/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
+static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ struct eapol_state_machine *sm = sta->eapol_sm;
+ struct wpabuf *cui;
+ u8 *buf;
+ size_t len;
+
+ if (sm == NULL)
+ return;
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) < 0)
+ return;
+
+ cui = wpabuf_alloc_copy(buf, len);
+ if (cui == NULL)
+ return;
+
+ wpabuf_free(sm->radius_cui);
+ sm->radius_cui = cui;
+}
+
+
struct sta_id_search {
u8 identifier;
struct eapol_state_machine *sm;
@@ -1348,6 +1432,7 @@
shared_secret_len);
ieee802_1x_store_radius_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
+ ieee802_1x_update_sta_cui(hapd, sta, msg);
if (sm->eap_if->eapKeyAvailable &&
wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
session_timeout_set ?
@@ -1865,6 +1950,14 @@
}
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+ if (sm == NULL)
+ return NULL;
+ return sm->radius_cui;
+}
+
+
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 58f6084..f9b05ca 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -67,6 +67,7 @@
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);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 9eb4840..ba2c033 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -40,6 +40,7 @@
if (entry == NULL)
return;
os_free(entry->identity);
+ wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
@@ -136,6 +137,9 @@
}
}
+ if (eapol->radius_cui)
+ entry->cui = wpabuf_dup(eapol->radius_cui);
+
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &eapol->radius_class);
#endif /* CONFIG_NO_RADIUS */
@@ -163,6 +167,11 @@
eapol->identity, eapol->identity_len);
}
+ if (entry->cui) {
+ wpabuf_free(eapol->radius_cui);
+ eapol->radius_cui = wpabuf_dup(entry->cui);
+ }
+
#ifndef CONFIG_NO_RADIUS
radius_free_class(&eapol->radius_class);
radius_copy_class(&eapol->radius_class, &entry->radius_class);
@@ -299,6 +308,8 @@
old_entry->identity_len);
}
}
+ if (old_entry->cui)
+ entry->cui = wpabuf_dup(old_entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 74b73c4..d473f3f 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +25,7 @@
u8 *identity;
size_t identity_len;
+ struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
int vlan_id;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index afabdaa..95b701c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -28,6 +28,7 @@
#include "vlan_init.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
+#include "gas_serv.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -194,6 +195,8 @@
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
+ wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
+ __func__, MAC2STR(sta->addr));
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -218,6 +221,15 @@
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (sta->gas_dialog) {
+ int i;
+ for (i = 0; i < GAS_DIALOG_MAX; i++)
+ gas_serv_dialog_clear(&sta->gas_dialog[i]);
+ os_free(sta->gas_dialog);
+ }
+#endif /* CONFIG_INTERWORKING */
+
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
@@ -262,6 +274,9 @@
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
+ wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
+ __func__, MAC2STR(sta->addr), sta->flags,
+ sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@@ -274,6 +289,12 @@
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
int inactive_sec;
+ /*
+ * Add random value to timeout so that we don't end up bouncing
+ * all stations at the same time if we have lots of associated
+ * stations that are idle (but keep re-associating).
+ */
+ int fuzz = os_random() % 20;
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
if (inactive_sec == -1) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -285,7 +306,7 @@
* Anyway, try again after the next inactivity timeout,
* but do not disconnect the station now.
*/
- next_time = hapd->conf->ap_max_inactivity;
+ next_time = hapd->conf->ap_max_inactivity + fuzz;
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
sta->flags & WLAN_STA_ASSOC) {
/* station activity detected; reset timeout state */
@@ -293,7 +314,7 @@
"Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
- next_time = hapd->conf->ap_max_inactivity -
+ next_time = hapd->conf->ap_max_inactivity + fuzz -
inactive_sec;
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -320,6 +341,9 @@
}
if (next_time) {
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%lu seconds)",
+ __func__, MAC2STR(sta->addr), next_time);
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
sta);
return;
@@ -353,6 +377,9 @@
switch (sta->timeout_next) {
case STA_NULLFUNC:
sta->timeout_next = STA_DISASSOC;
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
+ __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
hapd, sta);
break;
@@ -369,6 +396,9 @@
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
sta->timeout_next = STA_DEAUTH;
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
+ __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
@@ -397,8 +427,14 @@
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
- if (!(sta->flags & WLAN_STA_AUTH))
+ if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (sta->flags & WLAN_STA_GAS) {
+ wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
+ "entry " MACSTR, MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ }
return;
+ }
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -455,6 +491,10 @@
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
/* initialize STA info data */
+ wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - ap_max_inactivity)",
+ __func__, MAC2STR(addr),
+ hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
@@ -528,6 +568,11 @@
sta->flags &= ~WLAN_STA_ASSOC;
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DISASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
@@ -561,6 +606,11 @@
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
@@ -576,6 +626,23 @@
}
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ if (sta && (sta->flags & WLAN_STA_WPS)) {
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+ __func__, MAC2STR(sta->addr));
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
+
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
@@ -778,11 +845,20 @@
int authorized)
{
const u8 *dev_addr = NULL;
+#ifdef CONFIG_P2P
+ u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
#ifdef CONFIG_P2P
- dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+ if (hapd->p2p_group == NULL) {
+ if (sta->p2p_ie != NULL &&
+ p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
+ dev_addr = addr;
+ } else
+ dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
if (authorized) {
@@ -848,6 +924,11 @@
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+ "for " MACSTR " (%d seconds - "
+ "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+ __func__, MAC2STR(sta->addr),
+ AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 60b3a7b..cef428d 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -27,6 +27,7 @@
#define WLAN_STA_WDS BIT(14)
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -107,6 +108,12 @@
struct os_time sa_query_start;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_INTERWORKING
+#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
+ struct gas_dialog_info *gas_dialog;
+ u8 gas_dialog_next;
+#endif /* CONFIG_INTERWORKING */
+
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
};
@@ -137,7 +144,6 @@
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
@@ -149,6 +155,10 @@
u16 reason);
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx);
+#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 60088ee..dd5aa68 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_mlme.h"
@@ -44,12 +45,17 @@
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
hapd, NULL);
- for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+ while ((sta = hapd->sta_list)) {
+ sta->acct_terminate_cause =
+ RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
+ if (sta->flags & WLAN_STA_AUTH) {
+ mlme_deauthenticate_indication(
+ hapd, sta,
+ WLAN_REASON_MICHAEL_MIC_FAILURE);
+ }
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
- ap_sta_set_authorized(hapd, sta, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- hostapd_drv_sta_remove(hapd, sta->addr);
+ ap_free_sta(hapd, sta);
}
}
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 36c1182..3e9fc08 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -17,7 +17,8 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *da, const u8 *bssid,
- const u8 *ie, size_t ie_len),
+ const u8 *ie, size_t ie_len,
+ int ssi_signal),
void *ctx)
{
struct hostapd_probereq_cb *n;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index d1b9b4d..1d942a4 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1641,10 +1641,23 @@
wpa_group_ensure_init(sm->wpa_auth, sm->group);
- os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+ /*
+ * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+ * ambiguous. The Authenticator state machine uses a counter that is
+ * incremented by one for each 4-way handshake. However, the security
+ * analysis of 4-way handshake points out that unpredictable nonces
+ * help in preventing precomputation attacks. Instead of the state
+ * machine definition, use an unpredictable nonce value here to provide
+ * stronger protection against potential precomputation attacks.
+ */
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+ "ANonce.");
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ return;
+ }
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 8999217..07ce06c 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,8 @@
#include "utils/eloop.h"
#include "utils/uuid.h"
#include "crypto/dh_groups.h"
+#include "crypto/dh_group5.h"
+#include "crypto/random.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -20,6 +22,7 @@
#include "wps/wps.h"
#include "wps/wps_defs.h"
#include "wps/wps_dev_attr.h"
+#include "wps/wps_attr_parse.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
@@ -37,7 +40,8 @@
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
- const u8 *ie, size_t ie_len);
+ const u8 *ie, size_t ie_len,
+ int ssi_signal);
static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
@@ -183,19 +187,23 @@
struct wps_stop_reg_data {
struct hostapd_data *current_hapd;
const u8 *uuid_e;
+ const u8 *dev_pw;
+ size_t dev_pw_len;
};
static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
{
struct wps_stop_reg_data *data = ctx;
if (hapd != data->current_hapd && hapd->wps != NULL)
- wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+ wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
+ data->dev_pw, data->dev_pw_len);
return 0;
}
static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
- const u8 *uuid_e)
+ const u8 *uuid_e, const u8 *dev_pw,
+ size_t dev_pw_len)
{
struct hostapd_data *hapd = ctx;
char uuid[40];
@@ -209,6 +217,8 @@
mac_addr, uuid_e);
data.current_hapd = hapd;
data.uuid_e = uuid_e;
+ data.dev_pw = dev_pw;
+ data.dev_pw_len = dev_pw_len;
hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
}
@@ -984,6 +994,20 @@
}
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+ wps->ap_nfc_dev_pw_id = 0;
+ wpabuf_free(wps->ap_nfc_dh_pubkey);
+ wps->ap_nfc_dh_pubkey = NULL;
+ wpabuf_free(wps->ap_nfc_dh_privkey);
+ wps->ap_nfc_dh_privkey = NULL;
+ wpabuf_free(wps->ap_nfc_dev_pw);
+ wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1001,6 +1025,7 @@
wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
wpabuf_free(hapd->wps->oob_conf.dev_password);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
+ hostapd_wps_nfc_clear(hapd->wps);
os_free(hapd->wps);
hapd->wps = NULL;
hostapd_wps_clear_ies(hapd);
@@ -1098,6 +1123,24 @@
}
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
+{
+ if (hapd->wps == NULL)
+ return 0;
+
+ wps_registrar_wps_cancel(hapd->wps->registrar);
+ ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+
+ return 0;
+}
+
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+ return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+}
+
+
#ifdef CONFIG_WPS_OOB
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name)
@@ -1154,7 +1197,8 @@
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
struct hostapd_data *hapd = ctx;
struct wpabuf *wps_ie;
@@ -1471,3 +1515,156 @@
return wps_registrar_config_ap(hapd->wps->registrar, &cred);
}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_password_token_data {
+ const u8 *oob_dev_pw;
+ size_t oob_dev_pw_len;
+ int added;
+};
+
+
+static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
+{
+ struct wps_nfc_password_token_data *data = ctx;
+ int ret;
+
+ if (hapd->wps == NULL)
+ return 0;
+ ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
+ data->oob_dev_pw,
+ data->oob_dev_pw_len);
+ if (ret == 0)
+ data->added++;
+ return ret;
+}
+
+
+static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
+ struct wps_parse_attr *attr)
+{
+ struct wps_nfc_password_token_data data;
+
+ data.oob_dev_pw = attr->oob_dev_password;
+ data.oob_dev_pw_len = attr->oob_dev_password_len;
+ data.added = 0;
+ if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
+ return -1;
+ return data.added ? 0 : -1;
+}
+
+
+static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
+ const struct wpabuf *wps)
+{
+ struct wps_parse_attr attr;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+ if (wps_parse_msg(wps, &attr)) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+ return -1;
+ }
+
+ if (attr.oob_dev_password)
+ return hostapd_wps_add_nfc_password_token(hapd, &attr);
+
+ wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+ return -1;
+}
+
+
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+ const struct wpabuf *data)
+{
+ const struct wpabuf *wps = data;
+ struct wpabuf *tmp = NULL;
+ int ret;
+
+ if (wpabuf_len(data) < 4)
+ return -1;
+
+ if (*wpabuf_head_u8(data) != 0x10) {
+ /* Assume this contains full NDEF record */
+ tmp = ndef_parse_wifi(data);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+ return -1;
+ }
+ wps = tmp;
+ }
+
+ ret = hostapd_wps_nfc_tag_process(hapd, wps);
+ wpabuf_free(tmp);
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+ int ndef)
+{
+ struct wpabuf *ret;
+
+ if (hapd->wps == NULL)
+ return NULL;
+
+ ret = wps_get_oob_cred(hapd->wps);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+ return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+ &hapd->conf->wps_nfc_dh_pubkey,
+ &hapd->conf->wps_nfc_dh_privkey,
+ &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+ struct wps_context *wps = hapd->wps;
+
+ if (wps == NULL)
+ return -1;
+
+ if (!hapd->conf->wps_nfc_dh_pubkey ||
+ !hapd->conf->wps_nfc_dh_privkey ||
+ !hapd->conf->wps_nfc_dev_pw ||
+ !hapd->conf->wps_nfc_dev_pw_id)
+ return -1;
+
+ hostapd_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+ wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+ wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+ !wps->ap_nfc_dev_pw) {
+ hostapd_wps_nfc_clear(wps);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+ hostapd_wps_nfc_clear(hapd->wps);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index 9194225..f968e15 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -1,6 +1,6 @@
/*
* hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,7 @@
const char *uuid, const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
+int hostapd_wps_cancel(struct hostapd_data *hapd);
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
@@ -32,6 +33,13 @@
void hostapd_wps_update_ie(struct hostapd_data *hapd);
int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
const char *auth, const char *encr, const char *key);
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+ const struct wpabuf *data);
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+ int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
#else /* CONFIG_WPS */
@@ -67,6 +75,11 @@
return 0;
}
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_HOSTAPD_H */