1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 #include <sys/param.h> 6 #include <sys/module.h> 7 8 #include <netlink/netlink.h> 9 #include <netlink/netlink_route.h> 10 #include "netlink/netlink_snl.h" 11 #include "netlink/netlink_snl_route.h" 12 #include "netlink/netlink_snl_route_parsers.h" 13 14 #include <atf-c.h> 15 16 static void 17 require_netlink(void) 18 { 19 if (modfind("netlink") == -1) 20 atf_tc_skip("netlink module not loaded"); 21 } 22 23 ATF_TC(snl_verify_core_parsers); 24 ATF_TC_HEAD(snl_verify_core_parsers, tc) 25 { 26 atf_tc_set_md_var(tc, "descr", "Tests snl(3) core nlmsg parsers are correct"); 27 } 28 29 ATF_TC_BODY(snl_verify_core_parsers, tc) 30 { 31 SNL_VERIFY_PARSERS(snl_all_core_parsers); 32 33 } 34 35 ATF_TC(snl_verify_route_parsers); 36 ATF_TC_HEAD(snl_verify_route_parsers, tc) 37 { 38 atf_tc_set_md_var(tc, "descr", "Tests snl(3) route parsers are correct"); 39 } 40 41 ATF_TC_BODY(snl_verify_route_parsers, tc) 42 { 43 SNL_VERIFY_PARSERS(snl_all_route_parsers); 44 45 } 46 47 ATF_TC(snl_parse_errmsg_capped); 48 ATF_TC_HEAD(snl_parse_errmsg_capped, tc) 49 { 50 atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing capped errors"); 51 } 52 53 ATF_TC_BODY(snl_parse_errmsg_capped, tc) 54 { 55 struct snl_state ss; 56 struct snl_writer nw; 57 58 require_netlink(); 59 60 if (!snl_init(&ss, NETLINK_ROUTE)) 61 atf_tc_fail("snl_init() failed"); 62 63 int optval = 1; 64 ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval, sizeof(optval)) == 0); 65 66 snl_init_writer(&ss, &nw); 67 68 struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); 69 ATF_CHECK(hdr != NULL); 70 ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); 71 snl_add_msg_attr_string(&nw, 143, "some random string"); 72 ATF_CHECK(snl_finalize_msg(&nw) != NULL); 73 74 ATF_CHECK(snl_send_message(&ss, hdr)); 75 76 struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); 77 ATF_CHECK(rx_hdr != NULL); 78 ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); 79 80 struct snl_errmsg_data e = {}; 81 ATF_CHECK(rx_hdr->nlmsg_len == sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr)); 82 ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); 83 ATF_CHECK(e.error != 0); 84 ATF_CHECK(!memcmp(hdr, e.orig_hdr, sizeof(struct nlmsghdr))); 85 } 86 87 ATF_TC(snl_parse_errmsg_capped_extack); 88 ATF_TC_HEAD(snl_parse_errmsg_capped_extack, tc) 89 { 90 atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing capped errors with extack"); 91 } 92 93 ATF_TC_BODY(snl_parse_errmsg_capped_extack, tc) 94 { 95 struct snl_state ss; 96 struct snl_writer nw; 97 98 require_netlink(); 99 100 if (!snl_init(&ss, NETLINK_ROUTE)) 101 atf_tc_fail("snl_init() failed"); 102 103 int optval = 1; 104 ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval, sizeof(optval)) == 0); 105 optval = 1; 106 ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, sizeof(optval)) == 0); 107 108 snl_init_writer(&ss, &nw); 109 110 struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); 111 ATF_CHECK(hdr != NULL); 112 ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); 113 snl_add_msg_attr_string(&nw, 143, "some random string"); 114 ATF_CHECK(snl_finalize_msg(&nw) != NULL); 115 116 ATF_CHECK(snl_send_message(&ss, hdr)); 117 118 struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); 119 ATF_CHECK(rx_hdr != NULL); 120 ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); 121 122 struct snl_errmsg_data e = {}; 123 ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); 124 ATF_CHECK(e.error != 0); 125 ATF_CHECK(!memcmp(hdr, e.orig_hdr, sizeof(struct nlmsghdr))); 126 127 ATF_CHECK(e.error_str != NULL); 128 } 129 130 ATF_TC(snl_parse_errmsg_uncapped_extack); 131 ATF_TC_HEAD(snl_parse_errmsg_uncapped_extack, tc) 132 { 133 atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing errors with extack"); 134 } 135 136 ATF_TC_BODY(snl_parse_errmsg_uncapped_extack, tc) 137 { 138 struct snl_state ss; 139 struct snl_writer nw; 140 141 require_netlink(); 142 143 ATF_CHECK(snl_init(&ss, NETLINK_ROUTE)); 144 145 int optval = 1; 146 ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, sizeof(optval)) == 0); 147 148 snl_init_writer(&ss, &nw); 149 150 struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); 151 ATF_CHECK(hdr != NULL); 152 ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); 153 snl_add_msg_attr_string(&nw, 143, "some random string"); 154 ATF_CHECK(snl_finalize_msg(&nw) != NULL); 155 156 ATF_CHECK(snl_send_message(&ss, hdr)); 157 158 struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); 159 ATF_CHECK(rx_hdr != NULL); 160 ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); 161 162 struct snl_errmsg_data e = {}; 163 ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); 164 ATF_CHECK(e.error != 0); 165 ATF_CHECK(!memcmp(hdr, e.orig_hdr, hdr->nlmsg_len)); 166 167 ATF_CHECK(e.error_str != NULL); 168 } 169 170 ATF_TC(snl_list_ifaces); 171 ATF_TC_HEAD(snl_list_ifaces, tc) 172 { 173 atf_tc_set_md_var(tc, "descr", "Tests snl(3) listing interfaces"); 174 } 175 176 struct nl_parsed_link { 177 uint32_t ifi_index; 178 uint32_t ifla_mtu; 179 char *ifla_ifname; 180 }; 181 182 #define _IN(_field) offsetof(struct ifinfomsg, _field) 183 #define _OUT(_field) offsetof(struct nl_parsed_link, _field) 184 static struct snl_attr_parser ap_link[] = { 185 { .type = IFLA_IFNAME, .off = _OUT(ifla_ifname), .cb = snl_attr_get_string }, 186 { .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = snl_attr_get_uint32 }, 187 }; 188 static struct snl_field_parser fp_link[] = { 189 {.off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 }, 190 }; 191 #undef _IN 192 #undef _OUT 193 SNL_DECLARE_PARSER(link_parser, struct ifinfomsg, fp_link, ap_link); 194 195 196 ATF_TC_BODY(snl_list_ifaces, tc) 197 { 198 struct snl_state ss; 199 struct snl_writer nw; 200 201 require_netlink(); 202 203 if (!snl_init(&ss, NETLINK_ROUTE)) 204 atf_tc_fail("snl_init() failed"); 205 206 snl_init_writer(&ss, &nw); 207 208 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 209 ATF_CHECK(hdr != NULL); 210 ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); 211 ATF_CHECK(snl_finalize_msg(&nw) != NULL); 212 uint32_t seq_id = hdr->nlmsg_seq; 213 214 ATF_CHECK(snl_send_message(&ss, hdr)); 215 216 struct snl_errmsg_data e = {}; 217 int count = 0; 218 219 while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { 220 count++; 221 } 222 ATF_REQUIRE(e.error == 0); 223 224 ATF_REQUIRE_MSG(count > 0, "Empty interface list"); 225 } 226 227 ATF_TP_ADD_TCS(tp) 228 { 229 ATF_TP_ADD_TC(tp, snl_verify_core_parsers); 230 ATF_TP_ADD_TC(tp, snl_verify_route_parsers); 231 ATF_TP_ADD_TC(tp, snl_parse_errmsg_capped); 232 ATF_TP_ADD_TC(tp, snl_parse_errmsg_capped_extack); 233 ATF_TP_ADD_TC(tp, snl_parse_errmsg_uncapped_extack); 234 ATF_TP_ADD_TC(tp, snl_list_ifaces); 235 236 return (atf_no_error()); 237 } 238