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 <stdio.h> 22#include <unistd.h> 23#include <errno.h> 24#include <netdb.h> 25#include <libgen.h> 26#include <pthread.h> 27#include <semaphore.h> 28 29#include <sys/time.h> 30#include <sys/socket.h> 31#include <netinet/in.h> 32 33#include "test.h" 34#include "safe_macros.h" 35 36char *TCID = "asapi_04"; 37 38static pid_t pid; 39 40static struct { 41 char *prt_name; 42 int prt_value; 43} ptab[] = { 44 {"hopopt", 0}, 45 {"ipv6", 41}, 46 {"ipv6-route", 43}, 47 {"ipv6-frag", 44}, 48 {"esp", 50}, 49 {"ah", 51}, 50 {"ipv6-icmp", 58}, 51 {"ipv6-nonxt", 59}, 52 {"ipv6-opts", 60}, 53}; 54 55#define PTCOUNT ARRAY_SIZE(ptab) 56#define READ_TIMEOUT 5 57 58static void do_tests(void); 59static void setup(void); 60static void csum_test(void); 61 62int main(int argc, char *argv[]) 63{ 64 int lc; 65 66 tst_parse_opts(argc, argv, 0, 0); 67 68 setup(); 69 70 for (lc = 0; TEST_LOOPING(lc); ++lc) 71 do_tests(); 72 73 tst_exit(); 74} 75 76static void do_tests(void) 77{ 78 unsigned int i; 79 80/* RFC 3542, Section 2.3 */ 81#ifndef IN6_ARE_ADDR_EQUAL 82 tst_resm(TCONF, "IN6_ARE_ADDR_EQUAL not present"); 83#else /* IN6_ARE_ADDR_EQUAL */ 84 /* 85 * set each bit in an address and check for unequal; then set 86 * in the second address and check for equal. Covers all bits, all 87 * combinations. 88 */ 89 struct in6_addr a1, a2; 90 int word, bit; 91 int rv = 1; 92 93 memset(&a1, 0, sizeof(a1)); 94 memset(&a2, 0, sizeof(a2)); 95 96 rv = IN6_ARE_ADDR_EQUAL(&a1, &a2); 97 98 for (word = 0; word < 4; ++word) { 99 for (bit = 0; bit < 32; ++bit) { 100 uint32_t newbit = 1U << bit; 101 102 a1.s6_addr32[word] |= newbit; 103 rv &= !IN6_ARE_ADDR_EQUAL(&a1, &a2); 104 a2.s6_addr32[word] |= newbit; 105 rv &= IN6_ARE_ADDR_EQUAL(&a1, &a2); 106 } 107 } 108 109 tst_resm(rv ? TPASS : TFAIL, "IN6_ARE_ADDR_EQUAL"); 110#endif /* IN6_ARE_ADDR_EQUAL */ 111 112/* RFC 3542, Section 2.4 */ 113 for (i = 0; i < PTCOUNT; ++i) { 114 struct protoent *pe; 115 int pass; 116 117 pe = getprotobyname(ptab[i].prt_name); 118 pass = pe && pe->p_proto == ptab[i].prt_value; 119 tst_resm(pass ? TPASS : TFAIL, "\"%s\" protocols entry", 120 ptab[i].prt_name); 121 } 122/* RFC 3542, Section 3.1 */ 123 csum_test(); 124} 125 126/* 127 * this next-header value shouldn't be a real protocol!! 128 * 0x9f = 01 0 11111 129 * | | | 130 * | | |--- rest- ~0 131 * | |--------- chg - "no change enroute" 132 * |----------- act - "discard unknown" 133 */ 134#define NH_TEST 0x9f 135 136struct tprot { 137 int tp_pid; /* sender PID */ 138 int tp_seq; /* sequence # */ 139 int tp_offset; /* offset of cksum */ 140 int tp_dlen; /* tp_dat length */ 141 unsigned char tp_dat[0]; /* user data */ 142}; 143 144static unsigned char tpbuf[sizeof(struct tprot) + 2048]; 145static unsigned char rpbuf[sizeof(struct tprot) + 2048]; 146 147static struct csent { 148 int cs_offset; 149 int cs_dlen; 150 int cs_setresult; /* setsockopt expected result */ 151 int cs_seterrno; /* setsockopt expected errno */ 152 int cs_sndresult; /* send expected result */ 153 int cs_snderrno; /* send expected errno */ 154} cstab[] = { 155 {0, 5, 0, 0, 0, 0}, 156 {6, 30, 0, 0, 0, 0}, 157 {3, 20, -1, EINVAL, -1, -1}, /* non-aligned offset */ 158 {4, 5, 0, 0, -1, EINVAL}, /* not enough space */ 159 {50, 5, 0, 0, -1, EINVAL}, /* outside of packet */ 160 {22, 30, 0, 0, 0, 0}, 161 {2000, 2004, 0, 0, 0, 0}, /* in a fragment (over Ethernet) */ 162}; 163 164#define CSCOUNT ARRAY_SIZE(cstab) 165 166int TST_TOTAL = PTCOUNT + CSCOUNT; 167 168static int recvtprot(int sd, unsigned char *packet) 169{ 170 struct tprot *tpt; 171 int cc; 172 unsigned int total, expected; 173 int gothead; 174 175 tpt = (struct tprot *)packet; 176 total = cc = recv(sd, packet, sizeof(struct tprot), 0); 177 expected = sizeof(struct tprot); /* until we get tp_dlen */ 178 gothead = total >= sizeof(struct tprot); 179 if (gothead) 180 expected += ntohl(tpt->tp_dlen); 181 if (cc <= 0) 182 return cc; 183 while (cc > 0 && total < expected) { 184 cc = recv(sd, &packet[total], expected - total, 0); 185 if (cc >= 0) { 186 total += cc; 187 if (!gothead && total >= sizeof(struct tprot)) { 188 gothead = 1; 189 expected += ntohl(tpt->tp_dlen); 190 } 191 } else { 192 break; 193 } 194 } 195 if (cc < 0) 196 return cc; 197 return total; 198} 199 200static unsigned short csum(unsigned short partial, unsigned char *packet, 201 int len) 202{ 203 unsigned long sum = partial; 204 unsigned short *ps; 205 int i; 206 207 ps = (unsigned short *)packet; 208 for (i = 0; i < len / 2; ++i) 209 sum += *ps++; 210 if (len & 1) 211 sum += htons(packet[len - 1] << 8); 212 sum = (sum >> 16) + (sum & 0xffff); 213 sum += (sum >> 16); 214 return ~sum; 215} 216 217static struct ph { 218 struct in6_addr ph_sa; 219 struct in6_addr ph_da; 220 uint32_t ph_len; 221 uint8_t ph_mbz[3]; 222 uint8_t ph_nh; 223} ph; 224 225static int client(int sfd) 226{ 227 struct tprot *pttp = (struct tprot *)tpbuf; 228 struct tprot *prtp = (struct tprot *)rpbuf; 229 struct sockaddr_in6 rsin6; 230 static int seq; 231 unsigned int i; 232 int sd, cc, cs; 233 234 memset(&rsin6, 0, sizeof(rsin6)); 235 rsin6.sin6_family = AF_INET6; 236 rsin6.sin6_addr = in6addr_loopback; 237 238 memset(&ph, 0, sizeof(ph)); 239 ph.ph_sa = rsin6.sin6_addr; 240 ph.ph_da = rsin6.sin6_addr; 241 ph.ph_nh = NH_TEST; 242 243 sd = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, NH_TEST); 244 245 for (i = 0; i < CSCOUNT; ++i) { 246 int offset, len, xlen; 247 int rv; 248 unsigned char *p, *pend; 249 250 offset = sizeof(struct tprot) + cstab[i].cs_offset; 251 len = sizeof(struct tprot) + cstab[i].cs_dlen; 252 253 memset(pttp, 0, sizeof(*pttp)); 254 memset(pttp->tp_dat, 0xA5, cstab[i].cs_dlen); 255 256 pttp->tp_pid = htonl(pid); 257 pttp->tp_offset = ntohl(offset); 258 pttp->tp_dlen = ntohl(cstab[i].cs_dlen); 259 pttp->tp_seq = ntohl(++seq); 260 261 TEST(setsockopt(sd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, 262 sizeof(offset))); 263 if (TEST_RETURN != cstab[i].cs_setresult) { 264 tst_resm(TFAIL | TTERRNO, 265 "IPV6_CHECKSUM offset %d len %d " 266 "- result %ld != %d", offset, len, TEST_RETURN, 267 cstab[i].cs_setresult); 268 continue; 269 } 270 if (TEST_RETURN < 0) { 271 tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", 272 offset, len); 273 continue; 274 } 275 if (TEST_RETURN && TEST_ERRNO != cstab[i].cs_seterrno) { 276 tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d " 277 "- errno %d != %d", offset, len, 278 TEST_ERRNO, cstab[i].cs_seterrno); 279 continue; 280 } 281 /* send packet */ 282 TEST(sendto(sd, pttp, len, 0, (struct sockaddr *)&rsin6, 283 sizeof(rsin6))); 284 xlen = (cstab[i].cs_sndresult < 0) ? -1 : len; 285 if (TEST_RETURN != xlen) { 286 tst_resm(TFAIL | TTERRNO, 287 "IPV6_CHECKSUM offset %d len %d " 288 "- sndresult %ld != %d", offset, len, 289 TEST_RETURN, xlen); 290 continue; 291 } 292 if (TEST_RETURN < 0 && TEST_ERRNO != cstab[i].cs_snderrno) { 293 tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d " 294 "- snderrno %d != %d", offset, len, 295 TEST_ERRNO, cstab[i].cs_snderrno); 296 continue; 297 } 298 if (TEST_RETURN < 0) { 299 tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", 300 offset, len); 301 continue; 302 } 303 while ((cc = recvtprot(sfd, rpbuf))) { 304 if (htonl(prtp->tp_pid) == (uint32_t)pid && 305 htonl(prtp->tp_seq) == (uint32_t)seq) 306 break; 307 } 308 rv = 1; 309 pend = rpbuf + sizeof(struct tprot) + ntohl(prtp->tp_dlen); 310 for (p = &prtp->tp_dat[0]; p < pend; ++p) { 311 if (p == &rpbuf[offset] || p == &rpbuf[offset + 1]) 312 continue; 313 if (*p != 0xa5) { 314 tst_resm(TFAIL, "IPV6_CHECKSUM corrupt data " 315 "0x%02x != 0xa5, offset %zd in packet", 316 *p, p - rpbuf); 317 rv = 0; 318 break; 319 } 320 } 321 if (rv == 0) 322 continue; 323 ph.ph_len = htonl(xlen); 324 cs = csum(0, (unsigned char *)&ph, sizeof(ph)); 325 cs = csum(~cs, rpbuf, xlen); 326 if (!csum(0, rpbuf, xlen)) { 327 tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d (bad " 328 "checksum)", offset, len); 329 continue; 330 } 331 tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", offset, len); 332 } 333 return 0; 334} 335 336static int listen_fd, connect_fd; 337 338static void *ilistener(void *arg LTP_ATTRIBUTE_UNUSED) 339{ 340 connect_fd = accept(listen_fd, 0, 0); 341 close(listen_fd); 342 return NULL; 343} 344 345static void isocketpair(int pf, int type, int proto, int fd[2]) 346{ 347 pthread_t thid; 348 struct sockaddr_in sin4; 349 socklen_t namelen; 350 351 listen_fd = SAFE_SOCKET(NULL, pf, type, proto); 352 353 memset(&sin4, 0, sizeof(sin4)); 354 355 SAFE_BIND(NULL, listen_fd, (struct sockaddr *)&sin4, sizeof(sin4)); 356 357 SAFE_LISTEN(NULL, listen_fd, 10); 358 359 namelen = sizeof(sin4); 360 SAFE_GETSOCKNAME(NULL, listen_fd, (struct sockaddr *)&sin4, &namelen); 361 362 if (pthread_create(&thid, 0, ilistener, 0) < 0) 363 tst_brkm(TBROK | TERRNO, NULL, "pthread_create error"); 364 365 fd[0] = SAFE_SOCKET(NULL, pf, type, proto); 366 367 sin4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 368 369 SAFE_CONNECT(NULL, fd[0], (struct sockaddr *)&sin4, sizeof(sin4)); 370 371 pthread_join(thid, NULL); 372 373 fd[1] = connect_fd; 374} 375 376#ifndef MAX 377#define MAX(a, b) ((a) >= (b) ? (a) : (b)) 378#endif /* MAX */ 379 380static void csum_test(void) 381{ 382 fd_set rset, rset_save; 383 int csd[2]; /* control sockets */ 384 int sd, nfds, maxfd, cc; 385 struct timeval tv; 386 387 isocketpair(PF_INET, SOCK_STREAM, 0, csd); 388 389 sd = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, NH_TEST); 390 391 FD_ZERO(&rset_save); 392 FD_SET(sd, &rset_save); 393 FD_SET(csd[1], &rset_save); 394 memcpy(&rset, &rset_save, sizeof(rset)); 395 maxfd = MAX(sd, csd[1]); 396 397 /* server socket set; now start the client */ 398 switch (fork()) { 399 case 0: 400 close(csd[0]); 401 break; 402 case -1: 403 tst_brkm(TBROK, NULL, "can't fork rserver"); 404 default: 405 close(sd); 406 close(csd[1]); 407 client(csd[0]); 408 return; 409 } 410 411 tv.tv_sec = READ_TIMEOUT; 412 tv.tv_usec = 0; 413 while ((nfds = select(maxfd + 1, &rset, 0, 0, &tv)) >= 0) { 414 if (nfds < 0) { 415 if (errno == EINTR) 416 continue; 417 exit(0); 418 } else if (nfds == 0) { 419 fprintf(stderr, "server read timed out"); 420 return; 421 } 422 if (FD_ISSET(sd, &rset)) { 423 static char packet[2048]; 424 425 cc = recv(sd, packet, sizeof(packet), 0); 426 if (cc < 0) { 427 perror("server recvtprot"); 428 exit(1); 429 } 430 if (cc == 0) 431 exit(0); 432 if (write(csd[1], packet, cc) < 0) { 433 perror("server write UNIX socket"); 434 exit(0); 435 } 436 } 437 if (FD_ISSET(csd[1], &rset)) { 438 char buf[2048]; 439 440 cc = read(csd[1], buf, sizeof(buf)); 441 if (cc == 0) 442 exit(0); 443 if (cc < 0) { 444 perror("server read"); 445 exit(1); 446 } 447 /* handle commands here, if any added later */ 448 } 449 memcpy(&rset, &rset_save, sizeof(rset)); 450 tv.tv_sec = READ_TIMEOUT; 451 tv.tv_usec = 0; 452 } 453} 454 455static void setup(void) 456{ 457 TEST_PAUSE; 458 459 pid = getpid(); 460} 461