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