/* * 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)