blob: b1c5275a6d5d78b574d95d3d1f0030f0d17c18ff [file] [log] [blame]
/*
*
* Embedded Linux library
*
* Copyright (C) 2011-2014 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 <config.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <linux/genetlink.h>
#include <ell/ell.h>
#include "ell/genl-private.h"
static bool do_print = false;
static void do_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
printf("%s%s\n", prefix, str);
}
static unsigned char set_station_request[] = {
0x34, 0x00, 0x00, 0x00, 0x17, 0x00, 0x05, 0x00, 0x8b, 0x53, 0x0d, 0x55,
0x14, 0x0e, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x24, 0xa2, 0xe1, 0xec,
0x17, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x43, 0x00, 0x02, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
};
static void parse_set_station(const void *data)
{
static const unsigned char mac[6] =
{ 0x24, 0xa2, 0xe1, 0xec, 0x17, 0x04 };
struct nlmsghdr *nlmsg;
struct l_genl_msg *msg;
struct l_genl_attr attr;
bool result;
uint16_t type;
uint16_t len;
const void *payload;
nlmsg = (struct nlmsghdr *) set_station_request;
msg = _genl_msg_create(nlmsg);
assert(msg);
assert(l_genl_msg_get_command(msg) == 18);
result = l_genl_attr_init(&attr, msg);
assert(result);
/*Interface Index: 3 (0x00000003) */
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 3);
assert(len == 4);
assert(*((unsigned int *) payload) == 3);
/* MAC Address 24:A2:E1:EC:17:04 */
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 6);
assert(len == 6);
assert(!memcmp(payload, mac, 6));
/* Station Flags 2: len 8
* Mask: 0x00000002
* Authorized
* Set: 0x00000002
* Authorized
*/
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 67);
assert(len == 8);
assert(((unsigned int *) payload)[0] == 2);
assert(((unsigned int *) payload)[1] == 2);
l_genl_msg_unref(msg);
}
static void build_set_station(const void *data)
{
static uint32_t index = 3;
static const unsigned char mac[6] =
{ 0x24, 0xa2, 0xe1, 0xec, 0x17, 0x04 };
static uint32_t flags[] = { 2, 2 };
struct l_genl_msg *msg;
const void *raw;
size_t size;
msg = l_genl_msg_new_sized(18, 512);
assert(msg);
assert(l_genl_msg_append_attr(msg, 3, 4, &index));
assert(l_genl_msg_append_attr(msg, 6, 6, mac));
assert(l_genl_msg_append_attr(msg, 67, 8, flags));
raw = _genl_msg_as_bytes(msg, 0x17, 0x05, 0x550d538b, 3604, &size);
if (do_print) {
l_util_hexdump(false, raw, size, do_debug, "[MSG] ");
l_util_hexdump(true, set_station_request, size,
do_debug, "[MSG] ");
}
assert(size == sizeof(set_station_request));
assert(!memcmp(raw, set_station_request, size));
l_genl_msg_unref(msg);
}
static const unsigned char set_rekey_offload_request[] = {
0x54, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x59, 0xa3, 0xe1, 0x53,
0xba, 0x02, 0x40, 0xe7, 0x4f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x7a, 0x00, 0x14, 0x00, 0x01, 0x00,
0x2f, 0x82, 0xbb, 0x0d, 0x93, 0x56, 0x60, 0x4b, 0xb1, 0x55, 0x1c, 0x85,
0xc0, 0xeb, 0x32, 0x8b, 0x14, 0x00, 0x02, 0x00, 0x43, 0x25, 0xcf, 0x08,
0x0b, 0x92, 0xa7, 0x2d, 0x86, 0xdc, 0x43, 0x21, 0xd6, 0x0c, 0x12, 0x03,
0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
static void parse_set_rekey_offload(const void *data)
{
static const unsigned char kek[] = {
0x2f, 0x82, 0xbb, 0x0d, 0x93, 0x56, 0x60, 0x4b,
0xb1, 0x55, 0x1c, 0x85, 0xc0, 0xeb, 0x32, 0x8b };
static const unsigned char kck[] = {
0x43, 0x25, 0xcf, 0x08, 0x0b, 0x92, 0xa7, 0x2d,
0x86, 0xdc, 0x43, 0x21, 0xd6, 0x0c, 0x12, 0x03 };
static const unsigned char replay_counter[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
struct nlmsghdr *nlmsg;
struct l_genl_msg *msg;
struct l_genl_attr attr;
struct l_genl_attr nested;
bool result;
uint16_t type;
uint16_t len;
const void *payload;
nlmsg = (struct nlmsghdr *) set_rekey_offload_request;
msg = _genl_msg_create(nlmsg);
assert(msg);
assert(l_genl_msg_get_command(msg) == 79);
result = l_genl_attr_init(&attr, msg);
assert(result);
/*Interface Index: 3 (0x00000003) */
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 3);
assert(len == 4);
assert(*((unsigned int *) payload) == 3);
/*
* Rekey Data: len 52
* KEK: len 16
* 2f 82 bb 0d 93 56 60 4b b1 55 1c 85 c0 eb 32 8b
* KCK: len 16
* 43 25 cf 08 0b 92 a7 2d 86 dc 43 21 d6 0c 12 03
* Replay CTR: len 8
* 00 00 00 00 00 00 00 01
*/
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 122);
assert(len == 52);
assert(l_genl_attr_recurse(&attr, &nested));
assert(l_genl_attr_next(&nested, &type, &len, &payload));
assert(type == 1);
assert(len == 16);
assert(!memcmp(payload, kek, 16));
assert(l_genl_attr_next(&nested, &type, &len, &payload));
assert(type == 2);
assert(len == 16);
assert(!memcmp(payload, kck, 16));
assert(l_genl_attr_next(&nested, &type, &len, &payload));
assert(type == 3);
assert(len == 8);
assert(!memcmp(payload, replay_counter, 8));
l_genl_msg_unref(msg);
}
static void build_set_rekey_offload(const void *data)
{
static uint32_t index = 3;
static const unsigned char kek[] = {
0x2f, 0x82, 0xbb, 0x0d, 0x93, 0x56, 0x60, 0x4b,
0xb1, 0x55, 0x1c, 0x85, 0xc0, 0xeb, 0x32, 0x8b };
static const unsigned char kck[] = {
0x43, 0x25, 0xcf, 0x08, 0x0b, 0x92, 0xa7, 0x2d,
0x86, 0xdc, 0x43, 0x21, 0xd6, 0x0c, 0x12, 0x03 };
static const unsigned char replay_counter[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
struct l_genl_msg *msg;
const void *raw;
size_t size;
msg = l_genl_msg_new_sized(79, 0);
assert(msg);
assert(l_genl_msg_append_attr(msg, 3, 4, &index));
assert(l_genl_msg_enter_nested(msg, 122));
assert(l_genl_msg_append_attr(msg, 1, 16, kek));
assert(l_genl_msg_append_attr(msg, 2, 16, kck));
assert(l_genl_msg_append_attr(msg, 3, 8, replay_counter));
assert(l_genl_msg_leave_nested(msg));
raw = _genl_msg_as_bytes(msg, 0x1b, 0x05, 0x53e1a359, 0xe74002ba,
&size);
if (do_print) {
l_util_hexdump(false, raw, size, do_debug, "[MSG] ");
l_util_hexdump(true, set_rekey_offload_request, size,
do_debug, "[MSG] ");
}
assert(size == sizeof(set_rekey_offload_request));
assert(!memcmp(raw, set_rekey_offload_request, size));
l_genl_msg_unref(msg);
}
/*
* This example is generated by libnl:
msg = nlmsg_alloc();
hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ops.o_id,
0, 0, TASKSTATS_CMD_GET, TASKSTATS_GENL_VERSION);
nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 1);
nest1 = nla_nest_start(msg, 0x45);
nla_put_string(msg, 0x46, "f");
nla_put_string(msg, 0x47, "foob");
nla_put_string(msg, 0x48, "foobar");
nest2 = nla_nest_start(msg, 0x49);
nla_put_string(msg, 0x50, "ba");
nla_nest_end(msg, nest2);
nla_nest_end(msg, nest1);
*/
static const unsigned char libnl_nested[] = {
0x4c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x05, 0x00, 0x72, 0x05, 0x13, 0x55,
0x77, 0x68, 0x40, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x45, 0x00, 0x06, 0x00, 0x46, 0x00,
0x66, 0x00, 0x00, 0x00, 0x09, 0x00, 0x47, 0x00, 0x66, 0x6f, 0x6f, 0x62,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x48, 0x00, 0x66, 0x6f, 0x6f, 0x62,
0x61, 0x72, 0x00, 0x00, 0x0c, 0x00, 0x49, 0x00, 0x07, 0x00, 0x50, 0x00,
0x62, 0x61, 0x00, 0x00,
};
static void parse_libnl_nested(const void *data)
{
struct nlmsghdr *nlmsg;
struct l_genl_msg *msg;
struct l_genl_attr attr;
struct l_genl_attr nested1;
struct l_genl_attr nested2;
bool result;
uint16_t type;
uint16_t len;
const void *payload;
nlmsg = (struct nlmsghdr *) libnl_nested;
msg = _genl_msg_create(nlmsg);
assert(msg);
assert(l_genl_msg_get_command(msg) == 1);
result = l_genl_attr_init(&attr, msg);
assert(result);
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 1);
assert(len == 4);
assert(*((unsigned int *) payload) == 1);
assert(l_genl_attr_next(&attr, &type, &len, &payload));
assert(type == 0x45);
assert(len == 44);
assert(l_genl_attr_recurse(&attr, &nested1));
assert(l_genl_attr_next(&nested1, &type, &len, &payload));
assert(type == 0x46);
assert(len == 2);
assert(!strcmp(payload, "f"));
assert(l_genl_attr_next(&nested1, &type, &len, &payload));
assert(type == 0x47);
assert(len == 5);
assert(!strcmp(payload, "foob"));
assert(l_genl_attr_next(&nested1, &type, &len, &payload));
assert(type == 0x48);
assert(len == 7);
assert(!strcmp(payload, "foobar"));
assert(l_genl_attr_next(&nested1, &type, &len, &payload));
assert(type == 0x49);
assert(len == 8);
assert(l_genl_attr_recurse(&nested1, &nested2));
assert(l_genl_attr_next(&nested2, &type, &len, &payload));
assert(type == 0x50);
assert(len == 3);
assert(!strcmp(payload, "ba"));
l_genl_msg_unref(msg);
}
static void build_libnl_nested(const void *data)
{
static uint32_t index = 1;
struct l_genl_msg *msg;
const void *raw;
size_t size;
msg = l_genl_msg_new_sized(1, 16);
assert(msg);
assert(l_genl_msg_append_attr(msg, 1, 4, &index));
assert(l_genl_msg_enter_nested(msg, 0x45));
assert(l_genl_msg_append_attr(msg, 0x46, 2, "f"));
assert(l_genl_msg_append_attr(msg, 0x47, 5, "foob"));
assert(l_genl_msg_append_attr(msg, 0x48, 7, "foobar"));
assert(l_genl_msg_enter_nested(msg, 0x49));
assert(l_genl_msg_append_attr(msg, 0x50, 3, "ba"));
assert(l_genl_msg_leave_nested(msg));
assert(l_genl_msg_leave_nested(msg));
raw = _genl_msg_as_bytes(msg, 0x15, 0x05, 0x55130572, 0x0c406877,
&size);
if (do_print) {
l_util_hexdump(false, raw, size, do_debug, "[MSG] ");
l_util_hexdump(true, libnl_nested, sizeof(libnl_nested),
do_debug, "[MSG] ");
}
assert(size == sizeof(libnl_nested));
assert(!memcmp(raw, libnl_nested, size));
l_genl_msg_unref(msg);
}
static void test_append_attrv(const void *data)
{
static const int num_blocks = 3;
unsigned char * const payload = set_station_request;
const size_t total_len = L_ARRAY_SIZE(set_station_request);
const size_t block_len = total_len / num_blocks;
const struct iovec iov[] = {
{
.iov_base = payload,
.iov_len = block_len
},
{
.iov_base = payload + block_len,
.iov_len = block_len
},
{
.iov_base = payload + block_len * 2,
.iov_len = total_len - block_len * 2
}
};
struct l_genl_msg *msg;
const uint16_t type = 2;
struct l_genl_attr attr;
uint16_t attr_type;
uint16_t attr_len;
const void *attr_payload;
assert(L_ARRAY_SIZE(iov) == num_blocks);
msg = l_genl_msg_new_sized(1, NLA_HDRLEN + NLA_ALIGN(total_len));
assert(msg);
assert(l_genl_msg_append_attrv(msg, type, iov, L_ARRAY_SIZE(iov)));
assert(l_genl_attr_init(&attr, msg));
assert(l_genl_attr_next(&attr, &attr_type, &attr_len, &attr_payload));
assert(type == attr_type);
assert(total_len == attr_len);
assert(memcmp(payload, attr_payload, total_len) == 0);
l_genl_msg_unref(msg);
}
int main(int argc, char *argv[])
{
bool little_endian;
#if __BYTE_ORDER == __LITTLE_ENDIAN
little_endian = true;
#elif __BYTE_ORDER == __BIG_ENDIAN
little_endian = false;
#else
#error "Unknown byte order"
#endif
l_test_init(&argc, &argv);
if (!little_endian)
goto done;
l_test_add("Parse Set Station Request", parse_set_station, NULL);
l_test_add("Parse Set Rekey Offload Request",
parse_set_rekey_offload, NULL);
l_test_add("Build Set Station Request", build_set_station, NULL);
l_test_add("Build Set Rekey Offload Request",
build_set_rekey_offload, NULL);
l_test_add("libnl-generated Example with Nesting",
parse_libnl_nested, NULL);
l_test_add("Build libnl-generated Example with Nesting",
build_libnl_nested, NULL);
l_test_add("Test l_genl_msg_append_attrv",
test_append_attrv, NULL);
done:
return l_test_run();
}