]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/wps/wps.c
WPS: Added support for fragmented WPS IE in Beacon and Probe Response
[thirdparty/hostap.git] / src / wps / wps.c
1 /*
2 * Wi-Fi Protected Setup
3 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "wps_i.h"
19 #include "wps_dev_attr.h"
20 #include "ieee802_11_defs.h"
21
22
23 struct wps_data * wps_init(const struct wps_config *cfg)
24 {
25 struct wps_data *data = os_zalloc(sizeof(*data));
26 if (data == NULL)
27 return NULL;
28 data->authenticator = cfg->authenticator;
29 data->wps = cfg->wps;
30 data->registrar = cfg->registrar;
31 if (cfg->enrollee_mac_addr)
32 os_memcpy(data->mac_addr_e, cfg->enrollee_mac_addr, ETH_ALEN);
33 if (cfg->uuid) {
34 os_memcpy(cfg->registrar ? data->uuid_r : data->uuid_e,
35 cfg->uuid, WPS_UUID_LEN);
36 }
37 if (cfg->pin) {
38 data->dev_pw_id = DEV_PW_DEFAULT;
39 data->dev_password = os_malloc(cfg->pin_len);
40 if (data->dev_password == NULL) {
41 os_free(data);
42 return NULL;
43 }
44 os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
45 data->dev_password_len = cfg->pin_len;
46 }
47
48 data->pbc = cfg->pbc;
49 if (cfg->pbc) {
50 /* Use special PIN '00000000' for PBC */
51 data->dev_pw_id = DEV_PW_PUSHBUTTON;
52 os_free(data->dev_password);
53 data->dev_password = os_malloc(8);
54 if (data->dev_password == NULL) {
55 os_free(data);
56 return NULL;
57 }
58 os_memset(data->dev_password, '0', 8);
59 data->dev_password_len = 8;
60 }
61
62 data->state = data->registrar ? RECV_M1 : SEND_M1;
63
64 if (cfg->assoc_wps_ie) {
65 struct wps_parse_attr attr;
66 wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
67 cfg->assoc_wps_ie);
68 if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
69 wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
70 "from (Re)AssocReq");
71 } else if (attr.request_type == NULL) {
72 wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
73 "in (Re)AssocReq WPS IE");
74 } else {
75 wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
76 "in (Re)AssocReq WPS IE): %d",
77 *attr.request_type);
78 data->request_type = *attr.request_type;
79 }
80 }
81
82 return data;
83 }
84
85
86 void wps_deinit(struct wps_data *data)
87 {
88 if (data->wps_pin_revealed) {
89 wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
90 "negotiation failed");
91 if (data->registrar)
92 wps_registrar_invalidate_pin(data->registrar,
93 data->uuid_e);
94 } else if (data->registrar)
95 wps_registrar_unlock_pin(data->registrar, data->uuid_e);
96
97 wpabuf_free(data->dh_privkey);
98 wpabuf_free(data->dh_pubkey_e);
99 wpabuf_free(data->dh_pubkey_r);
100 wpabuf_free(data->last_msg);
101 os_free(data->dev_password);
102 os_free(data->new_psk);
103 wps_device_data_free(&data->peer_dev);
104 os_free(data);
105 }
106
107
108 enum wps_process_res wps_process_msg(struct wps_data *wps, u8 op_code,
109 const struct wpabuf *msg)
110 {
111 if (wps->registrar)
112 return wps_registrar_process_msg(wps, op_code, msg);
113 else
114 return wps_enrollee_process_msg(wps, op_code, msg);
115 }
116
117
118 struct wpabuf * wps_get_msg(struct wps_data *wps, u8 *op_code)
119 {
120 if (wps->registrar)
121 return wps_registrar_get_msg(wps, op_code);
122 else
123 return wps_enrollee_get_msg(wps, op_code);
124 }
125
126
127 int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
128 {
129 struct wps_parse_attr attr;
130
131 if (wps_parse_msg(msg, &attr) < 0 ||
132 !attr.selected_registrar || *attr.selected_registrar == 0 ||
133 !attr.sel_reg_config_methods ||
134 !(WPA_GET_BE16(attr.sel_reg_config_methods) &
135 WPS_CONFIG_PUSHBUTTON) ||
136 !attr.dev_password_id ||
137 WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
138 return 0;
139
140 return 1;
141 }
142
143
144 int wps_is_selected_pin_registrar(const struct wpabuf *msg)
145 {
146 struct wps_parse_attr attr;
147
148 if (wps_parse_msg(msg, &attr) < 0 ||
149 !attr.selected_registrar || *attr.selected_registrar == 0 ||
150 !attr.sel_reg_config_methods ||
151 !(WPA_GET_BE16(attr.sel_reg_config_methods) &
152 (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)) ||
153 !attr.dev_password_id ||
154 WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
155 return 0;
156
157 return 1;
158 }
159
160
161 const u8 * wps_get_uuid_e(const struct wpabuf *msg)
162 {
163 struct wps_parse_attr attr;
164
165 if (wps_parse_msg(msg, &attr) < 0)
166 return NULL;
167 return attr.uuid_e;
168 }
169
170
171 struct wpabuf * wps_build_assoc_req_ie(u8 req_type)
172 {
173 struct wpabuf *ie;
174 u8 *len;
175
176 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
177 "Request");
178 ie = wpabuf_alloc(100);
179 if (ie == NULL)
180 return NULL;
181
182 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
183 len = wpabuf_put(ie, 1);
184 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
185
186 if (wps_build_version(ie) ||
187 wps_build_req_type(ie, req_type)) {
188 wpabuf_free(ie);
189 return NULL;
190 }
191
192 *len = wpabuf_len(ie) - 2;
193
194 return ie;
195 }
196
197
198 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
199 const u8 *uuid, u8 req_type)
200 {
201 struct wpabuf *ie;
202 u8 *len;
203 u16 methods;
204
205 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
206
207 ie = wpabuf_alloc(200);
208 if (ie == NULL)
209 return NULL;
210
211 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
212 len = wpabuf_put(ie, 1);
213 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
214
215 if (pbc)
216 methods = WPS_CONFIG_PUSHBUTTON;
217 else
218 methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
219 WPS_CONFIG_KEYPAD;
220
221 if (wps_build_version(ie) ||
222 wps_build_req_type(ie, req_type) ||
223 wps_build_config_methods(ie, methods) ||
224 wps_build_uuid_e(ie, uuid) ||
225 wps_build_primary_dev_type(dev, ie) ||
226 wps_build_rf_bands(dev, ie) ||
227 wps_build_assoc_state(NULL, ie) ||
228 wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
229 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
230 DEV_PW_DEFAULT)) {
231 wpabuf_free(ie);
232 return NULL;
233 }
234
235 *len = wpabuf_len(ie) - 2;
236
237 return ie;
238 }