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