1 /* 2 * Copyright (c) 2015 Fujitsu Ltd. 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 * Author: David L Stevens 19 */ 20 21 #include "config.h" 22 23 #include <stdio.h> 24 #include <unistd.h> 25 #include <errno.h> 26 #include <netdb.h> 27 #include <libgen.h> 28 #include <pthread.h> 29 #include <semaphore.h> 30 31 #include <sys/time.h> 32 #include <netinet/in.h> 33 #include <netinet/ip6.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <net/if.h> 37 #include <sys/ioctl.h> 38 #ifdef HAVE_IFADDRS_H 39 #include <ifaddrs.h> 40 #endif 41 #include <arpa/inet.h> 42 43 #include "test.h" 44 #include "safe_macros.h" 45 46 char *TCID = "asapi_06"; 47 48 int TST_TOTAL = 1; 49 50 #define READ_TIMEOUT 5 /* secs */ 51 52 static void do_tests(void); 53 static void setup(void); 54 55 int main(int argc, char *argv[]) 56 { 57 int lc; 58 59 tst_parse_opts(argc, argv, NULL, NULL); 60 61 setup(); 62 63 for (lc = 0; TEST_LOOPING(lc); ++lc) 64 do_tests(); 65 66 tst_exit(); 67 } 68 69 #define NH_TEST 0x9f 70 71 #ifndef IPV6_RECVPKTINFO 72 #define IPV6_RECVPKTINFO -1 73 #endif 74 #ifndef IPV6_RECVHOPLIMIT 75 #define IPV6_RECVHOPLIMIT -1 76 #endif 77 #ifndef IPV6_RECVRTHDR 78 #define IPV6_RECVRTHDR -1 79 #endif 80 #ifndef IPV6_RECVHOPOPTS 81 #define IPV6_RECVHOPOPTS -1 82 #endif 83 #ifndef IPV6_RECVDSTOPTS 84 #define IPV6_RECVDSTOPTS -1 85 #endif 86 #ifndef IPV6_RECVTCLASS 87 #define IPV6_RECVTCLASS -1 88 #endif 89 #ifndef IPV6_TCLASS 90 #define IPV6_TCLASS -1 91 #endif 92 #ifndef IPV6_2292PKTINFO 93 #define IPV6_2292PKTINFO -1 94 #endif 95 #ifndef IPV6_2292HOPLIMIT 96 #define IPV6_2292HOPLIMIT -1 97 #endif 98 #ifndef IPV6_2292RTHDR 99 #define IPV6_2292RTHDR -1 100 #endif 101 #ifndef IPV6_2292HOPOPTS 102 #define IPV6_2292HOPOPTS -1 103 #endif 104 #ifndef IPV6_2292DSTOPTS 105 #define IPV6_2292DSTOPTS -1 106 #endif 107 108 union soval { 109 struct in6_pktinfo sou_pktinfo; 110 int sou_hoplimit; 111 struct sockaddr_in6 sou_nexthop; 112 struct ip6_rthdr sou_rthdr; 113 struct ip6_hbh sou_hopopts; 114 struct ip6_dest sou_dstopts; 115 struct ip6_dest sou_rthdrdstopts; 116 int sou_tclass; 117 int sou_bool; 118 }; 119 120 /* in6_addr initializer for loopback interface */ 121 #define IN6_LOOP {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } 122 #define IN6_ANY {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } 123 124 /* so_clrval and so_setval members are initilized in the body */ 125 static struct soent { 126 char *so_tname; 127 int so_opt; 128 int so_dorecv; /* do receive test? */ 129 int so_cmtype; 130 int so_clear; /* get fresh socket? */ 131 union soval so_clrval; 132 union soval so_setval; 133 socklen_t so_valsize; 134 } sotab[] = { 135 /* RFC 3542, Section 4 */ 136 {"IPV6_RECVPKTINFO", IPV6_RECVPKTINFO, 1, IPV6_PKTINFO, 1, 137 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 138 {"IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT, 1, IPV6_HOPLIMIT, 1, 139 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 140 {"IPV6_RECVRTHDR", IPV6_RECVRTHDR, 0, IPV6_RTHDR, 1, 141 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 142 {"IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS, 0, IPV6_HOPOPTS, 1, 143 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 144 {"IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS, 0, IPV6_DSTOPTS, 1, 145 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 146 {"IPV6_RECVTCLASS", IPV6_RECVTCLASS, 1, IPV6_TCLASS, 1, 147 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 148 /* make sure TCLASS stays when setting another opt */ 149 {"IPV6_RECVTCLASS (2)", IPV6_RECVHOPLIMIT, 1, IPV6_TCLASS, 0, 150 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 151 /* OLD values */ 152 {"IPV6_2292PKTINFO", IPV6_2292PKTINFO, 1, IPV6_2292PKTINFO, 1, 153 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 154 {"IPV6_2292HOPLIMIT", IPV6_2292HOPLIMIT, 1, IPV6_2292HOPLIMIT, 1, 155 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 156 {"IPV6_2292RTHDR", IPV6_2292RTHDR, 0, IPV6_2292RTHDR, 1, 157 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 158 {"IPV6_2292HOPOPTS", IPV6_2292HOPOPTS, 0, IPV6_2292HOPOPTS, 1, 159 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 160 {"IPV6_2292DSTOPTS", IPV6_2292DSTOPTS, 0, IPV6_2292DSTOPTS, 1, 161 {{{{{0} } }, 0} }, {{{{{0} } }, 0} }, sizeof(int)}, 162 }; 163 164 #define SOCOUNT ARRAY_SIZE(sotab) 165 166 struct soprot { 167 int sop_pid; /* sender PID */ 168 int sop_seq; /* sequence # */ 169 int sop_dlen; /* tp_dat length */ 170 unsigned char sop_dat[0]; /* user data */ 171 }; 172 173 static unsigned char tpbuf[sizeof(struct soprot) + 2048]; 174 static unsigned char rpbuf[sizeof(struct soprot) + 2048]; 175 176 static unsigned char control[2048]; 177 178 static int seq; 179 180 static struct cme { 181 int cm_len; 182 int cm_level; 183 int cm_type; 184 union { 185 uint32_t cmu_tclass; 186 uint32_t cmu_hops; 187 } cmu; 188 } cmtab[] = { 189 {sizeof(uint32_t), SOL_IPV6, IPV6_TCLASS, {0x12} }, 190 {sizeof(uint32_t), SOL_IPV6, IPV6_HOPLIMIT, {0x21} }, 191 }; 192 193 #define CMCOUNT ARRAY_SIZE(cmtab) 194 195 static ssize_t sendall(int st) 196 { 197 struct sockaddr_in6 sin6; 198 struct msghdr msg; 199 struct iovec iov; 200 struct soprot *psop; 201 unsigned char *pd; 202 unsigned int i; 203 int ctotal; 204 205 psop = (struct soprot *)tpbuf; 206 psop->sop_pid = htonl(getpid()); 207 psop->sop_seq = ++seq; 208 psop->sop_dlen = 0; 209 210 memset(&sin6, 0, sizeof(sin6)); 211 sin6.sin6_family = AF_INET6; 212 sin6.sin6_addr = in6addr_loopback; 213 214 memset(&msg, 0, sizeof(msg)); 215 msg.msg_name = &sin6; 216 msg.msg_namelen = sizeof(sin6); 217 iov.iov_base = tpbuf; 218 iov.iov_len = sizeof(struct soprot) + ntohl(psop->sop_dlen); 219 msg.msg_iov = &iov; 220 msg.msg_iovlen = 1; 221 222 pd = control; 223 ctotal = 0; 224 for (i = 0; i < CMCOUNT; ++i) { 225 struct cmsghdr *pcmsg = (struct cmsghdr *)pd; 226 227 pcmsg->cmsg_len = CMSG_LEN(cmtab[i].cm_len); 228 pcmsg->cmsg_level = cmtab[i].cm_level; 229 pcmsg->cmsg_type = cmtab[i].cm_type; 230 memcpy(CMSG_DATA(pcmsg), &cmtab[i].cmu, cmtab[i].cm_len); 231 pd += CMSG_SPACE(cmtab[i].cm_len); 232 ctotal += CMSG_SPACE(cmtab[i].cm_len); 233 } 234 msg.msg_control = ctotal ? control : 0; 235 msg.msg_controllen = ctotal; 236 237 return sendmsg(st, &msg, 0); 238 } 239 240 static void so_test(struct soent *psoe) 241 { 242 struct sockaddr_in6 sin6; 243 union soval sobuf; 244 socklen_t valsize; 245 static int sr = -1; 246 int st; 247 248 if (psoe->so_opt == -1) { 249 tst_brkm(TBROK | TERRNO, NULL, "%s not present at compile time", 250 psoe->so_tname); 251 } 252 if (psoe->so_clear || sr < 0) { 253 if (sr < 0) 254 close(sr); 255 sr = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, NH_TEST); 256 } 257 memset(&sin6, 0, sizeof(sin6)); 258 sin6.sin6_family = AF_INET6; 259 sin6.sin6_addr = in6addr_loopback; 260 261 SAFE_BIND(NULL, sr, (struct sockaddr *)&sin6, sizeof(sin6)); 262 263 if (setsockopt(sr, SOL_IPV6, psoe->so_opt, &psoe->so_clrval, 264 psoe->so_valsize) < 0) { 265 tst_brkm(TBROK | TERRNO, NULL, "%s: setsockopt", 266 psoe->so_tname); 267 } 268 269 TEST(setsockopt(sr, SOL_IPV6, psoe->so_opt, &psoe->so_setval, 270 psoe->so_valsize)); 271 if (TEST_RETURN != 0) { 272 tst_resm(TFAIL | TERRNO, "%s set-get: setsockopt", 273 psoe->so_tname); 274 return; 275 } 276 277 valsize = psoe->so_valsize; 278 TEST(getsockopt(sr, SOL_IPV6, psoe->so_opt, &sobuf, &valsize)); 279 if (TEST_RETURN != 0) { 280 tst_brkm(TBROK | TERRNO, NULL, "%s set-get: getsockopt", 281 psoe->so_tname); 282 } else if (memcmp(&psoe->so_setval, &sobuf, psoe->so_valsize)) { 283 tst_resm(TFAIL, "%s set-get optval != setval", psoe->so_tname); 284 } else { 285 tst_resm(TPASS, "%s set-get", psoe->so_tname); 286 } 287 288 st = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, NH_TEST); 289 290 if (sendall(st) < 0) 291 tst_brkm(TBROK | TERRNO, NULL, "%s transmit sendto", 292 psoe->so_tname); 293 294 close(st); 295 296 /* receiver processing */ 297 { 298 fd_set rfds, rfds_saved; 299 int nfds, cc; 300 int gotone; 301 struct timeval tv; 302 struct msghdr msg; 303 unsigned char cmsg[2048]; 304 struct cmsghdr *pcmsg; 305 struct iovec iov; 306 307 FD_ZERO(&rfds_saved); 308 FD_SET(sr, &rfds_saved); 309 310 tv.tv_sec = 0; 311 tv.tv_usec = 250000; 312 313 while (1) { 314 memcpy(&rfds, &rfds_saved, sizeof(rfds)); 315 nfds = select(sr + 1, &rfds, 0, 0, &tv); 316 if (nfds < 0) { 317 if (errno == EINTR) 318 continue; 319 tst_brkm(TBROK | TERRNO, NULL, "%s select", 320 psoe->so_tname); 321 } 322 if (nfds == 0) { 323 tst_brkm(TBROK, NULL, "%s recvmsg timed out", 324 psoe->so_tname); 325 return; 326 } 327 /* else, nfds == 1 */ 328 if (!FD_ISSET(sr, &rfds)) 329 continue; 330 331 memset(&msg, 0, sizeof(msg)); 332 iov.iov_base = rpbuf; 333 iov.iov_len = sizeof(rpbuf); 334 msg.msg_iov = &iov; 335 msg.msg_iovlen = 1; 336 msg.msg_control = cmsg; 337 msg.msg_controllen = sizeof(cmsg); 338 339 cc = recvmsg(sr, &msg, 0); 340 if (cc < 0) { 341 tst_brkm(TBROK | TERRNO, NULL, "%s recvmsg", 342 psoe->so_tname); 343 } 344 /* check pid & seq here */ 345 break; 346 } 347 gotone = 0; 348 for (pcmsg = CMSG_FIRSTHDR(&msg); pcmsg != NULL; 349 pcmsg = CMSG_NXTHDR(&msg, pcmsg)) { 350 if (!psoe->so_dorecv) 351 break; 352 gotone = pcmsg->cmsg_level == SOL_IPV6 && 353 pcmsg->cmsg_type == psoe->so_cmtype; 354 if (gotone) { 355 break; 356 } else if (psoe->so_clear) { 357 tst_resm(TFAIL, "%s receive: extraneous data " 358 "in control: level %d type %d len %zu", 359 psoe->so_tname, pcmsg->cmsg_level, 360 pcmsg->cmsg_type, pcmsg->cmsg_len); 361 return; 362 } 363 } 364 /* check contents here */ 365 if (psoe->so_dorecv) 366 tst_resm(gotone ? TPASS : TFAIL, "%s receive", 367 psoe->so_tname); 368 } 369 } 370 371 static void do_tests(void) 372 { 373 unsigned int i; 374 375 for (i = 0; i < SOCOUNT; ++i) { 376 sotab[i].so_clrval.sou_bool = 0; 377 sotab[i].so_setval.sou_bool = 1; 378 so_test(&sotab[i]); 379 } 380 } 381 382 static void setup(void) 383 { 384 TEST_PAUSE; 385 } 386