1/*
2 * Wi-Fi Protected Setup - device attributes
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
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 "wps_i.h"
13#include "wps_dev_attr.h"
14
15
16int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)
17{
18	size_t len;
19	wpa_printf(MSG_DEBUG, "WPS:  * Manufacturer");
20	wpabuf_put_be16(msg, ATTR_MANUFACTURER);
21	len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
22#ifndef CONFIG_WPS_STRICT
23	if (len == 0) {
24		/*
25		 * Some deployed WPS implementations fail to parse zero-length
26		 * attributes. As a workaround, send a space character if the
27		 * device attribute string is empty.
28		 */
29		wpabuf_put_be16(msg, 1);
30		wpabuf_put_u8(msg, ' ');
31		return 0;
32	}
33#endif /* CONFIG_WPS_STRICT */
34	wpabuf_put_be16(msg, len);
35	wpabuf_put_data(msg, dev->manufacturer, len);
36	return 0;
37}
38
39
40int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)
41{
42	size_t len;
43	wpa_printf(MSG_DEBUG, "WPS:  * Model Name");
44	wpabuf_put_be16(msg, ATTR_MODEL_NAME);
45	len = dev->model_name ? os_strlen(dev->model_name) : 0;
46#ifndef CONFIG_WPS_STRICT
47	if (len == 0) {
48		/*
49		 * Some deployed WPS implementations fail to parse zero-length
50		 * attributes. As a workaround, send a space character if the
51		 * device attribute string is empty.
52		 */
53		wpabuf_put_be16(msg, 1);
54		wpabuf_put_u8(msg, ' ');
55		return 0;
56	}
57#endif /* CONFIG_WPS_STRICT */
58	wpabuf_put_be16(msg, len);
59	wpabuf_put_data(msg, dev->model_name, len);
60	return 0;
61}
62
63
64int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)
65{
66	size_t len;
67	wpa_printf(MSG_DEBUG, "WPS:  * Model Number");
68	wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
69	len = dev->model_number ? os_strlen(dev->model_number) : 0;
70#ifndef CONFIG_WPS_STRICT
71	if (len == 0) {
72		/*
73		 * Some deployed WPS implementations fail to parse zero-length
74		 * attributes. As a workaround, send a space character if the
75		 * device attribute string is empty.
76		 */
77		wpabuf_put_be16(msg, 1);
78		wpabuf_put_u8(msg, ' ');
79		return 0;
80	}
81#endif /* CONFIG_WPS_STRICT */
82	wpabuf_put_be16(msg, len);
83	wpabuf_put_data(msg, dev->model_number, len);
84	return 0;
85}
86
87
88int wps_build_serial_number(struct wps_device_data *dev, struct wpabuf *msg)
89{
90	size_t len;
91	wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
92	wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
93	len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
94#ifndef CONFIG_WPS_STRICT
95	if (len == 0) {
96		/*
97		 * Some deployed WPS implementations fail to parse zero-length
98		 * attributes. As a workaround, send a space character if the
99		 * device attribute string is empty.
100		 */
101		wpabuf_put_be16(msg, 1);
102		wpabuf_put_u8(msg, ' ');
103		return 0;
104	}
105#endif /* CONFIG_WPS_STRICT */
106	wpabuf_put_be16(msg, len);
107	wpabuf_put_data(msg, dev->serial_number, len);
108	return 0;
109}
110
111
112int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
113{
114	wpa_printf(MSG_DEBUG, "WPS:  * Primary Device Type");
115	wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
116	wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
117	wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN);
118	return 0;
119}
120
121
122int wps_build_secondary_dev_type(struct wps_device_data *dev,
123				  struct wpabuf *msg)
124{
125	if (!dev->num_sec_dev_types)
126		return 0;
127
128	wpa_printf(MSG_DEBUG, "WPS:  * Secondary Device Type");
129	wpabuf_put_be16(msg, ATTR_SECONDARY_DEV_TYPE_LIST);
130	wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
131	wpabuf_put_data(msg, dev->sec_dev_type,
132			WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
133
134	return 0;
135}
136
137
138int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
139			   unsigned int num_req_dev_types,
140			   const u8 *req_dev_types)
141{
142	unsigned int i;
143
144	for (i = 0; i < num_req_dev_types; i++) {
145		wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type",
146			    req_dev_types + i * WPS_DEV_TYPE_LEN,
147			    WPS_DEV_TYPE_LEN);
148		wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE);
149		wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
150		wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN,
151				WPS_DEV_TYPE_LEN);
152	}
153
154	return 0;
155}
156
157
158int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
159{
160	size_t len;
161	wpa_printf(MSG_DEBUG, "WPS:  * Device Name");
162	wpabuf_put_be16(msg, ATTR_DEV_NAME);
163	len = dev->device_name ? os_strlen(dev->device_name) : 0;
164#ifndef CONFIG_WPS_STRICT
165	if (len == 0) {
166		/*
167		 * Some deployed WPS implementations fail to parse zero-length
168		 * attributes. As a workaround, send a space character if the
169		 * device attribute string is empty.
170		 */
171		wpabuf_put_be16(msg, 1);
172		wpabuf_put_u8(msg, ' ');
173		return 0;
174	}
175#endif /* CONFIG_WPS_STRICT */
176	wpabuf_put_be16(msg, len);
177	wpabuf_put_data(msg, dev->device_name, len);
178	return 0;
179}
180
181
182int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)
183{
184	if (wps_build_manufacturer(dev, msg) ||
185	    wps_build_model_name(dev, msg) ||
186	    wps_build_model_number(dev, msg) ||
187	    wps_build_serial_number(dev, msg) ||
188	    wps_build_primary_dev_type(dev, msg) ||
189	    wps_build_dev_name(dev, msg))
190		return -1;
191	return 0;
192}
193
194
195int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
196{
197	wpa_printf(MSG_DEBUG, "WPS:  * OS Version");
198	wpabuf_put_be16(msg, ATTR_OS_VERSION);
199	wpabuf_put_be16(msg, 4);
200	wpabuf_put_be32(msg, 0x80000000 | dev->os_version);
201	return 0;
202}
203
204
205int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
206{
207	if (dev->vendor_ext_m1 != NULL) {
208		wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension M1",
209			    wpabuf_head_u8(dev->vendor_ext_m1),
210			    wpabuf_len(dev->vendor_ext_m1));
211		wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
212		wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1));
213		wpabuf_put_buf(msg, dev->vendor_ext_m1);
214	}
215	return 0;
216}
217
218
219int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg,
220		       u8 rf_band)
221{
222	return wps_build_rf_bands_attr(msg, rf_band ? rf_band : dev->rf_bands);
223}
224
225
226int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
227{
228	int i;
229
230	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
231		if (dev->vendor_ext[i] == NULL)
232			continue;
233		wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension",
234			    wpabuf_head_u8(dev->vendor_ext[i]),
235			    wpabuf_len(dev->vendor_ext[i]));
236		wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
237		wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i]));
238		wpabuf_put_buf(msg, dev->vendor_ext[i]);
239	}
240
241	return 0;
242}
243
244
245static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
246				    size_t str_len)
247{
248	if (str == NULL) {
249		wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received");
250		return -1;
251	}
252
253	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
254
255	os_free(dev->manufacturer);
256	dev->manufacturer = dup_binstr(str, str_len);
257	if (dev->manufacturer == NULL)
258		return -1;
259
260	return 0;
261}
262
263
264static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
265				  size_t str_len)
266{
267	if (str == NULL) {
268		wpa_printf(MSG_DEBUG, "WPS: No Model Name received");
269		return -1;
270	}
271
272	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
273
274	os_free(dev->model_name);
275	dev->model_name = dup_binstr(str, str_len);
276	if (dev->model_name == NULL)
277		return -1;
278
279	return 0;
280}
281
282
283static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
284				    size_t str_len)
285{
286	if (str == NULL) {
287		wpa_printf(MSG_DEBUG, "WPS: No Model Number received");
288		return -1;
289	}
290
291	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
292
293	os_free(dev->model_number);
294	dev->model_number = dup_binstr(str, str_len);
295	if (dev->model_number == NULL)
296		return -1;
297
298	return 0;
299}
300
301
302static int wps_process_serial_number(struct wps_device_data *dev,
303				     const u8 *str, size_t str_len)
304{
305	if (str == NULL) {
306		wpa_printf(MSG_DEBUG, "WPS: No Serial Number received");
307		return -1;
308	}
309
310	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
311
312	os_free(dev->serial_number);
313	dev->serial_number = dup_binstr(str, str_len);
314	if (dev->serial_number == NULL)
315		return -1;
316
317	return 0;
318}
319
320
321static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
322				size_t str_len)
323{
324	if (str == NULL) {
325		wpa_printf(MSG_DEBUG, "WPS: No Device Name received");
326		return -1;
327	}
328
329	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
330
331	os_free(dev->device_name);
332	dev->device_name = dup_binstr(str, str_len);
333	if (dev->device_name == NULL)
334		return -1;
335
336	return 0;
337}
338
339
340static int wps_process_primary_dev_type(struct wps_device_data *dev,
341					const u8 *dev_type)
342{
343#ifndef CONFIG_NO_STDOUT_DEBUG
344	char devtype[WPS_DEV_TYPE_BUFSIZE];
345#endif /* CONFIG_NO_STDOUT_DEBUG */
346
347	if (dev_type == NULL) {
348		wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
349		return -1;
350	}
351
352	os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN);
353	wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s",
354		   wps_dev_type_bin2str(dev->pri_dev_type, devtype,
355					sizeof(devtype)));
356
357	return 0;
358}
359
360
361int wps_process_device_attrs(struct wps_device_data *dev,
362			     struct wps_parse_attr *attr)
363{
364	if (wps_process_manufacturer(dev, attr->manufacturer,
365				     attr->manufacturer_len) ||
366	    wps_process_model_name(dev, attr->model_name,
367				   attr->model_name_len) ||
368	    wps_process_model_number(dev, attr->model_number,
369				     attr->model_number_len) ||
370	    wps_process_serial_number(dev, attr->serial_number,
371				      attr->serial_number_len) ||
372	    wps_process_primary_dev_type(dev, attr->primary_dev_type) ||
373	    wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len))
374		return -1;
375	return 0;
376}
377
378
379int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
380{
381	if (ver == NULL) {
382		wpa_printf(MSG_DEBUG, "WPS: No OS Version received");
383		return -1;
384	}
385
386	dev->os_version = WPA_GET_BE32(ver);
387	wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version);
388
389	return 0;
390}
391
392
393int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
394{
395	if (bands == NULL) {
396		wpa_printf(MSG_DEBUG, "WPS: No RF Bands received");
397		return -1;
398	}
399
400	dev->rf_bands = *bands;
401	wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands);
402
403	return 0;
404}
405
406
407void wps_device_data_free(struct wps_device_data *dev)
408{
409	os_free(dev->device_name);
410	dev->device_name = NULL;
411	os_free(dev->manufacturer);
412	dev->manufacturer = NULL;
413	os_free(dev->model_name);
414	dev->model_name = NULL;
415	os_free(dev->model_number);
416	dev->model_number = NULL;
417	os_free(dev->serial_number);
418	dev->serial_number = NULL;
419}
420