/* * * Wireless daemon for Linux * * Copyright (C) 2019 Intel Corporation. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "src/p2putil.h" #include "src/ie.h" static const uint8_t p2p_attrs1[] = { 0x02, 0x02, 0x00, 0x25, 0x00, 0x0d, 0x1d, 0x00, 0x00, 0x28, 0xf8, 0xed, 0x26, 0x57, 0x11, 0x08, 0x00, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x64, 0x65, 0x76, 0x31, 0x0f, 0x15, 0x00, 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x2d, 0x5a, 0x75, 0x2d, 0x41, 0x6e, 0x64, 0x72, 0x65, }; static void p2p_test_iter_sanity_check(const void *data) { struct p2p_attr_iter iter; p2p_attr_iter_init(&iter, p2p_attrs1, sizeof(p2p_attrs1)); assert(p2p_attr_iter_next(&iter)); assert(p2p_attr_iter_get_type(&iter) == P2P_ATTR_P2P_CAPABILITY); assert(p2p_attr_iter_get_length(&iter) == 2); assert(p2p_attr_iter_next(&iter)); assert(p2p_attr_iter_get_type(&iter) == P2P_ATTR_P2P_DEVICE_INFO); assert(p2p_attr_iter_get_length(&iter) == 29); assert(p2p_attr_iter_next(&iter)); assert(p2p_attr_iter_get_type(&iter) == P2P_ATTR_P2P_GROUP_ID); assert(p2p_attr_iter_get_length(&iter) == 21); assert(!p2p_attr_iter_next(&iter)); } typedef bool (*test_queue_cmp_func)(const void *data1, const void *data2); static bool test_queue_cmp(struct l_queue *q1, struct l_queue *q2, test_queue_cmp_func func) { const struct l_queue_entry *entry1 = l_queue_get_entries(q1); const struct l_queue_entry *entry2 = l_queue_get_entries(q2); while (entry1 && entry2) { if (!func(entry1->data, entry2->data)) return false; entry1 = entry1->next; entry2 = entry2->next; } return !entry1 && !entry2; } static bool p2p_noa_desc_cmp(const void *data1, const void *data2) { const struct p2p_notice_of_absence_desc *desc1 = data1; const struct p2p_notice_of_absence_desc *desc2 = data2; if (desc1->count_type != desc2->count_type) return false; if (desc1->duration != desc2->duration) return false; if (desc1->interval != desc2->interval) return false; if (desc1->start_time != desc2->start_time) return false; return true; } /* * The attributes in a P2P IE are not explicitly required to be ordered * in the same way they're listed in each frame's format specification in * Wi-Fi P2P Technical Specification v1.7 and in fact some consumer devices * switch some attributes' order in their probe responses. This compares * the contents of two sets of P2P IEs ignoring attribute order and payload * segmentation into individual P2P IEs. * TODO: Might also want to validate the WSC IEs written by the p2putil.c * builder functions. */ static bool p2p_payload_cmd(const uint8_t *ies1, size_t ies1_len, const uint8_t *ies2, size_t ies2_len) { uint8_t *payload1, *payload2; ssize_t payload1_len, payload2_len; struct p2p_attr_iter iter1, iter2; const uint8_t *attr1_start[P2P_ATTR_PERSISTENT_GROUP_INFO + 1]; int i; bool r = false; if (!ies1 || !ies2) return false; payload1 = ie_tlv_extract_p2p_payload(ies1, ies1_len, &payload1_len); payload2 = ie_tlv_extract_p2p_payload(ies2, ies2_len, &payload2_len); if (payload1_len < 0 || payload2_len < 0) return false; p2p_attr_iter_init(&iter1, payload1, payload1_len); p2p_attr_iter_init(&iter2, payload2, payload2_len); memset(attr1_start, 0, sizeof(attr1_start)); while (p2p_attr_iter_next(&iter1)) { enum p2p_attr type = p2p_attr_iter_get_type(&iter1); const uint8_t *start = p2p_attr_iter_get_data(&iter1) - 3; if (type >= L_ARRAY_SIZE(attr1_start)) goto done; /* Unknown attribute */ if (attr1_start[type]) goto done; /* Duplicate attribute type in @ies1 */ attr1_start[type] = start; } while (p2p_attr_iter_next(&iter2)) { enum p2p_attr type = p2p_attr_iter_get_type(&iter2); const uint8_t *start = p2p_attr_iter_get_data(&iter2) - 3; size_t len; if ((int) type >= (int) L_ARRAY_SIZE(attr1_start)) goto done; /* Unknown attribute */ if (!attr1_start[type]) goto done; /* Not in @ies1 or dupe in @ies2 */ len = p2p_attr_iter_get_length(&iter2) + 3; /* * It's safe to memcmp len bytes because the length is also * encoded in the first 3 bytes of both buffers. */ if (memcmp(start, attr1_start[type], len)) goto done; /* Contents or lengths differ */ attr1_start[type] = NULL; } for (i = 0; i < (int) L_ARRAY_SIZE(attr1_start); i++) if (attr1_start[i]) goto done; /* @ies1 attribute was not in @ies2 */ r = true; done: l_free(payload1); l_free(payload2); return r; } static const uint8_t p2p_beacon_ies_1[] = { 0xdd, 0x12, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x05, 0xab, 0x03, 0x06, 0x00, 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0, 0xdd, 0x4e, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x41, 0x00, 0x01, 0x01, 0x10, 0x12, 0x00, 0x02, 0x00, 0x04, 0x10, 0x53, 0x00, 0x02, 0x43, 0x88, 0x10, 0x49, 0x00, 0x0e, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x11, 0x00, 0x0d, 0x4c, 0x45, 0x58, 0x36, 0x32, 0x36, 0x2d, 0x50, 0x64, 0x61, 0x4e, 0x65, 0x74, 0x10, 0x54, 0x00, 0x08, 0x00, 0x08, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x02, 0xdd, 0x16, 0x50, 0x6f, 0x9a, 0x09, 0x0c, 0x0f, 0x00, 0xe1, 0x00, 0x01, 0xb0, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x45, 0x8f, 0x0c, }; struct p2p_beacon_data { const uint8_t *ies; size_t ies_len; ssize_t payload_len; struct p2p_beacon data; const struct p2p_notice_of_absence_desc *noa_descs; }; static const struct p2p_beacon_data p2p_beacon_data_1 = { .ies = p2p_beacon_ies_1, .ies_len = L_ARRAY_SIZE(p2p_beacon_ies_1), .payload_len = 32, .data = { .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CONCURRENT_OP, .group_caps = P2P_GROUP_CAP_GO | P2P_GROUP_CAP_PERSISTENT_GROUP | P2P_GROUP_CAP_INTRA_BSS_DISTRIBUTION | P2P_GROUP_CAP_PERSISTENT_RECONNECT | P2P_GROUP_CAP_IP_ALLOCATION, }, .device_addr = { 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0 }, .notice_of_absence = { .index = 225, .opp_ps = false, .ct_window = 0, }, }, .noa_descs = (const struct p2p_notice_of_absence_desc []) { [0] = { .count_type = 1, .duration = 46000, .interval = 0, .start_time = 210716028, }, [1] = {} }, }; static void p2p_test_parse_beacon(const void *data) { const struct p2p_beacon_data *test = data; struct p2p_beacon attrs1, attrs2; const struct p2p_notice_of_absence_desc *desc = test->noa_descs; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->ies, test->ies_len, &payload_len); l_free(payload); assert(payload_len == test->payload_len); memcpy(&attrs2, &test->data, sizeof(attrs2)); if (desc) attrs2.notice_of_absence.descriptors = l_queue_new(); while (desc && desc->start_time) { l_queue_push_tail(attrs2.notice_of_absence.descriptors, l_memdup(desc, sizeof(*desc))); desc++; } assert(p2p_parse_beacon(test->ies, test->ies_len, &attrs1) == 0); assert(attrs1.capability.device_caps == attrs2.capability.device_caps); assert(attrs1.capability.group_caps == attrs2.capability.group_caps); assert(!memcmp(attrs1.device_addr, attrs2.device_addr, 6)); assert(attrs1.notice_of_absence.index == attrs2.notice_of_absence.index); assert(attrs1.notice_of_absence.opp_ps == attrs2.notice_of_absence.opp_ps); assert(attrs1.notice_of_absence.ct_window == attrs2.notice_of_absence.ct_window); assert(test_queue_cmp(attrs1.notice_of_absence.descriptors, attrs2.notice_of_absence.descriptors, p2p_noa_desc_cmp)); p2p_clear_beacon(&attrs1); p2p_clear_beacon(&attrs2); } static void p2p_test_build_beacon(const void *data) { const struct p2p_beacon_data *test = data; struct p2p_beacon attrs2; const struct p2p_notice_of_absence_desc *desc = test->noa_descs; uint8_t *ies; size_t ies_len; memcpy(&attrs2, &test->data, sizeof(attrs2)); if (desc) attrs2.notice_of_absence.descriptors = l_queue_new(); while (desc && desc->start_time) { l_queue_push_tail(attrs2.notice_of_absence.descriptors, l_memdup(desc, sizeof(*desc))); desc++; } ies = p2p_build_beacon(&attrs2, &ies_len); p2p_clear_beacon(&attrs2); assert(p2p_payload_cmd(ies, ies_len, test->ies, test->ies_len)); l_free(ies); } static const uint8_t p2p_probe_req_ies_1[] = { 0xdd, 0x73, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x3a, 0x00, 0x01, 0x01, 0x10, 0x08, 0x00, 0x02, 0x31, 0x48, 0x10, 0x47, 0x00, 0x10, 0x9a, 0xdd, 0x77, 0x82, 0xcb, 0xa6, 0x5e, 0x2d, 0xac, 0xd9, 0xc0, 0x54, 0x34, 0xd0, 0xd7, 0x29, 0x10, 0x54, 0x00, 0x08, 0x00, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x10, 0x3c, 0x00, 0x01, 0x03, 0x10, 0x02, 0x00, 0x02, 0x00, 0x00, 0x10, 0x09, 0x00, 0x02, 0x00, 0x00, 0x10, 0x12, 0x00, 0x02, 0x00, 0x00, 0x10, 0x21, 0x00, 0x01, 0x20, 0x10, 0x23, 0x00, 0x01, 0x20, 0x10, 0x24, 0x00, 0x01, 0x20, 0x10, 0x11, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x64, 0x65, 0x76, 0x31, 0x10, 0x49, 0x00, 0x09, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0x03, 0x01, 0x01, 0xdd, 0x11, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x25, 0x00, 0x06, 0x05, 0x00, 0x58, 0x58, 0x04, 0x51, 0x01, }; struct p2p_probe_req_data { const uint8_t *ies; size_t ies_len; ssize_t payload_len; struct p2p_probe_req data; }; static const struct p2p_probe_req_data p2p_probe_req_data_1 = { .ies = p2p_probe_req_ies_1, .ies_len = L_ARRAY_SIZE(p2p_probe_req_ies_1), .payload_len = 13, .data = { .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CONCURRENT_OP | P2P_DEVICE_CAP_INVITATION_PROCEDURE, .group_caps = 0, }, .listen_channel = { .country = "XX\x04", .oper_class = 81, .channel_num = 1, }, }, }; static void p2p_test_parse_probe_req(const void *data) { const struct p2p_probe_req_data *test = data; uint8_t *payload; ssize_t payload_len; struct p2p_probe_req attrs; payload = ie_tlv_extract_p2p_payload(test->ies, test->ies_len, &payload_len); l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_probe_req(test->ies, test->ies_len, &attrs) == 0); assert(attrs.capability.device_caps == test->data.capability.device_caps); assert(attrs.capability.group_caps == test->data.capability.group_caps); assert(!memcmp(attrs.device_addr, test->data.device_addr, 6)); assert(!memcmp(attrs.listen_channel.country, test->data.listen_channel.country, 3)); assert(attrs.listen_channel.oper_class == test->data.listen_channel.oper_class); assert(attrs.listen_channel.channel_num == test->data.listen_channel.channel_num); assert(attrs.listen_availability.avail_period_ms == test->data.listen_availability.avail_period_ms); assert(attrs.listen_availability.avail_interval_ms == test->data.listen_availability.avail_interval_ms); assert(!memcmp(attrs.device_info.device_addr, test->data.device_info.device_addr, 6)); assert(attrs.device_info.wsc_config_methods == test->data.device_info.wsc_config_methods); assert(attrs.device_info.primary_device_type.category == test->data.device_info.primary_device_type.category); assert(!memcmp(attrs.device_info.primary_device_type.oui, test->data.device_info.primary_device_type.oui, 3)); assert(attrs.device_info.primary_device_type.oui_type == test->data.device_info.primary_device_type.oui_type); assert(attrs.device_info.primary_device_type.subcategory == test->data.device_info.primary_device_type.subcategory); assert(l_queue_length(attrs.device_info.secondary_device_types) == l_queue_length(test->data.device_info.secondary_device_types)); assert(!strcmp(attrs.device_info.device_name, test->data.device_info.device_name)); assert(!memcmp(attrs.operating_channel.country, test->data.operating_channel.country, 3)); assert(attrs.operating_channel.oper_class == test->data.operating_channel.oper_class); assert(attrs.operating_channel.channel_num == test->data.operating_channel.channel_num); assert(l_queue_length(attrs.service_hashes) == l_queue_length(test->data.service_hashes)); p2p_clear_probe_req(&attrs); } static void p2p_test_build_probe_req(const void *data) { const struct p2p_probe_req_data *test = data; uint8_t *ies; size_t ies_len; ies = p2p_build_probe_req(&test->data, &ies_len); assert(p2p_payload_cmd(ies, ies_len, test->ies, test->ies_len)); l_free(ies); } /* Notice of Absence and Device Info in the wrong order */ static const uint8_t p2p_probe_resp_ies_1[] = { 0xdd, 0xa2, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x41, 0x00, 0x01, 0x01, 0x10, 0x12, 0x00, 0x02, 0x00, 0x04, 0x10, 0x53, 0x00, 0x02, 0x43, 0x88, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0xb1, 0x7d, 0x6f, 0xc9, 0x4f, 0xd1, 0x5a, 0x6f, 0xb6, 0x50, 0x53, 0x11, 0x0b, 0x2a, 0xb5, 0x25, 0x10, 0x21, 0x00, 0x0d, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x65, 0x6b, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x10, 0x23, 0x00, 0x12, 0x4d, 0x54, 0x4b, 0x20, 0x57, 0x69, 0x72, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x10, 0x24, 0x00, 0x03, 0x31, 0x2e, 0x30, 0x10, 0x42, 0x00, 0x03, 0x32, 0x2e, 0x30, 0x10, 0x54, 0x00, 0x08, 0x00, 0x08, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x02, 0x10, 0x11, 0x00, 0x0d, 0x4c, 0x45, 0x58, 0x36, 0x32, 0x36, 0x2d, 0x50, 0x64, 0x61, 0x4e, 0x65, 0x74, 0x10, 0x08, 0x00, 0x02, 0x41, 0x08, 0x10, 0x49, 0x00, 0x0e, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0x01, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdd, 0x27, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x05, 0xab, 0x0d, 0x1b, 0x00, 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0, 0x01, 0x88, 0x00, 0x08, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x02, 0x00, 0x10, 0x11, 0x00, 0x06, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0xdd, 0x16, 0x50, 0x6f, 0x9a, 0x09, 0x0c, 0x0f, 0x00, 0xe1, 0x00, 0x01, 0xb0, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x45, 0x8f, 0x0c, }; struct p2p_probe_resp_data { const uint8_t *ies; size_t ies_len; ssize_t payload_len; struct p2p_probe_resp data; const struct p2p_notice_of_absence_desc *noa_descs; }; static const struct p2p_probe_resp_data p2p_probe_resp_data_1 = { .ies = p2p_probe_resp_ies_1, .ies_len = L_ARRAY_SIZE(p2p_probe_resp_ies_1), .payload_len = 53, .data = { .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CONCURRENT_OP, .group_caps = P2P_GROUP_CAP_GO | P2P_GROUP_CAP_PERSISTENT_GROUP | P2P_GROUP_CAP_INTRA_BSS_DISTRIBUTION | P2P_GROUP_CAP_PERSISTENT_RECONNECT | P2P_GROUP_CAP_IP_ALLOCATION, }, .notice_of_absence = { .index = 225, .opp_ps = false, .ct_window = 0, }, .device_info = { .device_addr = { 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0 }, .wsc_config_methods = WSC_CONFIGURATION_METHOD_DISPLAY | WSC_CONFIGURATION_METHOD_PUSH_BUTTON | WSC_CONFIGURATION_METHOD_KEYPAD, .primary_device_type = { .category = 8, .oui = { 0x00, 0x50, 0xf2 }, .oui_type = 0x04, .subcategory = 2, }, .device_name = "Mobile", }, }, .noa_descs = (const struct p2p_notice_of_absence_desc []) { [0] = { .count_type = 1, .duration = 46000, .interval = 0, .start_time = 210716028, }, [1] = {} }, }; static const uint8_t p2p_probe_resp_ies_2[] = { 0xdd, 0x3e, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x05, 0x01, 0x0d, 0x32, 0x00, 0xa2, 0x8c, 0xfd, 0xb9, 0x05, 0xef, 0x5a, 0x88, 0x00, 0x03, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x1d, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x2d, 0x45, 0x46, 0x2d, 0x48, 0x50, 0x20, 0x45, 0x4e, 0x56, 0x59, 0x20, 0x34, 0x35, 0x32, 0x30, 0x20, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0xdd, 0xc1, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x44, 0x00, 0x01, 0x02, 0x10, 0x57, 0x00, 0x01, 0x01, 0x10, 0x41, 0x00, 0x01, 0x00, 0x10, 0x3b, 0x00, 0x01, 0x03, 0x10, 0x47, 0x00, 0x10, 0x1c, 0x85, 0x2a, 0x4d, 0xb8, 0x00, 0x1f, 0x08, 0xab, 0xcd, 0xa0, 0x8c, 0xfd, 0xb9, 0x05, 0xef, 0x10, 0x21, 0x00, 0x02, 0x48, 0x50, 0x10, 0x23, 0x00, 0x11, 0x45, 0x4e, 0x56, 0x59, 0x20, 0x34, 0x35, 0x32, 0x30, 0x20, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x00, 0x10, 0x24, 0x00, 0x05, 0x34, 0x35, 0x32, 0x37, 0x00, 0x10, 0x42, 0x00, 0x10, 0x54, 0x48, 0x36, 0x35, 0x4f, 0x33, 0x48, 0x31, 0x58, 0x59, 0x30, 0x36, 0x36, 0x30, 0x00, 0x00, 0x10, 0x54, 0x00, 0x08, 0x00, 0x03, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x05, 0x10, 0x11, 0x00, 0x1d, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x2d, 0x45, 0x46, 0x2d, 0x48, 0x50, 0x20, 0x45, 0x4e, 0x56, 0x59, 0x20, 0x34, 0x35, 0x32, 0x30, 0x20, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x10, 0x08, 0x00, 0x02, 0x00, 0x00, 0x10, 0x49, 0x00, 0x06, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0x10, 0x49, 0x00, 0x17, 0x00, 0x01, 0x37, 0x10, 0x06, 0x00, 0x10, 0x1c, 0x85, 0x2a, 0x4d, 0xb8, 0x00, 0x1f, 0x08, 0xab, 0xcd, 0xa0, 0x8c, 0xfd, 0xb9, 0x05, 0xef, }; static const struct p2p_probe_resp_data p2p_probe_resp_data_2 = { .ies = p2p_probe_resp_ies_2, .ies_len = L_ARRAY_SIZE(p2p_probe_resp_ies_2), .payload_len = 58, .data = { .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CONCURRENT_OP, .group_caps = P2P_GROUP_CAP_GO, }, .device_info = { .device_addr = { 0xa2, 0x8c, 0xfd, 0xb9, 0x05, 0xef }, .wsc_config_methods = WSC_CONFIGURATION_METHOD_VIRTUAL_PUSH_BUTTON | 0x0800 | WSC_CONFIGURATION_METHOD_P2P | WSC_CONFIGURATION_METHOD_PHYSICAL_DISPLAY_PIN, .primary_device_type = { .category = 3, .oui = { 0x00, 0x50, 0xf2 }, .oui_type = 0x04, .subcategory = 1, }, .device_name = "DIRECT-EF-HP ENVY 4520 series", }, }, }; static void p2p_test_parse_probe_resp(const void *data) { const struct p2p_probe_resp_data *test = data; struct p2p_probe_resp attrs1, attrs2; const struct p2p_notice_of_absence_desc *desc = test->noa_descs; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->ies, test->ies_len, &payload_len); l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_probe_resp(test->ies, test->ies_len, &attrs1) == 0); memcpy(&attrs2, &test->data, sizeof(attrs2)); if (desc) attrs2.notice_of_absence.descriptors = l_queue_new(); while (desc && desc->start_time) { l_queue_push_tail(attrs2.notice_of_absence.descriptors, l_memdup(desc, sizeof(*desc))); desc++; } assert(attrs1.capability.device_caps == attrs2.capability.device_caps); assert(attrs1.capability.group_caps == attrs2.capability.group_caps); assert(attrs1.listen_availability.avail_period_ms == attrs2.listen_availability.avail_period_ms); assert(attrs1.listen_availability.avail_interval_ms == attrs2.listen_availability.avail_interval_ms); assert(attrs1.notice_of_absence.index == attrs2.notice_of_absence.index); assert(attrs1.notice_of_absence.opp_ps == attrs2.notice_of_absence.opp_ps); assert(attrs1.notice_of_absence.ct_window == attrs2.notice_of_absence.ct_window); assert(test_queue_cmp(attrs1.notice_of_absence.descriptors, attrs2.notice_of_absence.descriptors, p2p_noa_desc_cmp)); assert(!memcmp(attrs1.device_info.device_addr, attrs2.device_info.device_addr, 6)); assert(attrs1.device_info.wsc_config_methods == attrs2.device_info.wsc_config_methods); assert(attrs1.device_info.primary_device_type.category == attrs2.device_info.primary_device_type.category); assert(!memcmp(attrs1.device_info.primary_device_type.oui, attrs2.device_info.primary_device_type.oui, 3)); assert(attrs1.device_info.primary_device_type.oui_type == attrs2.device_info.primary_device_type.oui_type); assert(attrs1.device_info.primary_device_type.subcategory == attrs2.device_info.primary_device_type.subcategory); assert(l_queue_length(attrs1.device_info.secondary_device_types) == l_queue_length(attrs2.device_info.secondary_device_types)); assert(!strcmp(attrs1.device_info.device_name, attrs2.device_info.device_name)); assert(l_queue_length(attrs1.group_clients) == l_queue_length(attrs2.group_clients)); assert(l_queue_length(attrs1.advertised_svcs) == l_queue_length(attrs2.advertised_svcs)); p2p_clear_probe_resp(&attrs1); p2p_clear_probe_resp(&attrs2); } static void p2p_test_build_probe_resp(const void *data) { const struct p2p_probe_resp_data *test = data; struct p2p_probe_resp attrs2; const struct p2p_notice_of_absence_desc *desc = test->noa_descs; uint8_t *ies; size_t ies_len; memcpy(&attrs2, &test->data, sizeof(attrs2)); if (desc) attrs2.notice_of_absence.descriptors = l_queue_new(); while (desc && desc->start_time) { l_queue_push_tail(attrs2.notice_of_absence.descriptors, l_memdup(desc, sizeof(*desc))); desc++; } ies = p2p_build_probe_resp(&attrs2, &ies_len); p2p_clear_probe_resp(&attrs2); assert(p2p_payload_cmd(ies, ies_len, test->ies, test->ies_len)); l_free(ies); } static const uint8_t p2p_association_req_ies_1[] = { 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x4a, 0x00, 0x01, 0x10, 0x10, 0x3a, 0x00, 0x01, 0x01, 0x10, 0x49, 0x00, 0x06, 0x00, 0x37, 0x2a, 0x00, 0x01, 0x20, 0xdd, 0x29, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x27, 0x00, 0x0d, 0x1d, 0x00, 0x00, 0x28, 0xf8, 0xed, 0x26, 0x57, 0x11, 0x08, 0x00, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x64, 0x65, 0x76, 0x31, }; struct p2p_association_req_data { const uint8_t *ies; size_t ies_len; ssize_t payload_len; struct p2p_association_req data; }; static const struct p2p_association_req_data p2p_association_req_data_1 = { .ies = p2p_association_req_ies_1, .ies_len = L_ARRAY_SIZE(p2p_association_req_ies_1), .payload_len = 37, .data = { .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CLIENT_DISCOVERABILITY | P2P_DEVICE_CAP_CONCURRENT_OP | P2P_DEVICE_CAP_INVITATION_PROCEDURE, .group_caps = 0, }, .device_info = { .device_addr = { 0x00, 0x28, 0xf8, 0xed, 0x26, 0x57 }, .wsc_config_methods = WSC_CONFIGURATION_METHOD_DISPLAY | WSC_CONFIGURATION_METHOD_KEYPAD | WSC_CONFIGURATION_METHOD_P2P, .primary_device_type = { .category = 1, .oui = { 0x00, 0x50, 0xf2 }, .oui_type = 0x04, .subcategory = 1, }, .device_name = "testdev1", }, }, }; static void p2p_test_parse_association_req(const void *data) { const struct p2p_association_req_data *test = data; struct p2p_association_req attrs1, attrs2; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->ies, test->ies_len, &payload_len); l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_association_req(test->ies, test->ies_len, &attrs1) == 0); memcpy(&attrs2, &test->data, sizeof(attrs2)); assert(attrs1.capability.device_caps == attrs2.capability.device_caps); assert(attrs1.capability.group_caps == attrs2.capability.group_caps); assert(attrs1.listen_availability.avail_period_ms == attrs2.listen_availability.avail_period_ms); assert(attrs1.listen_availability.avail_interval_ms == attrs2.listen_availability.avail_interval_ms); assert(!memcmp(attrs1.device_info.device_addr, attrs2.device_info.device_addr, 6)); assert(attrs1.device_info.wsc_config_methods == attrs2.device_info.wsc_config_methods); assert(attrs1.device_info.primary_device_type.category == attrs2.device_info.primary_device_type.category); assert(!memcmp(attrs1.device_info.primary_device_type.oui, attrs2.device_info.primary_device_type.oui, 3)); assert(attrs1.device_info.primary_device_type.oui_type == attrs2.device_info.primary_device_type.oui_type); assert(attrs1.device_info.primary_device_type.subcategory == attrs2.device_info.primary_device_type.subcategory); assert(l_queue_length(attrs1.device_info.secondary_device_types) == l_queue_length(attrs2.device_info.secondary_device_types)); assert(!strcmp(attrs1.device_info.device_name, attrs2.device_info.device_name)); assert(!memcmp(attrs1.interface.device_addr, attrs2.interface.device_addr, 6)); assert(l_queue_length(attrs1.interface.interface_addrs) == l_queue_length(attrs2.interface.interface_addrs)); p2p_clear_association_req(&attrs1); p2p_clear_association_req(&attrs2); } static void p2p_test_build_association_req(const void *data) { const struct p2p_association_req_data *test = data; uint8_t *ies; size_t ies_len; ies = p2p_build_association_req(&test->data, &ies_len); assert(p2p_payload_cmd(ies, ies_len, test->ies, test->ies_len)); l_free(ies); } /* Obligatory P2P IE empty here */ static const uint8_t p2p_association_resp_ies_1[] = { 0x01, 0x08, 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0x2d, 0x1a, 0x73, 0x11, 0x03, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16, 0x64, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x04, 0x50, 0x6f, 0x9a, 0x09, 0x7f, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xbf, 0x0c, 0x30, 0x71, 0x90, 0x03, 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01, 0x80, 0x01, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, 0xdd, 0x07, 0x00, 0x0c, 0xe7, 0x08, 0x00, 0x00, 0x00, }; struct p2p_association_resp_data { const uint8_t *ies; size_t ies_len; ssize_t payload_len; struct p2p_association_resp data; }; static const struct p2p_association_resp_data p2p_association_resp_data_1 = { .ies = p2p_association_resp_ies_1, .ies_len = L_ARRAY_SIZE(p2p_association_resp_ies_1), .payload_len = 0, .data = {}, }; static void p2p_test_parse_association_resp(const void *data) { const struct p2p_association_resp_data *test = data; struct p2p_association_resp attrs1, attrs2; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->ies, test->ies_len, &payload_len); l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_association_resp(test->ies, test->ies_len, &attrs1) == 0); memcpy(&attrs2, &test->data, sizeof(attrs2)); assert(attrs1.status == attrs2.status); assert(attrs1.listen_availability.avail_period_ms == attrs2.listen_availability.avail_period_ms); assert(attrs1.listen_availability.avail_interval_ms == attrs2.listen_availability.avail_interval_ms); p2p_clear_association_resp(&attrs1); p2p_clear_association_resp(&attrs2); } static void p2p_test_build_association_resp(const void *data) { const struct p2p_association_resp_data *test = data; uint8_t *ies; size_t ies_len; ies = p2p_build_association_resp(&test->data, &ies_len); assert(p2p_payload_cmd(ies, ies_len, test->ies, test->ies_len)); l_free(ies); } static const uint8_t p2p_provision_disc_req_1[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09, 0x07, 0x01, 0xdd, 0x41, 0x50, 0x6f, 0x9a, 0x09, 0x02, 0x02, 0x00, 0x25, 0x00, 0x0d, 0x1d, 0x00, 0x00, 0x28, 0xf8, 0xed, 0x26, 0x57, 0x11, 0x08, 0x00, 0x01, 0x00, 0x50, 0xf2, 0x04, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x64, 0x65, 0x76, 0x31, 0x0f, 0x15, 0x00, 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x2d, 0x5a, 0x75, 0x2d, 0x54, 0x65, 0x73, 0x74, 0x31, 0xdd, 0x0a, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x08, 0x00, 0x02, 0x00, 0x80, }; struct p2p_provision_disc_req_data { const uint8_t *frame; size_t frame_len; ssize_t payload_len; struct p2p_provision_discovery_req data; }; static const struct p2p_provision_disc_req_data p2p_provision_disc_req_data_1 = { .frame = p2p_provision_disc_req_1, .frame_len = L_ARRAY_SIZE(p2p_provision_disc_req_1), .payload_len = 61, .data = { .dialog_token = 1, .capability = { .device_caps = P2P_DEVICE_CAP_SVC_DISCOVERY | P2P_DEVICE_CAP_CONCURRENT_OP | P2P_DEVICE_CAP_INVITATION_PROCEDURE, .group_caps = 0, }, .device_info = { .device_addr = { 0x00, 0x28, 0xf8, 0xed, 0x26, 0x57 }, .wsc_config_methods = WSC_CONFIGURATION_METHOD_DISPLAY | WSC_CONFIGURATION_METHOD_KEYPAD | WSC_CONFIGURATION_METHOD_P2P, .primary_device_type = { .category = 1, .oui = { 0x00, 0x50, 0xf2 }, .oui_type = 0x04, .subcategory = 1, }, .device_name = "testdev1", }, .group_id = { .device_addr = { 0x2a, 0xfe, 0xcd, 0x01, 0xbe, 0xa0 }, .ssid = "DIRECT-Zu-Test1", }, .status = -1, .wsc_config_method = WSC_CONFIGURATION_METHOD_PUSH_BUTTON, }, }; static void p2p_test_parse_provision_disc_req(const void *data) { const struct p2p_provision_disc_req_data *test = data; struct p2p_provision_discovery_req attrs1, attrs2; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->frame + 8, test->frame_len - 8, &payload_len); l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_provision_disc_req(test->frame + 7, test->frame_len - 7, &attrs1) == 0); memcpy(&attrs2, &test->data, sizeof(attrs2)); assert(attrs1.dialog_token == attrs2.dialog_token); assert(attrs1.capability.device_caps == attrs2.capability.device_caps); assert(attrs1.capability.group_caps == attrs2.capability.group_caps); assert(!memcmp(attrs1.device_info.device_addr, attrs2.device_info.device_addr, 6)); assert(attrs1.device_info.wsc_config_methods == attrs2.device_info.wsc_config_methods); assert(attrs1.device_info.primary_device_type.category == attrs2.device_info.primary_device_type.category); assert(!memcmp(attrs1.device_info.primary_device_type.oui, attrs2.device_info.primary_device_type.oui, 3)); assert(attrs1.device_info.primary_device_type.oui_type == attrs2.device_info.primary_device_type.oui_type); assert(attrs1.device_info.primary_device_type.subcategory == attrs2.device_info.primary_device_type.subcategory); assert(l_queue_length(attrs1.device_info.secondary_device_types) == l_queue_length(attrs2.device_info.secondary_device_types)); assert(!strcmp(attrs1.device_info.device_name, attrs2.device_info.device_name)); assert(!memcmp(attrs1.group_id.device_addr, attrs2.group_id.device_addr, 6)); assert(!strcmp(attrs1.group_id.ssid, attrs2.group_id.ssid)); assert(!memcmp(attrs1.intended_interface_addr, attrs2.intended_interface_addr, 6)); assert(attrs1.status == attrs2.status); assert(!memcmp(attrs1.operating_channel.country, attrs2.operating_channel.country, 3)); assert(attrs1.operating_channel.oper_class == attrs2.operating_channel.oper_class); assert(attrs1.operating_channel.channel_num == attrs2.operating_channel.channel_num); assert(!memcmp(attrs1.channel_list.country, attrs2.channel_list.country, 3)); assert(l_queue_length(attrs1.channel_list.channel_entries) == l_queue_length(attrs2.channel_list.channel_entries)); assert(attrs1.session_info.data_len == attrs2.session_info.data_len); assert(!attrs1.session_info.data_len || !memcmp(attrs1.session_info.data, attrs2.session_info.data, attrs1.session_info.data_len)); assert(attrs1.connection_capability == attrs2.connection_capability); assert(attrs1.advertisement_id.advertisement_id == attrs2.advertisement_id.advertisement_id); assert(!memcmp(attrs1.advertisement_id.service_mac_addr, attrs2.advertisement_id.service_mac_addr, 6)); assert(attrs1.config_timeout.go_config_timeout == attrs2.config_timeout.go_config_timeout); assert(attrs1.config_timeout.client_config_timeout == attrs2.config_timeout.client_config_timeout); assert(!memcmp(attrs1.listen_channel.country, attrs2.listen_channel.country, 3)); assert(attrs1.listen_channel.oper_class == attrs2.listen_channel.oper_class); assert(attrs1.listen_channel.channel_num == attrs2.listen_channel.channel_num); assert(attrs1.session_id.session_id == attrs2.session_id.session_id); assert(!memcmp(attrs1.session_id.session_mac_addr, attrs2.session_id.session_mac_addr, 6)); assert(attrs1.transport_protocol == attrs2.transport_protocol); assert(!memcmp(attrs1.persistent_group_info.device_addr, attrs2.persistent_group_info.device_addr, 6)); assert(!strcmp(attrs1.persistent_group_info.ssid, attrs2.persistent_group_info.ssid)); assert(attrs1.wsc_config_method == attrs2.wsc_config_method); p2p_clear_provision_disc_req(&attrs1); p2p_clear_provision_disc_req(&attrs2); } static void p2p_test_build_provision_disc_req(const void *data) { const struct p2p_provision_disc_req_data *test = data; uint8_t *frame; size_t frame_len; frame = p2p_build_provision_disc_req(&test->data, &frame_len); assert(!memcmp(frame, test->frame, 8)); assert(p2p_payload_cmd(frame + 8, frame_len - 8, test->frame + 8, test->frame_len - 8)); l_free(frame); } /* The optional P2P IE not present here */ static const uint8_t p2p_provision_disc_resp_1[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09, 0x08, 0x01, 0xdd, 0x0a, 0x00, 0x50, 0xf2, 0x04, 0x10, 0x08, 0x00, 0x02, 0x00, 0x80, 0xdd, 0x0d, 0x50, 0x6f, 0x9a, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x32, }; struct p2p_provision_disc_resp_data { const uint8_t *frame; size_t frame_len; ssize_t payload_len; struct p2p_provision_discovery_resp data; }; static const struct p2p_provision_disc_resp_data p2p_provision_disc_resp_data_1 = { .frame = p2p_provision_disc_resp_1, .frame_len = L_ARRAY_SIZE(p2p_provision_disc_resp_1), .payload_len = -ENOENT, .data = { .dialog_token = 1, .status = -1, .wsc_config_method = WSC_CONFIGURATION_METHOD_PUSH_BUTTON, }, }; static void p2p_test_parse_provision_disc_resp(const void *data) { const struct p2p_provision_disc_resp_data *test = data; struct p2p_provision_discovery_resp attrs1, attrs2; uint8_t *payload; ssize_t payload_len; payload = ie_tlv_extract_p2p_payload(test->frame + 8, test->frame_len - 8, &payload_len); if (payload_len >= 0) l_free(payload); assert(payload_len == test->payload_len); assert(p2p_parse_provision_disc_resp(test->frame + 7, test->frame_len - 7, &attrs1) == 0); memcpy(&attrs2, &test->data, sizeof(attrs2)); assert(attrs1.dialog_token == attrs2.dialog_token); assert(attrs1.status == attrs2.status); assert(attrs1.capability.device_caps == attrs2.capability.device_caps); assert(attrs1.capability.group_caps == attrs2.capability.group_caps); assert(!memcmp(attrs1.device_info.device_addr, attrs2.device_info.device_addr, 6)); assert(attrs1.device_info.wsc_config_methods == attrs2.device_info.wsc_config_methods); assert(attrs1.device_info.primary_device_type.category == attrs2.device_info.primary_device_type.category); assert(!memcmp(attrs1.device_info.primary_device_type.oui, attrs2.device_info.primary_device_type.oui, 3)); assert(attrs1.device_info.primary_device_type.oui_type == attrs2.device_info.primary_device_type.oui_type); assert(attrs1.device_info.primary_device_type.subcategory == attrs2.device_info.primary_device_type.subcategory); assert(l_queue_length(attrs1.device_info.secondary_device_types) == l_queue_length(attrs2.device_info.secondary_device_types)); assert(!strcmp(attrs1.device_info.device_name, attrs2.device_info.device_name)); assert(!memcmp(attrs1.group_id.device_addr, attrs2.group_id.device_addr, 6)); assert(!strcmp(attrs1.group_id.ssid, attrs2.group_id.ssid)); assert(!memcmp(attrs1.intended_interface_addr, attrs2.intended_interface_addr, 6)); assert(!memcmp(attrs1.operating_channel.country, attrs2.operating_channel.country, 3)); assert(attrs1.operating_channel.oper_class == attrs2.operating_channel.oper_class); assert(attrs1.operating_channel.channel_num == attrs2.operating_channel.channel_num); assert(!memcmp(attrs1.channel_list.country, attrs2.channel_list.country, 3)); assert(l_queue_length(attrs1.channel_list.channel_entries) == l_queue_length(attrs2.channel_list.channel_entries)); assert(attrs1.connection_capability == attrs2.connection_capability); assert(attrs1.advertisement_id.advertisement_id == attrs2.advertisement_id.advertisement_id); assert(!memcmp(attrs1.advertisement_id.service_mac_addr, attrs2.advertisement_id.service_mac_addr, 6)); assert(attrs1.config_timeout.go_config_timeout == attrs2.config_timeout.go_config_timeout); assert(attrs1.config_timeout.client_config_timeout == attrs2.config_timeout.client_config_timeout); assert(attrs1.session_id.session_id == attrs2.session_id.session_id); assert(!memcmp(attrs1.session_id.session_mac_addr, attrs2.session_id.session_mac_addr, 6)); assert(attrs1.transport_protocol == attrs2.transport_protocol); assert(!memcmp(attrs1.persistent_group_info.device_addr, attrs2.persistent_group_info.device_addr, 6)); assert(!strcmp(attrs1.persistent_group_info.ssid, attrs2.persistent_group_info.ssid)); assert(attrs1.session_info.data_len == attrs2.session_info.data_len); assert(!attrs1.session_info.data_len || !memcmp(attrs1.session_info.data, attrs2.session_info.data, attrs1.session_info.data_len)); assert(attrs1.wsc_config_method == attrs2.wsc_config_method); p2p_clear_provision_disc_resp(&attrs1); p2p_clear_provision_disc_resp(&attrs2); } int main(int argc, char *argv[]) { l_test_init(&argc, &argv); l_test_add("/p2p/iter/sanity-check", p2p_test_iter_sanity_check, NULL); l_test_add("/p2p/parse/Beacon IEs 1", p2p_test_parse_beacon, &p2p_beacon_data_1); l_test_add("/p2p/build/Beacon IEs 1", p2p_test_build_beacon, &p2p_beacon_data_1); l_test_add("/p2p/parse/Probe Request IEs 1", p2p_test_parse_probe_req, &p2p_probe_req_data_1); l_test_add("/p2p/build/Probe Request IEs 1", p2p_test_build_probe_req, &p2p_probe_req_data_1); l_test_add("/p2p/parse/Probe Response IEs 1", p2p_test_parse_probe_resp, &p2p_probe_resp_data_1); l_test_add("/p2p/parse/Probe Response IEs 2", p2p_test_parse_probe_resp, &p2p_probe_resp_data_2); l_test_add("/p2p/build/Probe Response IEs 1", p2p_test_build_probe_resp, &p2p_probe_resp_data_1); l_test_add("/p2p/build/Probe Response IEs 2", p2p_test_build_probe_resp, &p2p_probe_resp_data_2); l_test_add("/p2p/parse/Association Request IEs 1", p2p_test_parse_association_req, &p2p_association_req_data_1); l_test_add("/p2p/build/Association Request IEs 1", p2p_test_build_association_req, &p2p_association_req_data_1); l_test_add("/p2p/parse/Association Response IEs 1", p2p_test_parse_association_resp, &p2p_association_resp_data_1); l_test_add("/p2p/build/Association Response IEs 1", p2p_test_build_association_resp, &p2p_association_resp_data_1); l_test_add("/p2p/parse/Provision Discovery Request 1", p2p_test_parse_provision_disc_req, &p2p_provision_disc_req_data_1); l_test_add("/p2p/build/Provision Discovery Request 1", p2p_test_build_provision_disc_req, &p2p_provision_disc_req_data_1); l_test_add("/p2p/parse/Provision Discovery Response 1", p2p_test_parse_provision_disc_resp, &p2p_provision_disc_resp_data_1); return l_test_run(); }