xref: /dflybsd-src/contrib/wpa_supplicant/src/wps/wps.c (revision 6d49e1aea1f916afb9e202b8d2ad09cfab6e48c3)
1*6d49e1aeSJan Lentfer /*
2*6d49e1aeSJan Lentfer  * Wi-Fi Protected Setup
3*6d49e1aeSJan Lentfer  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
4*6d49e1aeSJan Lentfer  *
5*6d49e1aeSJan Lentfer  * This program is free software; you can redistribute it and/or modify
6*6d49e1aeSJan Lentfer  * it under the terms of the GNU General Public License version 2 as
7*6d49e1aeSJan Lentfer  * published by the Free Software Foundation.
8*6d49e1aeSJan Lentfer  *
9*6d49e1aeSJan Lentfer  * Alternatively, this software may be distributed under the terms of BSD
10*6d49e1aeSJan Lentfer  * license.
11*6d49e1aeSJan Lentfer  *
12*6d49e1aeSJan Lentfer  * See README and COPYING for more details.
13*6d49e1aeSJan Lentfer  */
14*6d49e1aeSJan Lentfer 
15*6d49e1aeSJan Lentfer #include "includes.h"
16*6d49e1aeSJan Lentfer 
17*6d49e1aeSJan Lentfer #include "common.h"
18*6d49e1aeSJan Lentfer #include "wps_i.h"
19*6d49e1aeSJan Lentfer #include "wps_dev_attr.h"
20*6d49e1aeSJan Lentfer #include "ieee802_11_defs.h"
21*6d49e1aeSJan Lentfer 
22*6d49e1aeSJan Lentfer 
23*6d49e1aeSJan Lentfer /**
24*6d49e1aeSJan Lentfer  * wps_init - Initialize WPS Registration protocol data
25*6d49e1aeSJan Lentfer  * @cfg: WPS configuration
26*6d49e1aeSJan Lentfer  * Returns: Pointer to allocated data or %NULL on failure
27*6d49e1aeSJan Lentfer  *
28*6d49e1aeSJan Lentfer  * This function is used to initialize WPS data for a registration protocol
29*6d49e1aeSJan Lentfer  * instance (i.e., each run of registration protocol as a Registrar of
30*6d49e1aeSJan Lentfer  * Enrollee. The caller is responsible for freeing this data after the
31*6d49e1aeSJan Lentfer  * registration run has been completed by calling wps_deinit().
32*6d49e1aeSJan Lentfer  */
33*6d49e1aeSJan Lentfer struct wps_data * wps_init(const struct wps_config *cfg)
34*6d49e1aeSJan Lentfer {
35*6d49e1aeSJan Lentfer 	struct wps_data *data = os_zalloc(sizeof(*data));
36*6d49e1aeSJan Lentfer 	if (data == NULL)
37*6d49e1aeSJan Lentfer 		return NULL;
38*6d49e1aeSJan Lentfer 	data->wps = cfg->wps;
39*6d49e1aeSJan Lentfer 	data->registrar = cfg->registrar;
40*6d49e1aeSJan Lentfer 	if (cfg->registrar) {
41*6d49e1aeSJan Lentfer 		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
42*6d49e1aeSJan Lentfer 	} else {
43*6d49e1aeSJan Lentfer 		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
44*6d49e1aeSJan Lentfer 		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
45*6d49e1aeSJan Lentfer 	}
46*6d49e1aeSJan Lentfer 	if (cfg->pin) {
47*6d49e1aeSJan Lentfer 		data->dev_pw_id = DEV_PW_DEFAULT;
48*6d49e1aeSJan Lentfer 		data->dev_password = os_malloc(cfg->pin_len);
49*6d49e1aeSJan Lentfer 		if (data->dev_password == NULL) {
50*6d49e1aeSJan Lentfer 			os_free(data);
51*6d49e1aeSJan Lentfer 			return NULL;
52*6d49e1aeSJan Lentfer 		}
53*6d49e1aeSJan Lentfer 		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
54*6d49e1aeSJan Lentfer 		data->dev_password_len = cfg->pin_len;
55*6d49e1aeSJan Lentfer 	}
56*6d49e1aeSJan Lentfer 
57*6d49e1aeSJan Lentfer 	data->pbc = cfg->pbc;
58*6d49e1aeSJan Lentfer 	if (cfg->pbc) {
59*6d49e1aeSJan Lentfer 		/* Use special PIN '00000000' for PBC */
60*6d49e1aeSJan Lentfer 		data->dev_pw_id = DEV_PW_PUSHBUTTON;
61*6d49e1aeSJan Lentfer 		os_free(data->dev_password);
62*6d49e1aeSJan Lentfer 		data->dev_password = os_malloc(8);
63*6d49e1aeSJan Lentfer 		if (data->dev_password == NULL) {
64*6d49e1aeSJan Lentfer 			os_free(data);
65*6d49e1aeSJan Lentfer 			return NULL;
66*6d49e1aeSJan Lentfer 		}
67*6d49e1aeSJan Lentfer 		os_memset(data->dev_password, '0', 8);
68*6d49e1aeSJan Lentfer 		data->dev_password_len = 8;
69*6d49e1aeSJan Lentfer 	}
70*6d49e1aeSJan Lentfer 
71*6d49e1aeSJan Lentfer 	data->state = data->registrar ? RECV_M1 : SEND_M1;
72*6d49e1aeSJan Lentfer 
73*6d49e1aeSJan Lentfer 	if (cfg->assoc_wps_ie) {
74*6d49e1aeSJan Lentfer 		struct wps_parse_attr attr;
75*6d49e1aeSJan Lentfer 		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
76*6d49e1aeSJan Lentfer 				cfg->assoc_wps_ie);
77*6d49e1aeSJan Lentfer 		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
78*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
79*6d49e1aeSJan Lentfer 				   "from (Re)AssocReq");
80*6d49e1aeSJan Lentfer 		} else if (attr.request_type == NULL) {
81*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
82*6d49e1aeSJan Lentfer 				   "in (Re)AssocReq WPS IE");
83*6d49e1aeSJan Lentfer 		} else {
84*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
85*6d49e1aeSJan Lentfer 				   "in (Re)AssocReq WPS IE): %d",
86*6d49e1aeSJan Lentfer 				   *attr.request_type);
87*6d49e1aeSJan Lentfer 			data->request_type = *attr.request_type;
88*6d49e1aeSJan Lentfer 		}
89*6d49e1aeSJan Lentfer 	}
90*6d49e1aeSJan Lentfer 
91*6d49e1aeSJan Lentfer 	return data;
92*6d49e1aeSJan Lentfer }
93*6d49e1aeSJan Lentfer 
94*6d49e1aeSJan Lentfer 
95*6d49e1aeSJan Lentfer /**
96*6d49e1aeSJan Lentfer  * wps_deinit - Deinitialize WPS Registration protocol data
97*6d49e1aeSJan Lentfer  * @data: WPS Registration protocol data from wps_init()
98*6d49e1aeSJan Lentfer  */
99*6d49e1aeSJan Lentfer void wps_deinit(struct wps_data *data)
100*6d49e1aeSJan Lentfer {
101*6d49e1aeSJan Lentfer 	if (data->wps_pin_revealed) {
102*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
103*6d49e1aeSJan Lentfer 			   "negotiation failed");
104*6d49e1aeSJan Lentfer 		if (data->registrar)
105*6d49e1aeSJan Lentfer 			wps_registrar_invalidate_pin(data->wps->registrar,
106*6d49e1aeSJan Lentfer 						     data->uuid_e);
107*6d49e1aeSJan Lentfer 	} else if (data->registrar)
108*6d49e1aeSJan Lentfer 		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
109*6d49e1aeSJan Lentfer 
110*6d49e1aeSJan Lentfer 	wpabuf_free(data->dh_privkey);
111*6d49e1aeSJan Lentfer 	wpabuf_free(data->dh_pubkey_e);
112*6d49e1aeSJan Lentfer 	wpabuf_free(data->dh_pubkey_r);
113*6d49e1aeSJan Lentfer 	wpabuf_free(data->last_msg);
114*6d49e1aeSJan Lentfer 	os_free(data->dev_password);
115*6d49e1aeSJan Lentfer 	os_free(data->new_psk);
116*6d49e1aeSJan Lentfer 	wps_device_data_free(&data->peer_dev);
117*6d49e1aeSJan Lentfer 	os_free(data);
118*6d49e1aeSJan Lentfer }
119*6d49e1aeSJan Lentfer 
120*6d49e1aeSJan Lentfer 
121*6d49e1aeSJan Lentfer /**
122*6d49e1aeSJan Lentfer  * wps_process_msg - Process a WPS message
123*6d49e1aeSJan Lentfer  * @wps: WPS Registration protocol data from wps_init()
124*6d49e1aeSJan Lentfer  * @op_code: Message OP Code
125*6d49e1aeSJan Lentfer  * @msg: Message data
126*6d49e1aeSJan Lentfer  * Returns: Processing result
127*6d49e1aeSJan Lentfer  *
128*6d49e1aeSJan Lentfer  * This function is used to process WPS messages with OP Codes WSC_ACK,
129*6d49e1aeSJan Lentfer  * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
130*6d49e1aeSJan Lentfer  * responsible for reassembling the messages before calling this function.
131*6d49e1aeSJan Lentfer  * Response to this message is built by calling wps_get_msg().
132*6d49e1aeSJan Lentfer  */
133*6d49e1aeSJan Lentfer enum wps_process_res wps_process_msg(struct wps_data *wps,
134*6d49e1aeSJan Lentfer 				     enum wsc_op_code op_code,
135*6d49e1aeSJan Lentfer 				     const struct wpabuf *msg)
136*6d49e1aeSJan Lentfer {
137*6d49e1aeSJan Lentfer 	if (wps->registrar)
138*6d49e1aeSJan Lentfer 		return wps_registrar_process_msg(wps, op_code, msg);
139*6d49e1aeSJan Lentfer 	else
140*6d49e1aeSJan Lentfer 		return wps_enrollee_process_msg(wps, op_code, msg);
141*6d49e1aeSJan Lentfer }
142*6d49e1aeSJan Lentfer 
143*6d49e1aeSJan Lentfer 
144*6d49e1aeSJan Lentfer /**
145*6d49e1aeSJan Lentfer  * wps_get_msg - Build a WPS message
146*6d49e1aeSJan Lentfer  * @wps: WPS Registration protocol data from wps_init()
147*6d49e1aeSJan Lentfer  * @op_code: Buffer for returning message OP Code
148*6d49e1aeSJan Lentfer  * Returns: The generated WPS message or %NULL on failure
149*6d49e1aeSJan Lentfer  *
150*6d49e1aeSJan Lentfer  * This function is used to build a response to a message processed by calling
151*6d49e1aeSJan Lentfer  * wps_process_msg(). The caller is responsible for freeing the buffer.
152*6d49e1aeSJan Lentfer  */
153*6d49e1aeSJan Lentfer struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
154*6d49e1aeSJan Lentfer {
155*6d49e1aeSJan Lentfer 	if (wps->registrar)
156*6d49e1aeSJan Lentfer 		return wps_registrar_get_msg(wps, op_code);
157*6d49e1aeSJan Lentfer 	else
158*6d49e1aeSJan Lentfer 		return wps_enrollee_get_msg(wps, op_code);
159*6d49e1aeSJan Lentfer }
160*6d49e1aeSJan Lentfer 
161*6d49e1aeSJan Lentfer 
162*6d49e1aeSJan Lentfer /**
163*6d49e1aeSJan Lentfer  * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
164*6d49e1aeSJan Lentfer  * @msg: WPS IE contents from Beacon or Probe Response frame
165*6d49e1aeSJan Lentfer  * Returns: 1 if PBC Registrar is active, 0 if not
166*6d49e1aeSJan Lentfer  */
167*6d49e1aeSJan Lentfer int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
168*6d49e1aeSJan Lentfer {
169*6d49e1aeSJan Lentfer 	struct wps_parse_attr attr;
170*6d49e1aeSJan Lentfer 
171*6d49e1aeSJan Lentfer 	/*
172*6d49e1aeSJan Lentfer 	 * In theory, this could also verify that attr.sel_reg_config_methods
173*6d49e1aeSJan Lentfer 	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
174*6d49e1aeSJan Lentfer 	 * do not set Selected Registrar Config Methods attribute properly, so
175*6d49e1aeSJan Lentfer 	 * it is safer to just use Device Password ID here.
176*6d49e1aeSJan Lentfer 	 */
177*6d49e1aeSJan Lentfer 
178*6d49e1aeSJan Lentfer 	if (wps_parse_msg(msg, &attr) < 0 ||
179*6d49e1aeSJan Lentfer 	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
180*6d49e1aeSJan Lentfer 	    !attr.dev_password_id ||
181*6d49e1aeSJan Lentfer 	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
182*6d49e1aeSJan Lentfer 		return 0;
183*6d49e1aeSJan Lentfer 
184*6d49e1aeSJan Lentfer 	return 1;
185*6d49e1aeSJan Lentfer }
186*6d49e1aeSJan Lentfer 
187*6d49e1aeSJan Lentfer 
188*6d49e1aeSJan Lentfer /**
189*6d49e1aeSJan Lentfer  * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
190*6d49e1aeSJan Lentfer  * @msg: WPS IE contents from Beacon or Probe Response frame
191*6d49e1aeSJan Lentfer  * Returns: 1 if PIN Registrar is active, 0 if not
192*6d49e1aeSJan Lentfer  */
193*6d49e1aeSJan Lentfer int wps_is_selected_pin_registrar(const struct wpabuf *msg)
194*6d49e1aeSJan Lentfer {
195*6d49e1aeSJan Lentfer 	struct wps_parse_attr attr;
196*6d49e1aeSJan Lentfer 
197*6d49e1aeSJan Lentfer 	/*
198*6d49e1aeSJan Lentfer 	 * In theory, this could also verify that attr.sel_reg_config_methods
199*6d49e1aeSJan Lentfer 	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
200*6d49e1aeSJan Lentfer 	 * but some deployed AP implementations do not set Selected Registrar
201*6d49e1aeSJan Lentfer 	 * Config Methods attribute properly, so it is safer to just use
202*6d49e1aeSJan Lentfer 	 * Device Password ID here.
203*6d49e1aeSJan Lentfer 	 */
204*6d49e1aeSJan Lentfer 
205*6d49e1aeSJan Lentfer 	if (wps_parse_msg(msg, &attr) < 0)
206*6d49e1aeSJan Lentfer 		return 0;
207*6d49e1aeSJan Lentfer 
208*6d49e1aeSJan Lentfer 	if (!attr.selected_registrar || *attr.selected_registrar == 0)
209*6d49e1aeSJan Lentfer 		return 0;
210*6d49e1aeSJan Lentfer 
211*6d49e1aeSJan Lentfer 	if (attr.dev_password_id != NULL &&
212*6d49e1aeSJan Lentfer 	    WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
213*6d49e1aeSJan Lentfer 		return 0;
214*6d49e1aeSJan Lentfer 
215*6d49e1aeSJan Lentfer 	return 1;
216*6d49e1aeSJan Lentfer }
217*6d49e1aeSJan Lentfer 
218*6d49e1aeSJan Lentfer 
219*6d49e1aeSJan Lentfer /**
220*6d49e1aeSJan Lentfer  * wps_get_uuid_e - Get UUID-E from WPS IE
221*6d49e1aeSJan Lentfer  * @msg: WPS IE contents from Beacon or Probe Response frame
222*6d49e1aeSJan Lentfer  * Returns: Pointer to UUID-E or %NULL if not included
223*6d49e1aeSJan Lentfer  *
224*6d49e1aeSJan Lentfer  * The returned pointer is to the msg contents and it remains valid only as
225*6d49e1aeSJan Lentfer  * long as the msg buffer is valid.
226*6d49e1aeSJan Lentfer  */
227*6d49e1aeSJan Lentfer const u8 * wps_get_uuid_e(const struct wpabuf *msg)
228*6d49e1aeSJan Lentfer {
229*6d49e1aeSJan Lentfer 	struct wps_parse_attr attr;
230*6d49e1aeSJan Lentfer 
231*6d49e1aeSJan Lentfer 	if (wps_parse_msg(msg, &attr) < 0)
232*6d49e1aeSJan Lentfer 		return NULL;
233*6d49e1aeSJan Lentfer 	return attr.uuid_e;
234*6d49e1aeSJan Lentfer }
235*6d49e1aeSJan Lentfer 
236*6d49e1aeSJan Lentfer 
237*6d49e1aeSJan Lentfer /**
238*6d49e1aeSJan Lentfer  * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
239*6d49e1aeSJan Lentfer  * @req_type: Value for Request Type attribute
240*6d49e1aeSJan Lentfer  * Returns: WPS IE or %NULL on failure
241*6d49e1aeSJan Lentfer  *
242*6d49e1aeSJan Lentfer  * The caller is responsible for freeing the buffer.
243*6d49e1aeSJan Lentfer  */
244*6d49e1aeSJan Lentfer struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
245*6d49e1aeSJan Lentfer {
246*6d49e1aeSJan Lentfer 	struct wpabuf *ie;
247*6d49e1aeSJan Lentfer 	u8 *len;
248*6d49e1aeSJan Lentfer 
249*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
250*6d49e1aeSJan Lentfer 		   "Request");
251*6d49e1aeSJan Lentfer 	ie = wpabuf_alloc(100);
252*6d49e1aeSJan Lentfer 	if (ie == NULL)
253*6d49e1aeSJan Lentfer 		return NULL;
254*6d49e1aeSJan Lentfer 
255*6d49e1aeSJan Lentfer 	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
256*6d49e1aeSJan Lentfer 	len = wpabuf_put(ie, 1);
257*6d49e1aeSJan Lentfer 	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
258*6d49e1aeSJan Lentfer 
259*6d49e1aeSJan Lentfer 	if (wps_build_version(ie) ||
260*6d49e1aeSJan Lentfer 	    wps_build_req_type(ie, req_type)) {
261*6d49e1aeSJan Lentfer 		wpabuf_free(ie);
262*6d49e1aeSJan Lentfer 		return NULL;
263*6d49e1aeSJan Lentfer 	}
264*6d49e1aeSJan Lentfer 
265*6d49e1aeSJan Lentfer 	*len = wpabuf_len(ie) - 2;
266*6d49e1aeSJan Lentfer 
267*6d49e1aeSJan Lentfer 	return ie;
268*6d49e1aeSJan Lentfer }
269*6d49e1aeSJan Lentfer 
270*6d49e1aeSJan Lentfer 
271*6d49e1aeSJan Lentfer /**
272*6d49e1aeSJan Lentfer  * wps_build_probe_req_ie - Build WPS IE for Probe Request
273*6d49e1aeSJan Lentfer  * @pbc: Whether searching for PBC mode APs
274*6d49e1aeSJan Lentfer  * @dev: Device attributes
275*6d49e1aeSJan Lentfer  * @uuid: Own UUID
276*6d49e1aeSJan Lentfer  * @req_type: Value for Request Type attribute
277*6d49e1aeSJan Lentfer  * Returns: WPS IE or %NULL on failure
278*6d49e1aeSJan Lentfer  *
279*6d49e1aeSJan Lentfer  * The caller is responsible for freeing the buffer.
280*6d49e1aeSJan Lentfer  */
281*6d49e1aeSJan Lentfer struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
282*6d49e1aeSJan Lentfer 				       const u8 *uuid,
283*6d49e1aeSJan Lentfer 				       enum wps_request_type req_type)
284*6d49e1aeSJan Lentfer {
285*6d49e1aeSJan Lentfer 	struct wpabuf *ie;
286*6d49e1aeSJan Lentfer 	u8 *len;
287*6d49e1aeSJan Lentfer 	u16 methods;
288*6d49e1aeSJan Lentfer 
289*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
290*6d49e1aeSJan Lentfer 
291*6d49e1aeSJan Lentfer 	ie = wpabuf_alloc(200);
292*6d49e1aeSJan Lentfer 	if (ie == NULL)
293*6d49e1aeSJan Lentfer 		return NULL;
294*6d49e1aeSJan Lentfer 
295*6d49e1aeSJan Lentfer 	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
296*6d49e1aeSJan Lentfer 	len = wpabuf_put(ie, 1);
297*6d49e1aeSJan Lentfer 	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
298*6d49e1aeSJan Lentfer 
299*6d49e1aeSJan Lentfer 	if (pbc)
300*6d49e1aeSJan Lentfer 		methods = WPS_CONFIG_PUSHBUTTON;
301*6d49e1aeSJan Lentfer 	else
302*6d49e1aeSJan Lentfer 		methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
303*6d49e1aeSJan Lentfer 			WPS_CONFIG_KEYPAD;
304*6d49e1aeSJan Lentfer 
305*6d49e1aeSJan Lentfer 	if (wps_build_version(ie) ||
306*6d49e1aeSJan Lentfer 	    wps_build_req_type(ie, req_type) ||
307*6d49e1aeSJan Lentfer 	    wps_build_config_methods(ie, methods) ||
308*6d49e1aeSJan Lentfer 	    wps_build_uuid_e(ie, uuid) ||
309*6d49e1aeSJan Lentfer 	    wps_build_primary_dev_type(dev, ie) ||
310*6d49e1aeSJan Lentfer 	    wps_build_rf_bands(dev, ie) ||
311*6d49e1aeSJan Lentfer 	    wps_build_assoc_state(NULL, ie) ||
312*6d49e1aeSJan Lentfer 	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
313*6d49e1aeSJan Lentfer 	    wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
314*6d49e1aeSJan Lentfer 				      DEV_PW_DEFAULT)) {
315*6d49e1aeSJan Lentfer 		wpabuf_free(ie);
316*6d49e1aeSJan Lentfer 		return NULL;
317*6d49e1aeSJan Lentfer 	}
318*6d49e1aeSJan Lentfer 
319*6d49e1aeSJan Lentfer 	*len = wpabuf_len(ie) - 2;
320*6d49e1aeSJan Lentfer 
321*6d49e1aeSJan Lentfer 	return ie;
322*6d49e1aeSJan Lentfer }
323*6d49e1aeSJan Lentfer 
324*6d49e1aeSJan Lentfer 
325*6d49e1aeSJan Lentfer void wps_free_pending_msgs(struct upnp_pending_message *msgs)
326*6d49e1aeSJan Lentfer {
327*6d49e1aeSJan Lentfer 	struct upnp_pending_message *p, *prev;
328*6d49e1aeSJan Lentfer 	p = msgs;
329*6d49e1aeSJan Lentfer 	while (p) {
330*6d49e1aeSJan Lentfer 		prev = p;
331*6d49e1aeSJan Lentfer 		p = p->next;
332*6d49e1aeSJan Lentfer 		wpabuf_free(prev->msg);
333*6d49e1aeSJan Lentfer 		os_free(prev);
334*6d49e1aeSJan Lentfer 	}
335*6d49e1aeSJan Lentfer }
336