1 /*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017-2021 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #include <stdio.h>
12 #include "test_nlattr.h"
13 #include <arpa/inet.h>
14 #include <linux/if_bridge.h>
15 #include <linux/rtnetlink.h>
16
17 const unsigned int hdrlen = sizeof(struct br_port_msg);
18
19 static void
20 init_br_port_msg(struct nlmsghdr *const nlh, const unsigned int msg_len)
21 {
22 unsigned int len = msg_len;
23
24 SET_STRUCT(struct nlmsghdr, nlh,
25 .nlmsg_len = len,
26 .nlmsg_type = RTM_GETMDB,
27 .nlmsg_flags = NLM_F_DUMP
28 );
29
30 struct br_port_msg *const msg = NLMSG_DATA(nlh);
31 SET_STRUCT(struct br_port_msg, msg,
32 .family = AF_UNIX,
33 .ifindex = ifindex_lo()
34 );
35
36 struct nlattr *nla = NLMSG_ATTR(nlh, sizeof(*msg));
37 len -= NLMSG_SPACE(hdrlen);
38 SET_STRUCT(struct nlattr, nla,
39 .nla_len = len,
40 .nla_type = MDBA_MDB
41 );
42
43 nla = nla + 1;
44 len -= NLA_HDRLEN;
45 SET_STRUCT(struct nlattr, nla,
46 .nla_len = len,
47 .nla_type = MDBA_MDB_ENTRY
48 );
49 }
50
51 static void
52 print_br_port_msg(const unsigned int msg_len)
53 {
54 printf("{nlmsg_len=%u, nlmsg_type=RTM_GETMDB, nlmsg_flags=NLM_F_DUMP"
55 ", nlmsg_seq=0, nlmsg_pid=0}, {family=AF_UNIX"
56 ", ifindex=" IFINDEX_LO_STR "}"
57 ", [{nla_len=%u, nla_type=MDBA_MDB}"
58 ", [{nla_len=%u, nla_type=MDBA_MDB_ENTRY}",
59 msg_len, msg_len - NLMSG_SPACE(hdrlen),
60 msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN);
61 }
62
63 int
64 main(void)
65 {
66 skip_if_unavailable("/proc/self/fd/");
67
68 const int fd = create_nl_socket(NETLINK_ROUTE);
69
70 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + 4
71 - 4 + NLA_HDRLEN * 2 + sizeof(struct nlattr)
72 + sizeof(struct br_mdb_entry)
73 );
74
75 static char pattern[4096];
76 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
77
78 const unsigned int nla_type = 0xffff & NLA_TYPE_MASK;
79 char nla_type_str[256];
80 sprintf(nla_type_str, "%#x /* MDBA_MDB_ENTRY_??? */", nla_type);
81 TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * 2, hdrlen + NLA_HDRLEN * 2,
82 init_br_port_msg, print_br_port_msg,
83 nla_type, nla_type_str,
84 4, pattern, 4,
85 print_quoted_hex(pattern, 4);
86 printf("]]"));
87
88 struct br_mdb_entry entry = {
89 .ifindex = ifindex_lo(),
90 .state = MDB_TEMPORARY,
91 .flags = MDB_FLAGS_OFFLOAD,
92 .vid = 0xcdef,
93 .addr = {
94 .proto = htons(AF_UNSPEC)
95 }
96 };
97
98 memcpy(&entry.addr.u, pattern, sizeof(entry.addr.u));
99 TEST_NESTED_NLATTR_OBJECT_EX(fd, nlh0, hdrlen,
100 init_br_port_msg, print_br_port_msg,
101 MDBA_MDB_ENTRY_INFO, pattern, entry, 2,
102 printf("{ifindex=" IFINDEX_LO_STR);
103 printf(", state=MDB_TEMPORARY");
104 printf(", flags=MDB_FLAGS_OFFLOAD");
105 printf(", ");
106 PRINT_FIELD_U(entry, vid);
107 printf(", addr={u=");
108 print_quoted_hex(&entry.addr.u,
109 sizeof(entry.addr.u));
110 printf(", proto=htons(AF_UNSPEC)}}"));
111
112 static const struct nlattr nla = {
113 .nla_len = sizeof(nla),
114 .nla_type = MDBA_MDB_EATTR_TIMER
115 };
116 char buf[NLMSG_ALIGN(sizeof(entry)) + sizeof(nla)];
117 memcpy(buf, &entry, sizeof(entry));
118 memcpy(buf + NLMSG_ALIGN(sizeof(entry)), &nla, sizeof(nla));
119 TEST_NLATTR(fd, nlh0 - NLA_HDRLEN * 2, hdrlen + NLA_HDRLEN * 2,
120 init_br_port_msg, print_br_port_msg,
121 MDBA_MDB_ENTRY_INFO, sizeof(buf), buf, sizeof(buf),
122 printf("{ifindex=" IFINDEX_LO_STR);
123 printf(", state=MDB_TEMPORARY");
124 printf(", flags=MDB_FLAGS_OFFLOAD");
125 printf(", ");
126 PRINT_FIELD_U(entry, vid);
127 printf(", addr={u=");
128 print_quoted_hex(&entry.addr.u, sizeof(entry.addr.u));
129 printf(", proto=htons(AF_UNSPEC)}}"
130 ", {nla_len=%u, nla_type=MDBA_MDB_EATTR_TIMER}]]",
131 nla.nla_len));
132
133 puts("+++ exited with 0 +++");
134 return 0;
135 }