1/*
2 * Hotspot 2.0 AP ANQP processing
3 * Copyright (c) 2009, Atheros Communications, Inc.
4 * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "includes.h"
11
12#include "common.h"
13#include "common/ieee802_11_defs.h"
14#include "common/wpa_ctrl.h"
15#include "hostapd.h"
16#include "ap_config.h"
17#include "ap_drv_ops.h"
18#include "sta_info.h"
19#include "hs20.h"
20
21
22u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
23{
24	u8 conf;
25	if (!hapd->conf->hs20)
26		return eid;
27	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
28	*eid++ = hapd->conf->hs20_release < 2 ? 5 : 7;
29	WPA_PUT_BE24(eid, OUI_WFA);
30	eid += 3;
31	*eid++ = HS20_INDICATION_OUI_TYPE;
32	conf = (hapd->conf->hs20_release - 1) << 4; /* Release Number */
33	if (hapd->conf->hs20_release >= 2)
34		conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
35	if (hapd->conf->disable_dgaf)
36		conf |= HS20_DGAF_DISABLED;
37	*eid++ = conf;
38	if (hapd->conf->hs20_release >= 2) {
39		WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
40		eid += 2;
41	}
42
43	return eid;
44}
45
46
47u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
48{
49	u8 *len;
50	u16 capab;
51
52	if (!hapd->conf->osen)
53		return eid;
54
55	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
56	len = eid++; /* to be filled */
57	WPA_PUT_BE24(eid, OUI_WFA);
58	eid += 3;
59	*eid++ = HS20_OSEN_OUI_TYPE;
60
61	/* Group Data Cipher Suite */
62	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
63	eid += RSN_SELECTOR_LEN;
64
65	/* Pairwise Cipher Suite Count and List */
66	WPA_PUT_LE16(eid, 1);
67	eid += 2;
68	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
69	eid += RSN_SELECTOR_LEN;
70
71	/* AKM Suite Count and List */
72	WPA_PUT_LE16(eid, 1);
73	eid += 2;
74	RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
75	eid += RSN_SELECTOR_LEN;
76
77	/* RSN Capabilities */
78	capab = 0;
79	if (hapd->conf->wmm_enabled) {
80		/* 4 PTKSA replay counters when using WMM */
81		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
82	}
83	if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
84		capab |= WPA_CAPABILITY_MFPC;
85		if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
86			capab |= WPA_CAPABILITY_MFPR;
87	}
88#ifdef CONFIG_OCV
89	if (hapd->conf->ocv &&
90	    (hapd->iface->drv_flags2 &
91	     (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
92		capab |= WPA_CAPABILITY_OCVC;
93#endif /* CONFIG_OCV */
94	WPA_PUT_LE16(eid, capab);
95	eid += 2;
96
97	*len = eid - len - 1;
98
99	return eid;
100}
101
102
103int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
104			       u8 osu_method, const char *url)
105{
106	struct wpabuf *buf;
107	size_t len = 0;
108	int ret;
109
110	/* TODO: should refuse to send notification if the STA is not associated
111	 * or if the STA did not indicate support for WNM-Notification */
112
113	if (url) {
114		len = 1 + os_strlen(url);
115		if (5 + len > 255) {
116			wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
117				   "WNM-Notification: '%s'", url);
118			return -1;
119		}
120	}
121
122	buf = wpabuf_alloc(4 + 7 + len);
123	if (buf == NULL)
124		return -1;
125
126	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
127	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
128	wpabuf_put_u8(buf, 1); /* Dialog token */
129	wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
130
131	/* Subscription Remediation subelement */
132	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
133	wpabuf_put_u8(buf, 5 + len);
134	wpabuf_put_be24(buf, OUI_WFA);
135	wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
136	if (url) {
137		wpabuf_put_u8(buf, len - 1);
138		wpabuf_put_data(buf, url, len - 1);
139		wpabuf_put_u8(buf, osu_method);
140	} else {
141		/* Server URL and Server Method fields not included */
142		wpabuf_put_u8(buf, 0);
143	}
144
145	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
146				      wpabuf_head(buf), wpabuf_len(buf));
147
148	wpabuf_free(buf);
149
150	return ret;
151}
152
153
154int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
155					  const u8 *addr,
156					  const struct wpabuf *payload)
157{
158	struct wpabuf *buf;
159	int ret;
160
161	/* TODO: should refuse to send notification if the STA is not associated
162	 * or if the STA did not indicate support for WNM-Notification */
163
164	buf = wpabuf_alloc(4 + 6 + wpabuf_len(payload));
165	if (buf == NULL)
166		return -1;
167
168	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
169	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
170	wpabuf_put_u8(buf, 1); /* Dialog token */
171	wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
172
173	/* Deauthentication Imminent Notice subelement */
174	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
175	wpabuf_put_u8(buf, 4 + wpabuf_len(payload));
176	wpabuf_put_be24(buf, OUI_WFA);
177	wpabuf_put_u8(buf, HS20_WNM_DEAUTH_IMMINENT_NOTICE);
178	wpabuf_put_buf(buf, payload);
179
180	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
181				      wpabuf_head(buf), wpabuf_len(buf));
182
183	wpabuf_free(buf);
184
185	return ret;
186}
187
188
189int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
190				   const u8 *addr, const char *url)
191{
192	struct wpabuf *buf;
193	int ret;
194	size_t url_len;
195
196	if (!url) {
197		wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
198		return -1;
199	}
200
201	url_len = os_strlen(url);
202	if (5 + url_len > 255) {
203		wpa_printf(MSG_INFO,
204			   "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
205			   url);
206		return -1;
207	}
208
209	buf = wpabuf_alloc(4 + 7 + url_len);
210	if (!buf)
211		return -1;
212
213	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
214	wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
215	wpabuf_put_u8(buf, 1); /* Dialog token */
216	wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
217
218	/* Terms and Conditions Acceptance subelement */
219	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
220	wpabuf_put_u8(buf, 4 + 1 + url_len);
221	wpabuf_put_be24(buf, OUI_WFA);
222	wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
223	wpabuf_put_u8(buf, url_len);
224	wpabuf_put_str(buf, url);
225
226	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
227				      wpabuf_head(buf), wpabuf_len(buf));
228
229	wpabuf_free(buf);
230
231	return ret;
232}
233
234
235void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
236			int enabled)
237{
238	if (enabled) {
239		wpa_printf(MSG_DEBUG,
240			   "HS 2.0: Terms and Conditions filtering required for "
241			   MACSTR, MAC2STR(sta->addr));
242		sta->hs20_t_c_filtering = 1;
243		/* TODO: Enable firewall filtering for the STA */
244		wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
245			MAC2STR(sta->addr));
246	} else {
247		wpa_printf(MSG_DEBUG,
248			   "HS 2.0: Terms and Conditions filtering not required for "
249			   MACSTR, MAC2STR(sta->addr));
250		sta->hs20_t_c_filtering = 0;
251		/* TODO: Disable firewall filtering for the STA */
252		wpa_msg(hapd->msg_ctx, MSG_INFO,
253			HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
254	}
255}
256