1ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines/*
2ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines * Hotspot 2.0 AP ANQP processing
3ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines * Copyright (c) 2009, Atheros Communications, Inc.
4ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
5ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines *
6ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines * This software may be distributed under the terms of the BSD license.
7ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines * See README for more details.
8ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines */
9ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
10ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines#include "includes.h"
11ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
126948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar#include "common.h"
136948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar#include "common/ieee802_11_defs.h"
14ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines#include "hostapd.h"
15ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines#include "ap_config.h"
16cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "ap_drv_ops.h"
17cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#include "hs20.h"
18ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
19ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
20cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainaru8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
21cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar{
22cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	u8 conf;
23cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (!hapd->conf->hs20)
24cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		return eid;
25cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
26cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*eid++ = 7;
27cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	WPA_PUT_BE24(eid, OUI_WFA);
28cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += 3;
29cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*eid++ = HS20_INDICATION_OUI_TYPE;
30cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	conf = HS20_VERSION; /* Release Number */
31cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
32cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (hapd->conf->disable_dgaf)
33cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		conf |= HS20_DGAF_DISABLED;
34cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*eid++ = conf;
35cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
36cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += 2;
37cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
38cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	return eid;
39cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}
40cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
41cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
42cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainaru8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
43cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar{
44cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	u8 *len;
45cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	u16 capab;
46cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
47cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (!hapd->conf->osen)
48cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		return eid;
49cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
50cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
51cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	len = eid++; /* to be filled */
52ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	WPA_PUT_BE24(eid, OUI_WFA);
53ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	eid += 3;
54ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	*eid++ = HS20_OSEN_OUI_TYPE;
55ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
56ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	/* Group Data Cipher Suite */
57ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
58ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	eid += RSN_SELECTOR_LEN;
59ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
60ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	/* Pairwise Cipher Suite Count and List */
61ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	WPA_PUT_LE16(eid, 1);
62cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += 2;
63cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
64ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines	eid += RSN_SELECTOR_LEN;
65cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
66cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* AKM Suite Count and List */
67cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	WPA_PUT_LE16(eid, 1);
68cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += 2;
69cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
70cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += RSN_SELECTOR_LEN;
71cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
72cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* RSN Capabilities */
73cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	capab = 0;
74cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (hapd->conf->wmm_enabled) {
75cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		/* 4 PTKSA replay counters when using WMM */
76cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
77cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	}
78cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#ifdef CONFIG_IEEE80211W
79cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
80cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		capab |= WPA_CAPABILITY_MFPC;
81cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
82cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar			capab |= WPA_CAPABILITY_MFPR;
83cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	}
84cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar#endif /* CONFIG_IEEE80211W */
85cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	WPA_PUT_LE16(eid, capab);
86cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	eid += 2;
87cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
88cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	*len = eid - len - 1;
89cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
90cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	return eid;
91cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}
92cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
93cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
94cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarint hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
95cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar			       u8 osu_method, const char *url)
96cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar{
97cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	struct wpabuf *buf;
98cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	size_t len = 0;
99cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	int ret;
100cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
101cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* TODO: should refuse to send notification if the STA is not associated
102cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	 * or if the STA did not indicate support for WNM-Notification */
103cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
104cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (url) {
105cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		len = 1 + os_strlen(url);
106cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		if (5 + len > 255) {
107cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar			wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
108cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar				   "WNM-Notification: '%s'", url);
109cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar			return -1;
110cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		}
111cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	}
112cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
113cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	buf = wpabuf_alloc(4 + 7 + len);
114cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (buf == NULL)
115cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		return -1;
116cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
117cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
118cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
119cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 1); /* Dialog token */
120cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
121cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
122cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* Subscription Remediation subelement */
123cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
124cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 5 + len);
125cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_be24(buf, OUI_WFA);
126cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
127cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (url) {
128cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		wpabuf_put_u8(buf, len - 1);
129cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		wpabuf_put_data(buf, url, len - 1);
130cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		wpabuf_put_u8(buf, osu_method);
131cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	} else {
132cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		/* Server URL and Server Method fields not included */
133cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		wpabuf_put_u8(buf, 0);
134cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	}
135cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
136cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
137cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar				      wpabuf_head(buf), wpabuf_len(buf));
138cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
139cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_free(buf);
140cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
141cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	return ret;
142cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}
143cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
144cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
145cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainarint hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
146cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar					  const u8 *addr,
147cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar					  const struct wpabuf *payload)
148cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar{
149cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	struct wpabuf *buf;
150cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	int ret;
151cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
152cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* TODO: should refuse to send notification if the STA is not associated
153cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	 * or if the STA did not indicate support for WNM-Notification */
154cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
155cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	buf = wpabuf_alloc(4 + 6 + wpabuf_len(payload));
156cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	if (buf == NULL)
157cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar		return -1;
158cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
159cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
160cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
161cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 1); /* Dialog token */
162cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
163cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
164cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	/* Deauthentication Imminent Notice subelement */
165cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
166cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, 4 + wpabuf_len(payload));
167cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_be24(buf, OUI_WFA);
168cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_u8(buf, HS20_WNM_DEAUTH_IMMINENT_NOTICE);
169cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_put_buf(buf, payload);
170cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
171cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
172cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar				      wpabuf_head(buf), wpabuf_len(buf));
173cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
174cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	wpabuf_free(buf);
175cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar
176cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar	return ret;
177cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar}
178cddc3e03e4ec99c0268c03a126195173e519ed58Pirama Arumuga Nainar