xref: /freebsd/contrib/wpa/src/wps/wps_attr_parse.c (revision dd41de95a84d979615a2ef11df6850622bf6184e)
1 /*
2  * Wi-Fi Protected Setup - attribute parsing
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_defs.h"
13 #include "wps_attr_parse.h"
14 
15 #ifndef CONFIG_WPS_STRICT
16 #define WPS_WORKAROUNDS
17 #endif /* CONFIG_WPS_STRICT */
18 
19 
20 static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
21 					  u8 id, u8 len, const u8 *pos)
22 {
23 	wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
24 		   id, len);
25 	switch (id) {
26 	case WFA_ELEM_VERSION2:
27 		if (len != 1) {
28 			wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
29 				   "%u", len);
30 			return -1;
31 		}
32 		attr->version2 = pos;
33 		break;
34 	case WFA_ELEM_AUTHORIZEDMACS:
35 		attr->authorized_macs = pos;
36 		attr->authorized_macs_len = len;
37 		break;
38 	case WFA_ELEM_NETWORK_KEY_SHAREABLE:
39 		if (len != 1) {
40 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
41 				   "Shareable length %u", len);
42 			return -1;
43 		}
44 		attr->network_key_shareable = pos;
45 		break;
46 	case WFA_ELEM_REQUEST_TO_ENROLL:
47 		if (len != 1) {
48 			wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
49 				   "length %u", len);
50 			return -1;
51 		}
52 		attr->request_to_enroll = pos;
53 		break;
54 	case WFA_ELEM_SETTINGS_DELAY_TIME:
55 		if (len != 1) {
56 			wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
57 				   "Time length %u", len);
58 			return -1;
59 		}
60 		attr->settings_delay_time = pos;
61 		break;
62 	case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS:
63 		if (len != 2) {
64 			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u",
65 				   len);
66 			return -1;
67 		}
68 		attr->registrar_configuration_methods = pos;
69 		break;
70 	case WFA_ELEM_MULTI_AP:
71 		if (len != 1) {
72 			wpa_printf(MSG_DEBUG,
73 				   "WPS: Invalid Multi-AP Extension length %u",
74 				   len);
75 			return -1;
76 		}
77 		attr->multi_ap_ext = *pos;
78 		wpa_printf(MSG_DEBUG, "WPS: Multi-AP Extension 0x%02x",
79 			   attr->multi_ap_ext);
80 		break;
81 	default:
82 		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
83 			   "Extension subelement %u", id);
84 		break;
85 	}
86 
87 	return 0;
88 }
89 
90 
91 static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
92 				    u16 len)
93 {
94 	const u8 *end = pos + len;
95 	u8 id, elen;
96 
97 	while (end - pos >= 2) {
98 		id = *pos++;
99 		elen = *pos++;
100 		if (elen > end - pos)
101 			break;
102 		if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
103 			return -1;
104 		pos += elen;
105 	}
106 
107 	return 0;
108 }
109 
110 
111 static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
112 				u16 len)
113 {
114 	u32 vendor_id;
115 
116 	if (len < 3) {
117 		wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
118 		return 0;
119 	}
120 
121 	vendor_id = WPA_GET_BE24(pos);
122 	switch (vendor_id) {
123 	case WPS_VENDOR_ID_WFA:
124 		return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
125 	}
126 
127 	/* Handle unknown vendor extensions */
128 
129 	wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
130 		   vendor_id);
131 
132 	if (len > WPS_MAX_VENDOR_EXT_LEN) {
133 		wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
134 			   len);
135 		return -1;
136 	}
137 
138 	if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
139 		wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
140 			   "attribute (max %d vendor extensions)",
141 			   MAX_WPS_PARSE_VENDOR_EXT);
142 		return -1;
143 	}
144 	attr->vendor_ext[attr->num_vendor_ext] = pos;
145 	attr->vendor_ext_len[attr->num_vendor_ext] = len;
146 	attr->num_vendor_ext++;
147 
148 	return 0;
149 }
150 
151 
152 static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
153 			const u8 *pos, u16 len)
154 {
155 	switch (type) {
156 	case ATTR_VERSION:
157 		if (len != 1) {
158 			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
159 				   len);
160 			return -1;
161 		}
162 		attr->version = pos;
163 		break;
164 	case ATTR_MSG_TYPE:
165 		if (len != 1) {
166 			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
167 				   "length %u", len);
168 			return -1;
169 		}
170 		attr->msg_type = pos;
171 		break;
172 	case ATTR_ENROLLEE_NONCE:
173 		if (len != WPS_NONCE_LEN) {
174 			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
175 				   "length %u", len);
176 			return -1;
177 		}
178 		attr->enrollee_nonce = pos;
179 		break;
180 	case ATTR_REGISTRAR_NONCE:
181 		if (len != WPS_NONCE_LEN) {
182 			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
183 				   "length %u", len);
184 			return -1;
185 		}
186 		attr->registrar_nonce = pos;
187 		break;
188 	case ATTR_UUID_E:
189 		if (len != WPS_UUID_LEN) {
190 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
191 				   len);
192 			return -1;
193 		}
194 		attr->uuid_e = pos;
195 		break;
196 	case ATTR_UUID_R:
197 		if (len != WPS_UUID_LEN) {
198 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
199 				   len);
200 			return -1;
201 		}
202 		attr->uuid_r = pos;
203 		break;
204 	case ATTR_AUTH_TYPE_FLAGS:
205 		if (len != 2) {
206 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
207 				   "Type Flags length %u", len);
208 			return -1;
209 		}
210 		attr->auth_type_flags = pos;
211 		break;
212 	case ATTR_ENCR_TYPE_FLAGS:
213 		if (len != 2) {
214 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
215 				   "Flags length %u", len);
216 			return -1;
217 		}
218 		attr->encr_type_flags = pos;
219 		break;
220 	case ATTR_CONN_TYPE_FLAGS:
221 		if (len != 1) {
222 			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
223 				   "Flags length %u", len);
224 			return -1;
225 		}
226 		attr->conn_type_flags = pos;
227 		break;
228 	case ATTR_CONFIG_METHODS:
229 		if (len != 2) {
230 			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
231 				   "length %u", len);
232 			return -1;
233 		}
234 		attr->config_methods = pos;
235 		break;
236 	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
237 		if (len != 2) {
238 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
239 				   "Registrar Config Methods length %u", len);
240 			return -1;
241 		}
242 		attr->sel_reg_config_methods = pos;
243 		break;
244 	case ATTR_PRIMARY_DEV_TYPE:
245 		if (len != WPS_DEV_TYPE_LEN) {
246 			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
247 				   "Type length %u", len);
248 			return -1;
249 		}
250 		attr->primary_dev_type = pos;
251 		break;
252 	case ATTR_RF_BANDS:
253 		if (len != 1) {
254 			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
255 				   "%u", len);
256 			return -1;
257 		}
258 		attr->rf_bands = pos;
259 		break;
260 	case ATTR_ASSOC_STATE:
261 		if (len != 2) {
262 			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
263 				   "length %u", len);
264 			return -1;
265 		}
266 		attr->assoc_state = pos;
267 		break;
268 	case ATTR_CONFIG_ERROR:
269 		if (len != 2) {
270 			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
271 				   "Error length %u", len);
272 			return -1;
273 		}
274 		attr->config_error = pos;
275 		break;
276 	case ATTR_DEV_PASSWORD_ID:
277 		if (len != 2) {
278 			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
279 				   "ID length %u", len);
280 			return -1;
281 		}
282 		attr->dev_password_id = pos;
283 		break;
284 	case ATTR_OOB_DEVICE_PASSWORD:
285 		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
286 		    len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
287 		    WPS_OOB_DEVICE_PASSWORD_LEN ||
288 		    (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
289 		     WPS_OOB_DEVICE_PASSWORD_MIN_LEN &&
290 		     WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) !=
291 		     DEV_PW_NFC_CONNECTION_HANDOVER)) {
292 			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
293 				   "Password length %u", len);
294 			return -1;
295 		}
296 		attr->oob_dev_password = pos;
297 		attr->oob_dev_password_len = len;
298 		break;
299 	case ATTR_OS_VERSION:
300 		if (len != 4) {
301 			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
302 				   "%u", len);
303 			return -1;
304 		}
305 		attr->os_version = pos;
306 		break;
307 	case ATTR_WPS_STATE:
308 		if (len != 1) {
309 			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
310 				   "Setup State length %u", len);
311 			return -1;
312 		}
313 		attr->wps_state = pos;
314 		break;
315 	case ATTR_AUTHENTICATOR:
316 		if (len != WPS_AUTHENTICATOR_LEN) {
317 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
318 				   "length %u", len);
319 			return -1;
320 		}
321 		attr->authenticator = pos;
322 		break;
323 	case ATTR_R_HASH1:
324 		if (len != WPS_HASH_LEN) {
325 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
326 				   len);
327 			return -1;
328 		}
329 		attr->r_hash1 = pos;
330 		break;
331 	case ATTR_R_HASH2:
332 		if (len != WPS_HASH_LEN) {
333 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
334 				   len);
335 			return -1;
336 		}
337 		attr->r_hash2 = pos;
338 		break;
339 	case ATTR_E_HASH1:
340 		if (len != WPS_HASH_LEN) {
341 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
342 				   len);
343 			return -1;
344 		}
345 		attr->e_hash1 = pos;
346 		break;
347 	case ATTR_E_HASH2:
348 		if (len != WPS_HASH_LEN) {
349 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
350 				   len);
351 			return -1;
352 		}
353 		attr->e_hash2 = pos;
354 		break;
355 	case ATTR_R_SNONCE1:
356 		if (len != WPS_SECRET_NONCE_LEN) {
357 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
358 				   "%u", len);
359 			return -1;
360 		}
361 		attr->r_snonce1 = pos;
362 		break;
363 	case ATTR_R_SNONCE2:
364 		if (len != WPS_SECRET_NONCE_LEN) {
365 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
366 				   "%u", len);
367 			return -1;
368 		}
369 		attr->r_snonce2 = pos;
370 		break;
371 	case ATTR_E_SNONCE1:
372 		if (len != WPS_SECRET_NONCE_LEN) {
373 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
374 				   "%u", len);
375 			return -1;
376 		}
377 		attr->e_snonce1 = pos;
378 		break;
379 	case ATTR_E_SNONCE2:
380 		if (len != WPS_SECRET_NONCE_LEN) {
381 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
382 				   "%u", len);
383 			return -1;
384 		}
385 		attr->e_snonce2 = pos;
386 		break;
387 	case ATTR_KEY_WRAP_AUTH:
388 		if (len != WPS_KWA_LEN) {
389 			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
390 				   "Authenticator length %u", len);
391 			return -1;
392 		}
393 		attr->key_wrap_auth = pos;
394 		break;
395 	case ATTR_AUTH_TYPE:
396 		if (len != 2) {
397 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
398 				   "Type length %u", len);
399 			return -1;
400 		}
401 		attr->auth_type = pos;
402 		break;
403 	case ATTR_ENCR_TYPE:
404 		if (len != 2) {
405 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
406 				   "Type length %u", len);
407 			return -1;
408 		}
409 		attr->encr_type = pos;
410 		break;
411 	case ATTR_NETWORK_INDEX:
412 		if (len != 1) {
413 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
414 				   "length %u", len);
415 			return -1;
416 		}
417 		attr->network_idx = pos;
418 		break;
419 	case ATTR_NETWORK_KEY_INDEX:
420 		if (len != 1) {
421 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
422 				   "length %u", len);
423 			return -1;
424 		}
425 		attr->network_key_idx = pos;
426 		break;
427 	case ATTR_MAC_ADDR:
428 		if (len != ETH_ALEN) {
429 			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
430 				   "length %u", len);
431 			return -1;
432 		}
433 		attr->mac_addr = pos;
434 		break;
435 	case ATTR_SELECTED_REGISTRAR:
436 		if (len != 1) {
437 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
438 				   " length %u", len);
439 			return -1;
440 		}
441 		attr->selected_registrar = pos;
442 		break;
443 	case ATTR_REQUEST_TYPE:
444 		if (len != 1) {
445 			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
446 				   "length %u", len);
447 			return -1;
448 		}
449 		attr->request_type = pos;
450 		break;
451 	case ATTR_RESPONSE_TYPE:
452 		if (len != 1) {
453 			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
454 				   "length %u", len);
455 			return -1;
456 		}
457 		attr->response_type = pos;
458 		break;
459 	case ATTR_MANUFACTURER:
460 		attr->manufacturer = pos;
461 		if (len > WPS_MANUFACTURER_MAX_LEN)
462 			attr->manufacturer_len = WPS_MANUFACTURER_MAX_LEN;
463 		else
464 			attr->manufacturer_len = len;
465 		break;
466 	case ATTR_MODEL_NAME:
467 		attr->model_name = pos;
468 		if (len > WPS_MODEL_NAME_MAX_LEN)
469 			attr->model_name_len = WPS_MODEL_NAME_MAX_LEN;
470 		else
471 			attr->model_name_len = len;
472 		break;
473 	case ATTR_MODEL_NUMBER:
474 		attr->model_number = pos;
475 		if (len > WPS_MODEL_NUMBER_MAX_LEN)
476 			attr->model_number_len = WPS_MODEL_NUMBER_MAX_LEN;
477 		else
478 			attr->model_number_len = len;
479 		break;
480 	case ATTR_SERIAL_NUMBER:
481 		attr->serial_number = pos;
482 		if (len > WPS_SERIAL_NUMBER_MAX_LEN)
483 			attr->serial_number_len = WPS_SERIAL_NUMBER_MAX_LEN;
484 		else
485 			attr->serial_number_len = len;
486 		break;
487 	case ATTR_DEV_NAME:
488 		if (len > WPS_DEV_NAME_MAX_LEN) {
489 			wpa_printf(MSG_DEBUG,
490 				   "WPS: Ignore too long Device Name (len=%u)",
491 				   len);
492 			break;
493 		}
494 		attr->dev_name = pos;
495 		attr->dev_name_len = len;
496 		break;
497 	case ATTR_PUBLIC_KEY:
498 		/*
499 		 * The Public Key attribute is supposed to be exactly 192 bytes
500 		 * in length. Allow couple of bytes shorter one to try to
501 		 * interoperate with implementations that do not use proper
502 		 * zero-padding.
503 		 */
504 		if (len < 190 || len > 192) {
505 			wpa_printf(MSG_DEBUG,
506 				   "WPS: Ignore Public Key with unexpected length %u",
507 				   len);
508 			break;
509 		}
510 		attr->public_key = pos;
511 		attr->public_key_len = len;
512 		break;
513 	case ATTR_ENCR_SETTINGS:
514 		attr->encr_settings = pos;
515 		attr->encr_settings_len = len;
516 		break;
517 	case ATTR_CRED:
518 		if (attr->num_cred >= MAX_CRED_COUNT) {
519 			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
520 				   "attribute (max %d credentials)",
521 				   MAX_CRED_COUNT);
522 			break;
523 		}
524 		attr->cred[attr->num_cred] = pos;
525 		attr->cred_len[attr->num_cred] = len;
526 		attr->num_cred++;
527 		break;
528 	case ATTR_SSID:
529 		if (len > SSID_MAX_LEN) {
530 			wpa_printf(MSG_DEBUG,
531 				   "WPS: Ignore too long SSID (len=%u)", len);
532 			break;
533 		}
534 		attr->ssid = pos;
535 		attr->ssid_len = len;
536 		break;
537 	case ATTR_NETWORK_KEY:
538 		attr->network_key = pos;
539 		attr->network_key_len = len;
540 		break;
541 	case ATTR_AP_SETUP_LOCKED:
542 		if (len != 1) {
543 			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
544 				   "length %u", len);
545 			return -1;
546 		}
547 		attr->ap_setup_locked = pos;
548 		break;
549 	case ATTR_REQUESTED_DEV_TYPE:
550 		if (len != WPS_DEV_TYPE_LEN) {
551 			wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
552 				   "Type length %u", len);
553 			return -1;
554 		}
555 		if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
556 			wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
557 				   "Type attribute (max %u types)",
558 				   MAX_REQ_DEV_TYPE_COUNT);
559 			break;
560 		}
561 		attr->req_dev_type[attr->num_req_dev_type] = pos;
562 		attr->num_req_dev_type++;
563 		break;
564 	case ATTR_SECONDARY_DEV_TYPE_LIST:
565 		if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
566 		    (len % WPS_DEV_TYPE_LEN) > 0) {
567 			wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
568 				   "Type length %u", len);
569 			return -1;
570 		}
571 		attr->sec_dev_type_list = pos;
572 		attr->sec_dev_type_list_len = len;
573 		break;
574 	case ATTR_VENDOR_EXT:
575 		if (wps_parse_vendor_ext(attr, pos, len) < 0)
576 			return -1;
577 		break;
578 	case ATTR_AP_CHANNEL:
579 		if (len != 2) {
580 			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
581 				   "length %u", len);
582 			return -1;
583 		}
584 		attr->ap_channel = pos;
585 		break;
586 	default:
587 		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
588 			   "len=%u", type, len);
589 		break;
590 	}
591 
592 	return 0;
593 }
594 
595 
596 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
597 {
598 	const u8 *pos, *end;
599 	u16 type, len;
600 #ifdef WPS_WORKAROUNDS
601 	u16 prev_type = 0;
602 #endif /* WPS_WORKAROUNDS */
603 
604 	os_memset(attr, 0, sizeof(*attr));
605 	pos = wpabuf_head(msg);
606 	end = pos + wpabuf_len(msg);
607 
608 	while (pos < end) {
609 		if (end - pos < 4) {
610 			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
611 				   "%lu bytes remaining",
612 				   (unsigned long) (end - pos));
613 			return -1;
614 		}
615 
616 		type = WPA_GET_BE16(pos);
617 		pos += 2;
618 		len = WPA_GET_BE16(pos);
619 		pos += 2;
620 		wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
621 			   type, len);
622 		if (len > end - pos) {
623 			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
624 			wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
625 #ifdef WPS_WORKAROUNDS
626 			/*
627 			 * Some deployed APs seem to have a bug in encoding of
628 			 * Network Key attribute in the Credential attribute
629 			 * where they add an extra octet after the Network Key
630 			 * attribute at least when open network is being
631 			 * provisioned.
632 			 */
633 			if ((type & 0xff00) != 0x1000 &&
634 			    prev_type == ATTR_NETWORK_KEY) {
635 				wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
636 					   "to skip unexpected octet after "
637 					   "Network Key");
638 				pos -= 3;
639 				continue;
640 			}
641 #endif /* WPS_WORKAROUNDS */
642 			return -1;
643 		}
644 
645 #ifdef WPS_WORKAROUNDS
646 		if (type == 0 && len == 0) {
647 			/*
648 			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
649 			 * end of M1. Skip those to avoid interop issues.
650 			 */
651 			int i;
652 			for (i = 0; i < end - pos; i++) {
653 				if (pos[i])
654 					break;
655 			}
656 			if (i == end - pos) {
657 				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
658 					   "unexpected message padding");
659 				break;
660 			}
661 		}
662 #endif /* WPS_WORKAROUNDS */
663 
664 		if (wps_set_attr(attr, type, pos, len) < 0)
665 			return -1;
666 
667 #ifdef WPS_WORKAROUNDS
668 		prev_type = type;
669 #endif /* WPS_WORKAROUNDS */
670 		pos += len;
671 	}
672 
673 	return 0;
674 }
675