/src/hostap/src/p2p/p2p_parse.c
Line | Count | Source |
1 | | /* |
2 | | * P2P - IE parser |
3 | | * Copyright (c) 2009-2010, Atheros Communications |
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 "common/ieee802_11_defs.h" |
13 | | #include "common/ieee802_11_common.h" |
14 | | #include "wps/wps_i.h" |
15 | | #include "p2p_i.h" |
16 | | |
17 | | |
18 | | void p2p_copy_filter_devname(char *dst, size_t dst_len, |
19 | | const void *src, size_t src_len) |
20 | 1.79k | { |
21 | 1.79k | size_t i; |
22 | | |
23 | 1.79k | if (src_len >= dst_len) |
24 | 0 | src_len = dst_len - 1; |
25 | 1.79k | os_memcpy(dst, src, src_len); |
26 | 1.79k | dst[src_len] = '\0'; |
27 | 14.1k | for (i = 0; i < src_len; i++) { |
28 | 13.0k | if (dst[i] == '\0') |
29 | 659 | break; |
30 | 12.3k | if (is_ctrl_char(dst[i])) |
31 | 2.56k | dst[i] = '_'; |
32 | 12.3k | } |
33 | 1.79k | } |
34 | | |
35 | | |
36 | | static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, |
37 | | struct p2p_message *msg) |
38 | 20.5k | { |
39 | 20.5k | const u8 *pos; |
40 | 20.5k | u16 nlen; |
41 | 20.5k | char devtype[WPS_DEV_TYPE_BUFSIZE]; |
42 | | |
43 | 20.5k | switch (id) { |
44 | 481 | case P2P_ATTR_CAPABILITY: |
45 | 481 | if (len < 2) { |
46 | 14 | wpa_printf(MSG_DEBUG, "P2P: Too short Capability " |
47 | 14 | "attribute (length %d)", len); |
48 | 14 | return -1; |
49 | 14 | } |
50 | 467 | msg->capability = data; |
51 | 467 | wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x " |
52 | 467 | "Group Capability %02x", |
53 | 467 | data[0], data[1]); |
54 | 467 | break; |
55 | 3.50k | case P2P_ATTR_DEVICE_ID: |
56 | 3.50k | if (len < ETH_ALEN) { |
57 | 15 | wpa_printf(MSG_DEBUG, "P2P: Too short Device ID " |
58 | 15 | "attribute (length %d)", len); |
59 | 15 | return -1; |
60 | 15 | } |
61 | 3.48k | msg->device_id = data; |
62 | 3.48k | wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR, |
63 | 3.48k | MAC2STR(msg->device_id)); |
64 | 3.48k | break; |
65 | 251 | case P2P_ATTR_GROUP_OWNER_INTENT: |
66 | 251 | if (len < 1) { |
67 | 9 | wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent " |
68 | 9 | "attribute (length %d)", len); |
69 | 9 | return -1; |
70 | 9 | } |
71 | 242 | msg->go_intent = data; |
72 | 242 | wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u " |
73 | 242 | "Tie breaker %u", data[0] >> 1, data[0] & 0x01); |
74 | 242 | break; |
75 | 867 | case P2P_ATTR_STATUS: |
76 | 867 | if (len < 1) { |
77 | 78 | wpa_printf(MSG_DEBUG, "P2P: Too short Status " |
78 | 78 | "attribute (length %d)", len); |
79 | 78 | return -1; |
80 | 78 | } |
81 | 789 | msg->status = data; |
82 | 789 | wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]); |
83 | 789 | break; |
84 | 1.78k | case P2P_ATTR_LISTEN_CHANNEL: |
85 | 1.78k | if (len == 0) { |
86 | 196 | wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore " |
87 | 196 | "null channel"); |
88 | 196 | break; |
89 | 196 | } |
90 | 1.58k | if (len < 5) { |
91 | 12 | wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel " |
92 | 12 | "attribute (length %d)", len); |
93 | 12 | return -1; |
94 | 12 | } |
95 | 1.57k | msg->listen_channel = data; |
96 | 1.57k | if (has_ctrl_char(data, 2)) { |
97 | 620 | wpa_printf(MSG_DEBUG, |
98 | 620 | "P2P: * Listen Channel: Country(binary) %02x %02x (0x%02x) Regulatory Class %d Channel Number %d", |
99 | 620 | data[0], data[1], data[2], data[3], data[4]); |
100 | 620 | break; |
101 | 620 | } |
102 | 953 | wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: " |
103 | 953 | "Country %c%c(0x%02x) Regulatory " |
104 | 953 | "Class %d Channel Number %d", data[0], data[1], |
105 | 953 | data[2], data[3], data[4]); |
106 | 953 | break; |
107 | 1.23k | case P2P_ATTR_OPERATING_CHANNEL: |
108 | 1.23k | if (len == 0) { |
109 | 242 | wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " |
110 | 242 | "Ignore null channel"); |
111 | 242 | break; |
112 | 242 | } |
113 | 992 | if (len < 5) { |
114 | 10 | wpa_printf(MSG_DEBUG, "P2P: Too short Operating " |
115 | 10 | "Channel attribute (length %d)", len); |
116 | 10 | return -1; |
117 | 10 | } |
118 | 982 | msg->operating_channel = data; |
119 | 982 | if (has_ctrl_char(data, 2)) { |
120 | 552 | wpa_printf(MSG_DEBUG, |
121 | 552 | "P2P: * Operating Channel: Country(binary) %02x %02x (0x%02x) Regulatory Class %d Channel Number %d", |
122 | 552 | data[0], data[1], data[2], data[3], data[4]); |
123 | 552 | break; |
124 | 552 | } |
125 | 430 | wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " |
126 | 430 | "Country %c%c(0x%02x) Regulatory " |
127 | 430 | "Class %d Channel Number %d", data[0], data[1], |
128 | 430 | data[2], data[3], data[4]); |
129 | 430 | break; |
130 | 1.19k | case P2P_ATTR_CHANNEL_LIST: |
131 | 1.19k | if (len < 3) { |
132 | 8 | wpa_printf(MSG_DEBUG, "P2P: Too short Channel List " |
133 | 8 | "attribute (length %d)", len); |
134 | 8 | return -1; |
135 | 8 | } |
136 | 1.18k | msg->channel_list = data; |
137 | 1.18k | msg->channel_list_len = len; |
138 | 1.18k | if (has_ctrl_char(data, 2)) { |
139 | 769 | wpa_printf(MSG_DEBUG, |
140 | 769 | "P2P: * Channel List: Country String (binary) %02x %02x (0x%02x)", |
141 | 769 | data[0], data[1], data[2]); |
142 | 769 | } else { |
143 | 415 | wpa_printf(MSG_DEBUG, |
144 | 415 | "P2P: * Channel List: Country String '%c%c(0x%02x)'", |
145 | 415 | data[0], data[1], data[2]); |
146 | 415 | } |
147 | 1.18k | wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", |
148 | 1.18k | msg->channel_list, msg->channel_list_len); |
149 | 1.18k | break; |
150 | 551 | case P2P_ATTR_GROUP_INFO: |
151 | 551 | msg->group_info = data; |
152 | 551 | msg->group_info_len = len; |
153 | 551 | wpa_printf(MSG_DEBUG, "P2P: * Group Info"); |
154 | 551 | break; |
155 | 1.83k | case P2P_ATTR_DEVICE_INFO: |
156 | 1.83k | if (len < ETH_ALEN + 2 + 8 + 1) { |
157 | 18 | wpa_printf(MSG_DEBUG, "P2P: Too short Device Info " |
158 | 18 | "attribute (length %d)", len); |
159 | 18 | return -1; |
160 | 18 | } |
161 | 1.81k | msg->p2p_device_info = data; |
162 | 1.81k | msg->p2p_device_info_len = len; |
163 | 1.81k | pos = data; |
164 | 1.81k | msg->p2p_device_addr = pos; |
165 | 1.81k | pos += ETH_ALEN; |
166 | 1.81k | msg->config_methods = WPA_GET_BE16(pos); |
167 | 1.81k | pos += 2; |
168 | 1.81k | msg->pri_dev_type = pos; |
169 | 1.81k | pos += 8; |
170 | 1.81k | msg->num_sec_dev_types = *pos++; |
171 | 1.81k | if (msg->num_sec_dev_types * 8 > data + len - pos) { |
172 | 36 | wpa_printf(MSG_DEBUG, "P2P: Device Info underflow"); |
173 | 36 | return -1; |
174 | 36 | } |
175 | 1.77k | pos += msg->num_sec_dev_types * 8; |
176 | 1.77k | if (data + len - pos < 4) { |
177 | 10 | wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " |
178 | 10 | "length %d", (int) (data + len - pos)); |
179 | 10 | return -1; |
180 | 10 | } |
181 | 1.76k | if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) { |
182 | 66 | wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name " |
183 | 66 | "header", pos, 4); |
184 | 66 | return -1; |
185 | 66 | } |
186 | 1.70k | pos += 2; |
187 | 1.70k | nlen = WPA_GET_BE16(pos); |
188 | 1.70k | pos += 2; |
189 | 1.70k | if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) { |
190 | 46 | wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " |
191 | 46 | "length %u (buf len %d)", nlen, |
192 | 46 | (int) (data + len - pos)); |
193 | 46 | return -1; |
194 | 46 | } |
195 | 1.65k | p2p_copy_filter_devname(msg->device_name, |
196 | 1.65k | sizeof(msg->device_name), pos, nlen); |
197 | 1.65k | wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR |
198 | 1.65k | " primary device type %s device name '%s' " |
199 | 1.65k | "config methods 0x%x", |
200 | 1.65k | MAC2STR(msg->p2p_device_addr), |
201 | 1.65k | wps_dev_type_bin2str(msg->pri_dev_type, devtype, |
202 | 1.65k | sizeof(devtype)), |
203 | 1.65k | msg->device_name, msg->config_methods); |
204 | 1.65k | break; |
205 | 236 | case P2P_ATTR_CONFIGURATION_TIMEOUT: |
206 | 236 | if (len < 2) { |
207 | 8 | wpa_printf(MSG_DEBUG, "P2P: Too short Configuration " |
208 | 8 | "Timeout attribute (length %d)", len); |
209 | 8 | return -1; |
210 | 8 | } |
211 | 228 | msg->config_timeout = data; |
212 | 228 | wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout"); |
213 | 228 | break; |
214 | 326 | case P2P_ATTR_INTENDED_INTERFACE_ADDR: |
215 | 326 | if (len < ETH_ALEN) { |
216 | 10 | wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P " |
217 | 10 | "Interface Address attribute (length %d)", |
218 | 10 | len); |
219 | 10 | return -1; |
220 | 10 | } |
221 | 316 | msg->intended_addr = data; |
222 | 316 | wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: " |
223 | 316 | MACSTR, MAC2STR(msg->intended_addr)); |
224 | 316 | break; |
225 | 243 | case P2P_ATTR_GROUP_BSSID: |
226 | 243 | if (len < ETH_ALEN) { |
227 | 17 | wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID " |
228 | 17 | "attribute (length %d)", len); |
229 | 17 | return -1; |
230 | 17 | } |
231 | 226 | msg->group_bssid = data; |
232 | 226 | wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR, |
233 | 226 | MAC2STR(msg->group_bssid)); |
234 | 226 | break; |
235 | 960 | case P2P_ATTR_GROUP_ID: |
236 | 960 | if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { |
237 | 46 | wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID " |
238 | 46 | "attribute length %d", len); |
239 | 46 | return -1; |
240 | 46 | } |
241 | 914 | msg->group_id = data; |
242 | 914 | msg->group_id_len = len; |
243 | 914 | wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address " |
244 | 914 | MACSTR, MAC2STR(msg->group_id)); |
245 | 914 | wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID", |
246 | 914 | msg->group_id + ETH_ALEN, |
247 | 914 | msg->group_id_len - ETH_ALEN); |
248 | 914 | break; |
249 | 240 | case P2P_ATTR_INVITATION_FLAGS: |
250 | 240 | if (len < 1) { |
251 | 9 | wpa_printf(MSG_DEBUG, "P2P: Too short Invitation " |
252 | 9 | "Flag attribute (length %d)", len); |
253 | 9 | return -1; |
254 | 9 | } |
255 | 231 | msg->invitation_flags = data; |
256 | 231 | wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", |
257 | 231 | data[0]); |
258 | 231 | break; |
259 | 247 | case P2P_ATTR_MANAGEABILITY: |
260 | 247 | if (len < 1) { |
261 | 6 | wpa_printf(MSG_DEBUG, "P2P: Too short Manageability " |
262 | 6 | "attribute (length %d)", len); |
263 | 6 | return -1; |
264 | 6 | } |
265 | 241 | msg->manageability = data; |
266 | 241 | wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x", |
267 | 241 | data[0]); |
268 | 241 | break; |
269 | 287 | case P2P_ATTR_NOTICE_OF_ABSENCE: |
270 | 287 | if (len < 2) { |
271 | 8 | wpa_printf(MSG_DEBUG, "P2P: Too short Notice of " |
272 | 8 | "Absence attribute (length %d)", len); |
273 | 8 | return -1; |
274 | 8 | } |
275 | 279 | msg->noa = data; |
276 | 279 | msg->noa_len = len; |
277 | 279 | wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); |
278 | 279 | break; |
279 | 227 | case P2P_ATTR_EXT_LISTEN_TIMING: |
280 | 227 | if (len < 4) { |
281 | 11 | wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen " |
282 | 11 | "Timing attribute (length %d)", len); |
283 | 11 | return -1; |
284 | 11 | } |
285 | 216 | msg->ext_listen_timing = data; |
286 | 216 | wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing " |
287 | 216 | "(period %u msec interval %u msec)", |
288 | 216 | WPA_GET_LE16(msg->ext_listen_timing), |
289 | 216 | WPA_GET_LE16(msg->ext_listen_timing + 2)); |
290 | 216 | break; |
291 | 222 | case P2P_ATTR_MINOR_REASON_CODE: |
292 | 222 | if (len < 1) { |
293 | 8 | wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason " |
294 | 8 | "Code attribute (length %d)", len); |
295 | 8 | return -1; |
296 | 8 | } |
297 | 214 | msg->minor_reason_code = data; |
298 | 214 | wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u", |
299 | 214 | *msg->minor_reason_code); |
300 | 214 | break; |
301 | 215 | case P2P_ATTR_OOB_GO_NEG_CHANNEL: |
302 | 215 | if (len < 6) { |
303 | 12 | wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg " |
304 | 12 | "Channel attribute (length %d)", len); |
305 | 12 | return -1; |
306 | 12 | } |
307 | 203 | msg->oob_go_neg_channel = data; |
308 | 203 | wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: " |
309 | 203 | "Country %c%c(0x%02x) Operating Class %d " |
310 | 203 | "Channel Number %d Role %d", |
311 | 203 | data[0], data[1], data[2], data[3], data[4], |
312 | 203 | data[5]); |
313 | 203 | break; |
314 | 220 | case P2P_ATTR_SERVICE_HASH: |
315 | 220 | if (len < P2PS_HASH_LEN) { |
316 | 9 | wpa_printf(MSG_DEBUG, |
317 | 9 | "P2P: Too short Service Hash (length %u)", |
318 | 9 | len); |
319 | 9 | return -1; |
320 | 9 | } |
321 | 211 | msg->service_hash_count = len / P2PS_HASH_LEN; |
322 | 211 | msg->service_hash = data; |
323 | 211 | wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len); |
324 | 211 | break; |
325 | 202 | case P2P_ATTR_SESSION_INFORMATION_DATA: |
326 | 202 | msg->session_info = data; |
327 | 202 | msg->session_info_len = len; |
328 | 202 | wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p", |
329 | 202 | len, data); |
330 | 202 | break; |
331 | 420 | case P2P_ATTR_CONNECTION_CAPABILITY: |
332 | 420 | if (len < 1) { |
333 | 8 | wpa_printf(MSG_DEBUG, |
334 | 8 | "P2P: Too short Connection Capability (length %u)", |
335 | 8 | len); |
336 | 8 | return -1; |
337 | 8 | } |
338 | 412 | msg->conn_cap = data; |
339 | 412 | wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x", |
340 | 412 | *msg->conn_cap); |
341 | 412 | break; |
342 | 411 | case P2P_ATTR_ADVERTISEMENT_ID: |
343 | 411 | if (len < 10) { |
344 | 15 | wpa_printf(MSG_DEBUG, |
345 | 15 | "P2P: Too short Advertisement ID (length %u)", |
346 | 15 | len); |
347 | 15 | return -1; |
348 | 15 | } |
349 | 396 | msg->adv_id = data; |
350 | 396 | msg->adv_mac = &data[sizeof(u32)]; |
351 | 396 | wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x", |
352 | 396 | WPA_GET_LE32(data)); |
353 | 396 | break; |
354 | 662 | case P2P_ATTR_ADVERTISED_SERVICE: |
355 | 662 | if (len < 8) { |
356 | 6 | wpa_printf(MSG_DEBUG, |
357 | 6 | "P2P: Too short Service Instance (length %u)", |
358 | 6 | len); |
359 | 6 | return -1; |
360 | 6 | } |
361 | 656 | msg->adv_service_instance = data; |
362 | 656 | msg->adv_service_instance_len = len; |
363 | 656 | if (len <= 255 + 8) { |
364 | 454 | char str[256]; |
365 | 454 | u8 namelen; |
366 | | |
367 | 454 | namelen = data[6]; |
368 | 454 | if (namelen > len - 7) |
369 | 224 | break; |
370 | 230 | os_memcpy(str, &data[7], namelen); |
371 | 230 | str[namelen] = '\0'; |
372 | 230 | wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s", |
373 | 230 | WPA_GET_LE32(data), str); |
374 | 230 | } else { |
375 | 202 | wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p", |
376 | 202 | data); |
377 | 202 | } |
378 | 432 | break; |
379 | 432 | case P2P_ATTR_SESSION_ID: |
380 | 421 | if (len < sizeof(u32) + ETH_ALEN) { |
381 | 14 | wpa_printf(MSG_DEBUG, |
382 | 14 | "P2P: Too short Session ID Info (length %u)", |
383 | 14 | len); |
384 | 14 | return -1; |
385 | 14 | } |
386 | 407 | msg->session_id = data; |
387 | 407 | msg->session_mac = &data[sizeof(u32)]; |
388 | 407 | wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR, |
389 | 407 | WPA_GET_LE32(data), MAC2STR(msg->session_mac)); |
390 | 407 | break; |
391 | 410 | case P2P_ATTR_FEATURE_CAPABILITY: |
392 | 410 | if (!len) { |
393 | 6 | wpa_printf(MSG_DEBUG, |
394 | 6 | "P2P: Too short Feature Capability (length %u)", |
395 | 6 | len); |
396 | 6 | return -1; |
397 | 6 | } |
398 | 404 | msg->feature_cap = data; |
399 | 404 | msg->feature_cap_len = len; |
400 | 404 | wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len); |
401 | 404 | break; |
402 | 787 | case P2P_ATTR_PERSISTENT_GROUP: |
403 | 787 | { |
404 | 787 | if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { |
405 | 46 | wpa_printf(MSG_DEBUG, |
406 | 46 | "P2P: Invalid Persistent Group Info (length %u)", |
407 | 46 | len); |
408 | 46 | return -1; |
409 | 46 | } |
410 | | |
411 | 741 | msg->persistent_dev = data; |
412 | 741 | msg->persistent_ssid_len = len - ETH_ALEN; |
413 | 741 | msg->persistent_ssid = &data[ETH_ALEN]; |
414 | 741 | wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s", |
415 | 741 | MAC2STR(msg->persistent_dev), |
416 | 741 | wpa_ssid_txt(msg->persistent_ssid, |
417 | 741 | msg->persistent_ssid_len)); |
418 | 741 | break; |
419 | 787 | } |
420 | 331 | case P2P_ATTR_CAPABILITY_EXTENSION: |
421 | 331 | if (len < 2) { |
422 | 10 | wpa_printf(MSG_DEBUG, "P2P: Too short PCEA (length %d)", |
423 | 10 | len); |
424 | 10 | return -1; |
425 | 10 | } |
426 | 321 | msg->pcea_info = data; |
427 | 321 | msg->pcea_info_len = len; |
428 | 321 | wpa_printf(MSG_DEBUG, "P2P: * PCEA (length=%u)", len); |
429 | 321 | break; |
430 | 540 | case P2P_ATTR_PAIRING_AND_BOOTSTRAPPING: |
431 | 540 | if (len < 1) { |
432 | 6 | wpa_printf(MSG_DEBUG, "P2P: Too short PBMA (length %d)", |
433 | 6 | len); |
434 | 6 | return -1; |
435 | 6 | } |
436 | 534 | msg->pbma_info = data; |
437 | 534 | msg->pbma_info_len = len; |
438 | 534 | wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len); |
439 | 534 | break; |
440 | 230 | case P2P_ATTR_ACTION_FRAME_WRAPPER: |
441 | 230 | if (len < 2) { |
442 | 10 | wpa_printf(MSG_DEBUG, |
443 | 10 | "P2P: Too short Action Frame Wrapper attribute (length %d)", |
444 | 10 | len); |
445 | 10 | return -1; |
446 | 10 | } |
447 | 220 | msg->action_frame_wrapper = data; |
448 | 220 | msg->action_frame_wrapper_len = len; |
449 | 220 | wpa_printf(MSG_DEBUG, "P2P: * Action frame wrapper (length=%u)", |
450 | 220 | len); |
451 | 220 | break; |
452 | 294 | case P2P_ATTR_DEVICE_IDENTITY_RESOLUTION: |
453 | 294 | if (len < 1) { |
454 | 8 | wpa_printf(MSG_DEBUG, "P2P: Too short DIRA (length %d)", |
455 | 8 | len); |
456 | 8 | return -1; |
457 | 8 | } |
458 | 286 | msg->dira = data; |
459 | 286 | msg->dira_len = len; |
460 | 286 | wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len); |
461 | 286 | break; |
462 | 230 | case P2P_ATTR_WLAN_AP_INFORMATION: |
463 | | /* One or more AP Info fields (each being 12 octets) is required |
464 | | * to be included. */ |
465 | 230 | if (len < 12) { |
466 | 16 | wpa_printf(MSG_DEBUG, |
467 | 16 | "P2P: Too short WLAN AP info (length %d)", |
468 | 16 | len); |
469 | 16 | return -1; |
470 | 16 | } |
471 | 214 | msg->wlan_ap_info = data; |
472 | 214 | msg->wlan_ap_info_len = len; |
473 | 214 | break; |
474 | 448 | default: |
475 | 448 | wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " |
476 | 448 | "(length %d)", id, len); |
477 | 448 | break; |
478 | 20.5k | } |
479 | | |
480 | 19.8k | return 0; |
481 | 20.5k | } |
482 | | |
483 | | |
484 | | /** |
485 | | * p2p_parse_p2p_ie - Parse P2P IE |
486 | | * @buf: Concatenated P2P IE(s) payload |
487 | | * @msg: Buffer for returning parsed attributes |
488 | | * Returns: 0 on success, -1 on failure |
489 | | * |
490 | | * Note: Caller is responsible for clearing the msg data structure before |
491 | | * calling this function. |
492 | | */ |
493 | | int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg) |
494 | 6.73k | { |
495 | 6.73k | const u8 *pos = wpabuf_head_u8(buf); |
496 | 6.73k | const u8 *end = pos + wpabuf_len(buf); |
497 | | |
498 | 6.73k | wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE"); |
499 | | |
500 | 26.6k | while (pos < end) { |
501 | 20.9k | u16 attr_len; |
502 | 20.9k | u8 id; |
503 | | |
504 | 20.9k | if (end - pos < 3) { |
505 | 152 | wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute"); |
506 | 152 | return -1; |
507 | 152 | } |
508 | 20.8k | id = *pos++; |
509 | 20.8k | attr_len = WPA_GET_LE16(pos); |
510 | 20.8k | pos += 2; |
511 | 20.8k | wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u", |
512 | 20.8k | id, attr_len); |
513 | 20.8k | if (attr_len > end - pos) { |
514 | 308 | wpa_printf(MSG_DEBUG, "P2P: Attribute underflow " |
515 | 308 | "(len=%u left=%d)", |
516 | 308 | attr_len, (int) (end - pos)); |
517 | 308 | wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos); |
518 | 308 | return -1; |
519 | 308 | } |
520 | 20.5k | if (p2p_parse_attribute(id, pos, attr_len, msg)) |
521 | 611 | return -1; |
522 | 19.8k | pos += attr_len; |
523 | 19.8k | } |
524 | | |
525 | 5.66k | return 0; |
526 | 6.73k | } |
527 | | |
528 | | |
529 | | static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg) |
530 | 4.24k | { |
531 | 4.24k | struct wps_parse_attr attr; |
532 | 4.24k | int i; |
533 | | |
534 | 4.24k | wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE"); |
535 | 4.24k | if (wps_parse_msg(buf, &attr)) |
536 | 1.59k | return -1; |
537 | 2.64k | if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) && |
538 | 66 | !msg->device_name[0]) |
539 | 66 | os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len); |
540 | 2.64k | if (attr.config_methods) { |
541 | 282 | msg->wps_config_methods = |
542 | 282 | WPA_GET_BE16(attr.config_methods); |
543 | 282 | wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x", |
544 | 282 | msg->wps_config_methods); |
545 | 282 | } |
546 | 2.64k | if (attr.dev_password_id) { |
547 | 24 | msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id); |
548 | 24 | wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d", |
549 | 24 | msg->dev_password_id); |
550 | 24 | msg->dev_password_id_present = 1; |
551 | 24 | } |
552 | 2.64k | if (attr.primary_dev_type) { |
553 | 40 | char devtype[WPS_DEV_TYPE_BUFSIZE]; |
554 | 40 | msg->wps_pri_dev_type = attr.primary_dev_type; |
555 | 40 | wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s", |
556 | 40 | wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype, |
557 | 40 | sizeof(devtype))); |
558 | 40 | } |
559 | 2.64k | if (attr.sec_dev_type_list) { |
560 | 44 | msg->wps_sec_dev_type_list = attr.sec_dev_type_list; |
561 | 44 | msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len; |
562 | 44 | } |
563 | | |
564 | 29.0k | for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { |
565 | 26.4k | msg->wps_vendor_ext[i] = attr.vendor_ext[i]; |
566 | 26.4k | msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i]; |
567 | 26.4k | } |
568 | | |
569 | 2.64k | msg->manufacturer = attr.manufacturer; |
570 | 2.64k | msg->manufacturer_len = attr.manufacturer_len; |
571 | 2.64k | msg->model_name = attr.model_name; |
572 | 2.64k | msg->model_name_len = attr.model_name_len; |
573 | 2.64k | msg->model_number = attr.model_number; |
574 | 2.64k | msg->model_number_len = attr.model_number_len; |
575 | 2.64k | msg->serial_number = attr.serial_number; |
576 | 2.64k | msg->serial_number_len = attr.serial_number_len; |
577 | | |
578 | 2.64k | msg->oob_dev_password = attr.oob_dev_password; |
579 | 2.64k | msg->oob_dev_password_len = attr.oob_dev_password_len; |
580 | | |
581 | 2.64k | return 0; |
582 | 4.24k | } |
583 | | |
584 | | |
585 | | /** |
586 | | * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) |
587 | | * @data: IEs from the message |
588 | | * @len: Length of data buffer in octets |
589 | | * @msg: Buffer for returning parsed attributes |
590 | | * Returns: 0 on success, -1 on failure |
591 | | * |
592 | | * Note: Caller is responsible for clearing the msg data structure before |
593 | | * calling this function. |
594 | | * |
595 | | * Note: Caller must free temporary memory allocations by calling |
596 | | * p2p_parse_free() when the parsed data is not needed anymore. |
597 | | */ |
598 | | int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) |
599 | 16.0k | { |
600 | 16.0k | struct ieee802_11_elems elems; |
601 | | |
602 | 16.0k | if (ieee802_11_parse_elems(data, len, &elems, 0) == ParseFailed) |
603 | 2.09k | return -1; |
604 | | |
605 | 13.9k | if (elems.ds_params) |
606 | 629 | msg->ds_params = elems.ds_params; |
607 | 13.9k | if (elems.ssid) |
608 | 3.94k | msg->ssid = elems.ssid - 2; |
609 | | |
610 | 13.9k | msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, |
611 | 13.9k | WPS_DEV_OUI_WFA); |
612 | 13.9k | if (msg->wps_attributes && |
613 | 4.24k | p2p_parse_wps_ie(msg->wps_attributes, msg)) { |
614 | 1.59k | p2p_parse_free(msg); |
615 | 1.59k | return -1; |
616 | 1.59k | } |
617 | | |
618 | 12.3k | msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, |
619 | 12.3k | P2P_IE_VENDOR_TYPE); |
620 | 12.3k | if (msg->p2p_attributes && |
621 | 6.21k | p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { |
622 | 953 | wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); |
623 | 953 | if (msg->p2p_attributes) |
624 | 953 | wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", |
625 | 953 | msg->p2p_attributes); |
626 | 953 | p2p_parse_free(msg); |
627 | 953 | return -1; |
628 | 953 | } |
629 | | |
630 | 11.4k | msg->p2p2_attributes = ieee802_11_vendor_ie_concat(data, len, |
631 | 11.4k | P2P2_IE_VENDOR_TYPE); |
632 | 11.4k | if (msg->p2p2_attributes && |
633 | 525 | p2p_parse_p2p_ie(msg->p2p2_attributes, msg)) { |
634 | 118 | wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P2 IE data"); |
635 | 118 | if (msg->p2p2_attributes) |
636 | 118 | wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P2 IE data", |
637 | 118 | msg->p2p2_attributes); |
638 | 118 | p2p_parse_free(msg); |
639 | 118 | return -1; |
640 | 118 | } |
641 | | |
642 | 11.3k | #ifdef CONFIG_WIFI_DISPLAY |
643 | 11.3k | if (elems.wfd) { |
644 | 737 | msg->wfd_subelems = ieee802_11_vendor_ie_concat( |
645 | 737 | data, len, WFD_IE_VENDOR_TYPE); |
646 | 737 | } |
647 | 11.3k | #endif /* CONFIG_WIFI_DISPLAY */ |
648 | | |
649 | 11.3k | msg->pref_freq_list = elems.pref_freq_list; |
650 | 11.3k | msg->pref_freq_list_len = elems.pref_freq_list_len; |
651 | | |
652 | 11.3k | return 0; |
653 | 11.4k | } |
654 | | |
655 | | |
656 | | /** |
657 | | * p2p_parse - Parse a P2P Action frame contents |
658 | | * @data: Action frame payload after Category and Code fields |
659 | | * @len: Length of data buffer in octets |
660 | | * @msg: Buffer for returning parsed attributes |
661 | | * Returns: 0 on success, -1 on failure |
662 | | * |
663 | | * Note: Caller must free temporary memory allocations by calling |
664 | | * p2p_parse_free() when the parsed data is not needed anymore. |
665 | | */ |
666 | | int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg) |
667 | 2.48k | { |
668 | 2.48k | os_memset(msg, 0, sizeof(*msg)); |
669 | 2.48k | wpa_printf(MSG_DEBUG, "P2P: Parsing the received message"); |
670 | 2.48k | if (len < 1) { |
671 | 6 | wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message"); |
672 | 6 | return -1; |
673 | 6 | } |
674 | 2.47k | msg->dialog_token = data[0]; |
675 | 2.47k | wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token); |
676 | | |
677 | 2.47k | return p2p_parse_ies(data + 1, len - 1, msg); |
678 | 2.48k | } |
679 | | |
680 | | |
681 | | int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p, |
682 | | size_t p2p_len, struct p2p_message *msg) |
683 | 0 | { |
684 | 0 | os_memset(msg, 0, sizeof(*msg)); |
685 | |
|
686 | 0 | msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len); |
687 | 0 | if (msg->wps_attributes && |
688 | 0 | p2p_parse_wps_ie(msg->wps_attributes, msg)) { |
689 | 0 | p2p_parse_free(msg); |
690 | 0 | return -1; |
691 | 0 | } |
692 | | |
693 | 0 | msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len); |
694 | 0 | if (msg->p2p_attributes && |
695 | 0 | p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { |
696 | 0 | wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); |
697 | 0 | if (msg->p2p_attributes) |
698 | 0 | wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", |
699 | 0 | msg->p2p_attributes); |
700 | 0 | p2p_parse_free(msg); |
701 | 0 | return -1; |
702 | 0 | } |
703 | | |
704 | 0 | return 0; |
705 | 0 | } |
706 | | |
707 | | |
708 | | /** |
709 | | * p2p_parse_free - Free temporary data from P2P parsing |
710 | | * @msg: Parsed attributes |
711 | | */ |
712 | | void p2p_parse_free(struct p2p_message *msg) |
713 | 18.2k | { |
714 | 18.2k | wpabuf_free(msg->p2p_attributes); |
715 | 18.2k | msg->p2p_attributes = NULL; |
716 | 18.2k | wpabuf_free(msg->p2p2_attributes); |
717 | 18.2k | msg->p2p2_attributes = NULL; |
718 | 18.2k | wpabuf_free(msg->wps_attributes); |
719 | 18.2k | msg->wps_attributes = NULL; |
720 | 18.2k | #ifdef CONFIG_WIFI_DISPLAY |
721 | 18.2k | wpabuf_free(msg->wfd_subelems); |
722 | 18.2k | msg->wfd_subelems = NULL; |
723 | 18.2k | #endif /* CONFIG_WIFI_DISPLAY */ |
724 | 18.2k | } |
725 | | |
726 | | |
727 | | int p2p_group_info_parse(const u8 *gi, size_t gi_len, |
728 | | struct p2p_group_info *info) |
729 | 137 | { |
730 | 137 | const u8 *g, *gend; |
731 | | |
732 | 137 | os_memset(info, 0, sizeof(*info)); |
733 | 137 | if (gi == NULL) |
734 | 0 | return 0; |
735 | | |
736 | 137 | g = gi; |
737 | 137 | gend = gi + gi_len; |
738 | 310 | while (g < gend) { |
739 | 242 | struct p2p_client_info *cli; |
740 | 242 | const u8 *cend; |
741 | 242 | u16 count; |
742 | 242 | u8 len; |
743 | | |
744 | 242 | cli = &info->client[info->num_clients]; |
745 | 242 | len = *g++; |
746 | 242 | if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1) |
747 | 22 | return -1; /* invalid data */ |
748 | 220 | cend = g + len; |
749 | | /* g at start of P2P Client Info Descriptor */ |
750 | 220 | cli->p2p_device_addr = g; |
751 | 220 | g += ETH_ALEN; |
752 | 220 | cli->p2p_interface_addr = g; |
753 | 220 | g += ETH_ALEN; |
754 | 220 | cli->dev_capab = *g++; |
755 | | |
756 | 220 | cli->config_methods = WPA_GET_BE16(g); |
757 | 220 | g += 2; |
758 | 220 | cli->pri_dev_type = g; |
759 | 220 | g += 8; |
760 | | |
761 | | /* g at Number of Secondary Device Types */ |
762 | 220 | len = *g++; |
763 | 220 | if (8 * len > cend - g) |
764 | 18 | return -1; /* invalid data */ |
765 | 202 | cli->num_sec_dev_types = len; |
766 | 202 | cli->sec_dev_types = g; |
767 | 202 | g += 8 * len; |
768 | | |
769 | | /* g at Device Name in WPS TLV format */ |
770 | 202 | if (cend - g < 2 + 2) |
771 | 3 | return -1; /* invalid data */ |
772 | 199 | if (WPA_GET_BE16(g) != ATTR_DEV_NAME) |
773 | 21 | return -1; /* invalid Device Name TLV */ |
774 | 178 | g += 2; |
775 | 178 | count = WPA_GET_BE16(g); |
776 | 178 | g += 2; |
777 | 178 | if (count > cend - g) |
778 | 5 | return -1; /* invalid Device Name TLV */ |
779 | 173 | if (count >= WPS_DEV_NAME_MAX_LEN) |
780 | 6 | count = WPS_DEV_NAME_MAX_LEN; |
781 | 173 | cli->dev_name = (const char *) g; |
782 | 173 | cli->dev_name_len = count; |
783 | | |
784 | 173 | g = cend; |
785 | | |
786 | 173 | info->num_clients++; |
787 | 173 | if (info->num_clients == P2P_MAX_GROUP_ENTRIES) |
788 | 0 | return -1; |
789 | 173 | } |
790 | | |
791 | 68 | return 0; |
792 | 137 | } |
793 | | |
794 | | |
795 | | static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf, |
796 | | char *end) |
797 | 0 | { |
798 | 0 | char *pos = buf; |
799 | 0 | int ret; |
800 | 0 | struct p2p_group_info info; |
801 | 0 | unsigned int i; |
802 | |
|
803 | 0 | if (p2p_group_info_parse(gi, gi_len, &info) < 0) |
804 | 0 | return 0; |
805 | | |
806 | 0 | for (i = 0; i < info.num_clients; i++) { |
807 | 0 | struct p2p_client_info *cli; |
808 | 0 | char name[WPS_DEV_NAME_MAX_LEN + 1]; |
809 | 0 | char devtype[WPS_DEV_TYPE_BUFSIZE]; |
810 | 0 | u8 s; |
811 | 0 | int count; |
812 | |
|
813 | 0 | cli = &info.client[i]; |
814 | 0 | ret = os_snprintf(pos, end - pos, "p2p_group_client: " |
815 | 0 | "dev=" MACSTR " iface=" MACSTR, |
816 | 0 | MAC2STR(cli->p2p_device_addr), |
817 | 0 | MAC2STR(cli->p2p_interface_addr)); |
818 | 0 | if (os_snprintf_error(end - pos, ret)) |
819 | 0 | return pos - buf; |
820 | 0 | pos += ret; |
821 | |
|
822 | 0 | ret = os_snprintf(pos, end - pos, |
823 | 0 | " dev_capab=0x%x config_methods=0x%x " |
824 | 0 | "dev_type=%s", |
825 | 0 | cli->dev_capab, cli->config_methods, |
826 | 0 | wps_dev_type_bin2str(cli->pri_dev_type, |
827 | 0 | devtype, |
828 | 0 | sizeof(devtype))); |
829 | 0 | if (os_snprintf_error(end - pos, ret)) |
830 | 0 | return pos - buf; |
831 | 0 | pos += ret; |
832 | |
|
833 | 0 | for (s = 0; s < cli->num_sec_dev_types; s++) { |
834 | 0 | ret = os_snprintf(pos, end - pos, " dev_type=%s", |
835 | 0 | wps_dev_type_bin2str( |
836 | 0 | &cli->sec_dev_types[s * 8], |
837 | 0 | devtype, sizeof(devtype))); |
838 | 0 | if (os_snprintf_error(end - pos, ret)) |
839 | 0 | return pos - buf; |
840 | 0 | pos += ret; |
841 | 0 | } |
842 | | |
843 | 0 | os_memcpy(name, cli->dev_name, cli->dev_name_len); |
844 | 0 | name[cli->dev_name_len] = '\0'; |
845 | 0 | count = (int) cli->dev_name_len - 1; |
846 | 0 | while (count >= 0) { |
847 | 0 | if (is_ctrl_char(name[count])) |
848 | 0 | name[count] = '_'; |
849 | 0 | count--; |
850 | 0 | } |
851 | |
|
852 | 0 | ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name); |
853 | 0 | if (os_snprintf_error(end - pos, ret)) |
854 | 0 | return pos - buf; |
855 | 0 | pos += ret; |
856 | 0 | } |
857 | | |
858 | 0 | return pos - buf; |
859 | 0 | } |
860 | | |
861 | | |
862 | | /** |
863 | | * p2p_attr_text - Build text format description of P2P IE attributes |
864 | | * @data: P2P IE contents |
865 | | * @buf: Buffer for returning text |
866 | | * @end: Pointer to the end of the buf area |
867 | | * Returns: Number of octets written to the buffer or -1 on faikure |
868 | | * |
869 | | * This function can be used to parse P2P IE contents into text format |
870 | | * field=value lines. |
871 | | */ |
872 | | int p2p_attr_text(struct wpabuf *data, char *buf, char *end) |
873 | 0 | { |
874 | 0 | struct p2p_message msg; |
875 | 0 | char *pos = buf; |
876 | 0 | int ret; |
877 | |
|
878 | 0 | os_memset(&msg, 0, sizeof(msg)); |
879 | 0 | if (p2p_parse_p2p_ie(data, &msg)) |
880 | 0 | return -1; |
881 | | |
882 | 0 | if (msg.capability) { |
883 | 0 | ret = os_snprintf(pos, end - pos, |
884 | 0 | "p2p_dev_capab=0x%x\n" |
885 | 0 | "p2p_group_capab=0x%x\n", |
886 | 0 | msg.capability[0], msg.capability[1]); |
887 | 0 | if (os_snprintf_error(end - pos, ret)) |
888 | 0 | return pos - buf; |
889 | 0 | pos += ret; |
890 | 0 | } |
891 | | |
892 | 0 | if (msg.pri_dev_type) { |
893 | 0 | char devtype[WPS_DEV_TYPE_BUFSIZE]; |
894 | 0 | ret = os_snprintf(pos, end - pos, |
895 | 0 | "p2p_primary_device_type=%s\n", |
896 | 0 | wps_dev_type_bin2str(msg.pri_dev_type, |
897 | 0 | devtype, |
898 | 0 | sizeof(devtype))); |
899 | 0 | if (os_snprintf_error(end - pos, ret)) |
900 | 0 | return pos - buf; |
901 | 0 | pos += ret; |
902 | 0 | } |
903 | | |
904 | 0 | ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n", |
905 | 0 | msg.device_name); |
906 | 0 | if (os_snprintf_error(end - pos, ret)) |
907 | 0 | return pos - buf; |
908 | 0 | pos += ret; |
909 | |
|
910 | 0 | if (msg.p2p_device_addr) { |
911 | 0 | ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR |
912 | 0 | "\n", |
913 | 0 | MAC2STR(msg.p2p_device_addr)); |
914 | 0 | if (os_snprintf_error(end - pos, ret)) |
915 | 0 | return pos - buf; |
916 | 0 | pos += ret; |
917 | 0 | } |
918 | | |
919 | 0 | ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n", |
920 | 0 | msg.config_methods); |
921 | 0 | if (os_snprintf_error(end - pos, ret)) |
922 | 0 | return pos - buf; |
923 | 0 | pos += ret; |
924 | |
|
925 | 0 | ret = p2p_group_info_text(msg.group_info, msg.group_info_len, |
926 | 0 | pos, end); |
927 | 0 | if (ret < 0) |
928 | 0 | return pos - buf; |
929 | 0 | pos += ret; |
930 | |
|
931 | 0 | return pos - buf; |
932 | 0 | } |
933 | | |
934 | | |
935 | | int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie) |
936 | 0 | { |
937 | 0 | struct p2p_message msg; |
938 | |
|
939 | 0 | os_memset(&msg, 0, sizeof(msg)); |
940 | 0 | if (p2p_parse_p2p_ie(p2p_ie, &msg)) |
941 | 0 | return 0; |
942 | | |
943 | 0 | if (!msg.manageability) |
944 | 0 | return 0; |
945 | | |
946 | 0 | return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED); |
947 | 0 | } |
948 | | |
949 | | |
950 | | u8 p2p_get_group_capab(const struct wpabuf *p2p_ie) |
951 | 0 | { |
952 | 0 | struct p2p_message msg; |
953 | |
|
954 | 0 | os_memset(&msg, 0, sizeof(msg)); |
955 | 0 | if (p2p_parse_p2p_ie(p2p_ie, &msg)) |
956 | 0 | return 0; |
957 | | |
958 | 0 | if (!msg.capability) |
959 | 0 | return 0; |
960 | | |
961 | 0 | return msg.capability[1]; |
962 | 0 | } |
963 | | |
964 | | |
965 | | const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie) |
966 | 0 | { |
967 | 0 | struct p2p_message msg; |
968 | |
|
969 | 0 | os_memset(&msg, 0, sizeof(msg)); |
970 | 0 | if (p2p_parse_p2p_ie(p2p_ie, &msg)) |
971 | 0 | return NULL; |
972 | | |
973 | 0 | if (msg.p2p_device_addr) |
974 | 0 | return msg.p2p_device_addr; |
975 | 0 | if (msg.device_id) |
976 | 0 | return msg.device_id; |
977 | | |
978 | 0 | return NULL; |
979 | 0 | } |