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  
wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr * attr,u8 id,u8 len,const u8 * pos)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  
wps_parse_vendor_ext_wfa(struct wps_parse_attr * attr,const u8 * pos,u16 len)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  
wps_parse_vendor_ext(struct wps_parse_attr * attr,const u8 * pos,u16 len)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  
wps_set_attr(struct wps_parse_attr * attr,u16 type,const u8 * pos,u16 len)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  
wps_parse_msg(const struct wpabuf * msg,struct wps_parse_attr * attr)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  	size_t last_nonzero = 0;
603  	const u8 *start;
604  #endif /* WPS_WORKAROUNDS */
605  
606  	os_memset(attr, 0, sizeof(*attr));
607  	pos = wpabuf_head(msg);
608  #ifdef WPS_WORKAROUNDS
609  	start = pos;
610  #endif /* WPS_WORKAROUNDS */
611  	end = pos + wpabuf_len(msg);
612  
613  	while (pos < end) {
614  		if (end - pos < 4) {
615  			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
616  				   "%lu bytes remaining",
617  				   (unsigned long) (end - pos));
618  			return -1;
619  		}
620  
621  		type = WPA_GET_BE16(pos);
622  		pos += 2;
623  		len = WPA_GET_BE16(pos);
624  		pos += 2;
625  		wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
626  			   type, len);
627  		if (len > end - pos) {
628  			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
629  			wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
630  #ifdef WPS_WORKAROUNDS
631  			/*
632  			 * Some deployed APs seem to have a bug in encoding of
633  			 * Network Key attribute in the Credential attribute
634  			 * where they add an extra octet after the Network Key
635  			 * attribute at least when open network is being
636  			 * provisioned.
637  			 */
638  			if ((type & 0xff00) != 0x1000 &&
639  			    prev_type == ATTR_NETWORK_KEY) {
640  				wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
641  					   "to skip unexpected octet after "
642  					   "Network Key");
643  				pos -= 3;
644  				continue;
645  			}
646  #endif /* WPS_WORKAROUNDS */
647  			return -1;
648  		}
649  
650  #ifdef WPS_WORKAROUNDS
651  		if (type == 0 && len == 0) {
652  			/*
653  			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
654  			 * end of M1. Skip those to avoid interop issues.
655  			 */
656  			int i;
657  
658  			if (last_nonzero > (size_t) (pos - start))
659  				continue;
660  
661  			for (i = 0; i < end - pos; i++) {
662  				if (pos[i]) {
663  					last_nonzero = pos - start + i;
664  					break;
665  				}
666  			}
667  			if (i == end - pos) {
668  				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
669  					   "unexpected message padding");
670  				break;
671  			}
672  		}
673  #endif /* WPS_WORKAROUNDS */
674  
675  		if (wps_set_attr(attr, type, pos, len) < 0)
676  			return -1;
677  
678  #ifdef WPS_WORKAROUNDS
679  		prev_type = type;
680  #endif /* WPS_WORKAROUNDS */
681  		pos += len;
682  	}
683  
684  	return 0;
685  }
686