]>
Commit | Line | Data |
---|---|---|
25471fe3 JK |
1 | /* |
2 | * Copyright (c) 2009, Atheros Communications, Inc. | |
3 | * Copyright (c) 2011-2012, Qualcomm Atheros, Inc. | |
4 | * | |
5 | * This software may be distributed under the terms of the BSD license. | |
6 | * See README for more details. | |
7 | */ | |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
12 | #include "eloop.h" | |
13 | #include "common/ieee802_11_common.h" | |
14 | #include "common/ieee802_11_defs.h" | |
15 | #include "common/gas.h" | |
16 | #include "common/wpa_ctrl.h" | |
7ef69479 | 17 | #include "rsn_supp/wpa.h" |
25471fe3 JK |
18 | #include "wpa_supplicant_i.h" |
19 | #include "driver_i.h" | |
20 | #include "config.h" | |
21 | #include "bss.h" | |
7ef69479 | 22 | #include "blacklist.h" |
25471fe3 JK |
23 | #include "gas_query.h" |
24 | #include "interworking.h" | |
25 | #include "hs20_supplicant.h" | |
26 | ||
27 | ||
f9cd147d | 28 | void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) |
c923b8a5 | 29 | { |
f9cd147d JM |
30 | u8 conf; |
31 | ||
c923b8a5 | 32 | wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); |
f9cd147d | 33 | wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5); |
c923b8a5 JK |
34 | wpabuf_put_be24(buf, OUI_WFA); |
35 | wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE); | |
f9cd147d JM |
36 | conf = HS20_VERSION; |
37 | if (pps_mo_id >= 0) | |
38 | conf |= HS20_PPS_MO_ID_PRESENT; | |
39 | wpabuf_put_u8(buf, conf); | |
40 | if (pps_mo_id >= 0) | |
41 | wpabuf_put_le16(buf, pps_mo_id); | |
c923b8a5 JK |
42 | } |
43 | ||
44 | ||
55a2df43 JM |
45 | int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, |
46 | struct wpa_bss *bss) | |
47 | { | |
48 | if (!wpa_s->conf->hs20 || !ssid) | |
49 | return 0; | |
50 | ||
51 | if (ssid->parent_cred) | |
52 | return 1; | |
53 | ||
54 | if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) | |
55 | return 0; | |
56 | ||
57 | /* | |
58 | * This may catch some non-Hotspot 2.0 cases, but it is safer to do that | |
59 | * than cause Hotspot 2.0 connections without indication element getting | |
60 | * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element. | |
61 | */ | |
62 | ||
63 | if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X)) | |
64 | return 0; | |
65 | if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) | |
66 | return 0; | |
67 | if (ssid->proto != WPA_PROTO_RSN) | |
68 | return 0; | |
69 | ||
70 | return 1; | |
71 | } | |
72 | ||
73 | ||
f9cd147d JM |
74 | int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) |
75 | { | |
76 | struct wpa_cred *cred; | |
77 | ||
78 | if (ssid == NULL || ssid->parent_cred == NULL) | |
79 | return 0; | |
80 | ||
81 | for (cred = wpa_s->conf->cred; cred; cred = cred->next) { | |
82 | if (ssid->parent_cred == cred) | |
83 | return cred->update_identifier; | |
84 | } | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
89 | ||
25471fe3 JK |
90 | struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, |
91 | size_t payload_len) | |
92 | { | |
93 | struct wpabuf *buf; | |
94 | u8 *len_pos; | |
95 | ||
96 | buf = gas_anqp_build_initial_req(0, 100 + payload_len); | |
97 | if (buf == NULL) | |
98 | return NULL; | |
99 | ||
100 | len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); | |
101 | wpabuf_put_be24(buf, OUI_WFA); | |
102 | wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); | |
103 | if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) { | |
104 | wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); | |
105 | wpabuf_put_u8(buf, 0); /* Reserved */ | |
106 | if (payload) | |
107 | wpabuf_put_data(buf, payload, payload_len); | |
108 | } else { | |
109 | u8 i; | |
110 | wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST); | |
111 | wpabuf_put_u8(buf, 0); /* Reserved */ | |
112 | for (i = 0; i < 32; i++) { | |
113 | if (stypes & BIT(i)) | |
114 | wpabuf_put_u8(buf, i); | |
115 | } | |
116 | } | |
117 | gas_anqp_set_element_len(buf, len_pos); | |
118 | ||
119 | gas_anqp_set_len(buf); | |
120 | ||
121 | return buf; | |
122 | } | |
123 | ||
124 | ||
125 | int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, | |
126 | const u8 *payload, size_t payload_len) | |
127 | { | |
128 | struct wpabuf *buf; | |
129 | int ret = 0; | |
130 | int freq; | |
131 | struct wpa_bss *bss; | |
132 | int res; | |
133 | ||
134 | freq = wpa_s->assoc_freq; | |
135 | bss = wpa_bss_get_bssid(wpa_s, dst); | |
485e3a92 JM |
136 | if (bss) { |
137 | wpa_bss_anqp_unshare_alloc(bss); | |
25471fe3 | 138 | freq = bss->freq; |
485e3a92 | 139 | } |
25471fe3 JK |
140 | if (freq <= 0) |
141 | return -1; | |
142 | ||
143 | wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for " | |
144 | "subtypes 0x%x", MAC2STR(dst), stypes); | |
145 | ||
146 | buf = hs20_build_anqp_req(stypes, payload, payload_len); | |
147 | if (buf == NULL) | |
148 | return -1; | |
149 | ||
150 | res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); | |
151 | if (res < 0) { | |
152 | wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); | |
24c694b4 | 153 | wpabuf_free(buf); |
25471fe3 JK |
154 | ret = -1; |
155 | } else | |
156 | wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " | |
157 | "%u", res); | |
158 | ||
25471fe3 JK |
159 | return ret; |
160 | } | |
161 | ||
162 | ||
163 | void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, | |
164 | const u8 *sa, const u8 *data, size_t slen) | |
165 | { | |
166 | const u8 *pos = data; | |
167 | u8 subtype; | |
168 | struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); | |
476aed35 | 169 | struct wpa_bss_anqp *anqp = NULL; |
25471fe3 JK |
170 | |
171 | if (slen < 2) | |
172 | return; | |
173 | ||
476aed35 JM |
174 | if (bss) |
175 | anqp = bss->anqp; | |
176 | ||
25471fe3 JK |
177 | subtype = *pos++; |
178 | slen--; | |
179 | ||
180 | pos++; /* Reserved */ | |
181 | slen--; | |
182 | ||
183 | switch (subtype) { | |
184 | case HS20_STYPE_CAPABILITY_LIST: | |
185 | wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR | |
186 | " HS Capability List", MAC2STR(sa)); | |
187 | wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); | |
188 | break; | |
189 | case HS20_STYPE_OPERATOR_FRIENDLY_NAME: | |
190 | wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR | |
191 | " Operator Friendly Name", MAC2STR(sa)); | |
192 | wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); | |
476aed35 JM |
193 | if (anqp) { |
194 | wpabuf_free(anqp->hs20_operator_friendly_name); | |
195 | anqp->hs20_operator_friendly_name = | |
25471fe3 JK |
196 | wpabuf_alloc_copy(pos, slen); |
197 | } | |
198 | break; | |
199 | case HS20_STYPE_WAN_METRICS: | |
2edcd504 JM |
200 | wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen); |
201 | if (slen < 13) { | |
202 | wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN " | |
203 | "Metrics value from " MACSTR, MAC2STR(sa)); | |
204 | break; | |
205 | } | |
25471fe3 | 206 | wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR |
2edcd504 JM |
207 | " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), |
208 | pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), | |
209 | pos[9], pos[10], WPA_GET_LE16(pos + 11)); | |
476aed35 JM |
210 | if (anqp) { |
211 | wpabuf_free(anqp->hs20_wan_metrics); | |
212 | anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen); | |
25471fe3 JK |
213 | } |
214 | break; | |
215 | case HS20_STYPE_CONNECTION_CAPABILITY: | |
216 | wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR | |
217 | " Connection Capability", MAC2STR(sa)); | |
218 | wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); | |
476aed35 JM |
219 | if (anqp) { |
220 | wpabuf_free(anqp->hs20_connection_capability); | |
221 | anqp->hs20_connection_capability = | |
25471fe3 JK |
222 | wpabuf_alloc_copy(pos, slen); |
223 | } | |
224 | break; | |
225 | case HS20_STYPE_OPERATING_CLASS: | |
226 | wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR | |
227 | " Operating Class", MAC2STR(sa)); | |
228 | wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); | |
476aed35 JM |
229 | if (anqp) { |
230 | wpabuf_free(anqp->hs20_operating_class); | |
231 | anqp->hs20_operating_class = | |
25471fe3 JK |
232 | wpabuf_alloc_copy(pos, slen); |
233 | } | |
234 | break; | |
235 | default: | |
236 | wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); | |
237 | break; | |
238 | } | |
239 | } | |
95a3ea94 JM |
240 | |
241 | ||
242 | void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s, | |
243 | const char *url, u8 osu_method) | |
244 | { | |
245 | if (url) | |
246 | wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s", | |
247 | osu_method, url); | |
248 | else | |
249 | wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION); | |
250 | } | |
7ef69479 JM |
251 | |
252 | ||
253 | void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, | |
254 | u16 reauth_delay, const char *url) | |
255 | { | |
256 | if (!wpa_sm_pmf_enabled(wpa_s->wpa)) { | |
257 | wpa_printf(MSG_DEBUG, "HS 2.0: Ignore deauthentication imminent notice since PMF was not enabled"); | |
258 | return; | |
259 | } | |
260 | ||
261 | wpa_msg(wpa_s, MSG_INFO, HS20_DEAUTH_IMMINENT_NOTICE "%u %u %s", | |
262 | code, reauth_delay, url); | |
263 | ||
264 | if (code == HS20_DEAUTH_REASON_CODE_BSS) { | |
265 | wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist"); | |
266 | wpa_blacklist_add(wpa_s, wpa_s->bssid); | |
267 | } | |
268 | ||
269 | if (code == HS20_DEAUTH_REASON_CODE_ESS && wpa_s->current_ssid) { | |
270 | struct os_time now; | |
271 | os_get_time(&now); | |
272 | if (now.sec + reauth_delay <= | |
273 | wpa_s->current_ssid->disabled_until.sec) | |
274 | return; | |
275 | wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds", | |
276 | reauth_delay); | |
277 | wpa_s->current_ssid->disabled_until.sec = | |
278 | now.sec + reauth_delay; | |
279 | } | |
280 | } |