/*
* Copyright (c) 2017 The strace developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tests.h"
#include "print_fields.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include "netlink.h"
#include <linux/rtnetlink.h>
static void
init_nlattr(struct nlattr *const nla,
const uint16_t nla_len,
const uint16_t nla_type,
const void *const src,
const size_t n)
{
SET_STRUCT(struct nlattr, nla,
.nla_len = nla_len,
.nla_type = nla_type,
);
memcpy(RTA_DATA(nla), src, n);
}
static void
print_nlattr(const unsigned int nla_len, const char *const nla_type)
{
printf(", {{nla_len=%u, nla_type=%s}, ", nla_len, nla_type);
}
#define TEST_NLATTR_(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, nla_type_str_, \
nla_data_len_, src_, slen_, ...) \
do { \
struct nlmsghdr *const nlh = \
(nlh0_) - (NLA_HDRLEN + (slen_)); \
struct nlattr *const TEST_NLATTR_nla = \
NLMSG_ATTR(nlh, (hdrlen_)); \
const unsigned int nla_len = \
NLA_HDRLEN + (nla_data_len_); \
const unsigned int msg_len = \
NLMSG_SPACE(hdrlen_) + nla_len; \
\
(init_msg_)(nlh, msg_len); \
init_nlattr(TEST_NLATTR_nla, nla_len, (nla_type_), \
(src_), (slen_)); \
\
const char *const errstr = \
sprintrc(sendto((fd_), nlh, msg_len, \
MSG_DONTWAIT, NULL, 0)); \
\
printf("sendto(%d, {", (fd_)); \
(print_msg_)(msg_len); \
print_nlattr(nla_len, (nla_type_str_)); \
\
{ __VA_ARGS__; } \
\
printf("}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", \
msg_len, errstr); \
} while (0)
#define TEST_NLATTR(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, \
nla_data_len_, src_, slen_, ...) \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
(nla_data_len_), (src_), (slen_), __VA_ARGS__)
#define TEST_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, nla_type_str_, \
pattern_, obj_, fallback_func, ...) \
do { \
const unsigned int plen = \
sizeof(obj_) - 1 > DEFAULT_STRLEN \
? DEFAULT_STRLEN : (int) sizeof(obj_) - 1; \
/* len < sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
plen, (pattern_), plen, \
(fallback_func)((pattern_), plen)); \
/* short read of sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
sizeof(obj_), \
(pattern_), sizeof(obj_) - 1, \
printf("%p", \
RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_))))); \
/* sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
sizeof(obj_), \
&(obj_), sizeof(obj_), \
__VA_ARGS__); \
} while (0)
#define TEST_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, \
pattern_, obj_, fallback_func, ...) \
TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
(pattern_), (obj_), (fallback_func), \
__VA_ARGS__)
#define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, pattern_, obj_, ...) \
TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
(pattern_), (obj_), print_quoted_hex, \
__VA_ARGS__)
#define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, pattern_, obj_, print_elem_) \
do { \
const unsigned int plen = \
sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN \
? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1; \
/* len < sizeof((obj_)[0]) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
plen, (pattern_), plen, \
print_quoted_hex((pattern_), plen)); \
/* sizeof((obj_)[0]) < len < sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_) - 1, \
&(obj_), sizeof(obj_) - 1, \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf("]")); \
/* short read of sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_), \
&(obj_), sizeof(obj_) - 1, \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf(", %p]", \
RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_))) \
+ sizeof((obj_)[0]))); \
/* sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_), \
&(obj_), sizeof(obj_), \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_); ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf("]")); \
} while (0)
#define TEST_NESTED_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, nla_type_str_, \
pattern_, obj_, depth_, ...) \
do { \
const unsigned int plen = \
sizeof(obj_) - 1 > DEFAULT_STRLEN \
? DEFAULT_STRLEN : (int) sizeof(obj_) - 1; \
/* len < sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_, \
(hdrlen_) + NLA_HDRLEN * depth_, \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
plen, (pattern_), plen, \
print_quoted_hex((pattern_), plen); \
size_t i; \
for (i = 0; i < depth_; ++i) \
printf("}")); \
/* short read of sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_, \
(hdrlen_) + NLA_HDRLEN * depth_, \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
sizeof(obj_), \
(pattern_), sizeof(obj_) - 1, \
printf("%p", RTA_DATA(TEST_NLATTR_nla)); \
size_t i; \
for (i = 0; i < depth_; ++i) \
printf("}")); \
/* sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_, \
(hdrlen_) + NLA_HDRLEN * depth_, \
(init_msg_), (print_msg_), \
(nla_type_), (nla_type_str_), \
sizeof(obj_), \
&(obj_), sizeof(obj_), \
__VA_ARGS__; \
size_t i; \
for (i = 0; i < depth_; ++i) \
printf("}")); \
} while (0)
#define TEST_NESTED_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, pattern_, obj_, \
depth_, ...) \
TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
(pattern_), (obj_), (depth_), \
__VA_ARGS__)
#define TEST_NESTED_NLATTR_OBJECT(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, pattern_, obj_, ...) \
TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
(pattern_), (obj_), 1, \
__VA_ARGS__)
#define TEST_NESTED_NLATTR_ARRAY(fd_, nlh0_, hdrlen_, \
init_msg_, print_msg_, \
nla_type_, pattern_, obj_, print_elem_)\
do { \
const unsigned int plen = \
sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN \
? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1; \
/* len < sizeof((obj_)[0]) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN, \
(hdrlen_) + NLA_HDRLEN, \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
plen, (pattern_), plen, \
print_quoted_hex((pattern_), plen); \
printf("}")); \
/* sizeof((obj_)[0]) < len < sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN, \
(hdrlen_) + NLA_HDRLEN, \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_) - 1, \
&(obj_), sizeof(obj_) - 1, \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf("]}")); \
/* short read of sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN, \
(hdrlen_) + NLA_HDRLEN, \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_), \
&(obj_), sizeof(obj_) - 1, \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf(", %p]}", \
RTA_DATA(TEST_NLATTR_nla) \
+ sizeof((obj_)[0]))); \
/* sizeof(obj_) */ \
TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN, \
(hdrlen_) + NLA_HDRLEN, \
(init_msg_), (print_msg_), \
(nla_type_), #nla_type_, \
sizeof(obj_), \
&(obj_), sizeof(obj_), \
printf("["); \
size_t i; \
for (i = 0; i < ARRAY_SIZE(obj_); ++i) { \
if (i) printf(", "); \
(print_elem_)(&(obj_)[i]); \
} \
printf("]}")); \
} while (0)