mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 1 | /* |
| 2 | * |
| 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 2 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 |
| 13 | * the 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, write to the Free Software |
Wanlong Gao | 4548c6c | 2012-10-19 18:03:36 +0800 | [diff] [blame] | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 18 | */ |
| 19 | |
| 20 | /* |
| 21 | * Test Name: asapi_04 |
| 22 | * |
| 23 | * Test Description: |
| 24 | * Verify that in6 and sockaddr fields are present. Most of these are |
| 25 | * "PASS" if they just compile. |
| 26 | * |
| 27 | * Usage: <for command-line> |
| 28 | * asapi_04 |
| 29 | * |
| 30 | * HISTORY |
| 31 | * 04/2005 written by David L Stevens |
| 32 | * |
| 33 | * RESTRICTIONS: |
| 34 | * None. |
| 35 | * |
| 36 | */ |
| 37 | |
| 38 | #include <stdio.h> |
| 39 | #include <unistd.h> |
| 40 | #include <errno.h> |
| 41 | #include <netdb.h> |
| 42 | #include <libgen.h> |
| 43 | #include <pthread.h> |
| 44 | #include <semaphore.h> |
| 45 | |
| 46 | #include <sys/time.h> |
subrata_modak | 7fe6451 | 2008-12-12 13:41:11 +0000 | [diff] [blame] | 47 | #include <sys/socket.h> |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 48 | #include <netinet/in.h> |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 49 | |
| 50 | #include "test.h" |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 51 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 52 | char *TCID = "asapi_04"; /* Test program identifier. */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 53 | |
| 54 | pid_t pid; |
| 55 | |
| 56 | struct { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 57 | char *prt_name; |
| 58 | int prt_value; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 59 | } ptab[] = { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 60 | { |
| 61 | "hopopt", 0}, { |
| 62 | "ipv6", 41}, { |
| 63 | "ipv6-route", 43}, { |
| 64 | "ipv6-frag", 44}, { |
| 65 | "esp", 50}, { |
| 66 | "ah", 51}, { |
| 67 | "ipv6-icmp", 58}, { |
| 68 | "ipv6-nonxt", 59}, { |
| 69 | "ipv6-opts", 60},}; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 70 | |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 71 | #define PTCOUNT (sizeof(ptab)/sizeof(ptab[0])) |
| 72 | |
| 73 | #define READ_TIMEOUT 5 /* secs */ |
| 74 | |
| 75 | void do_tests(void); |
| 76 | void setup(void), cleanup(void); |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 77 | int csum_test(char *rhost); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 78 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 79 | int main(int argc, char *argv[]) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 80 | { |
Cyril Hrubis | 0b9589f | 2014-05-27 17:40:33 +0200 | [diff] [blame] | 81 | const char *msg; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 82 | int lc; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 83 | |
| 84 | /* Parse standard options given to run the test. */ |
| 85 | msg = parse_opts(argc, argv, 0, 0); |
Garrett Cooper | df3eb16 | 2010-11-28 22:44:32 -0800 | [diff] [blame] | 86 | if (msg != NULL) { |
Garrett Cooper | 5374050 | 2010-12-16 00:04:01 -0800 | [diff] [blame] | 87 | tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | pid = getpid(); |
| 91 | |
| 92 | setup(); |
| 93 | |
| 94 | for (lc = 0; TEST_LOOPING(lc); ++lc) |
| 95 | do_tests(); |
| 96 | |
| 97 | cleanup(); |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 98 | |
| 99 | tst_exit(); |
| 100 | } |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 101 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 102 | void do_tests(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 103 | { |
| 104 | int i; |
| 105 | |
| 106 | /* RFC 3542, Section 2.3 */ |
| 107 | #ifndef IN6_ARE_ADDR_EQUAL |
| 108 | tst_resm(TBROK, "IN6_ARE_ADDR_EQUAL not present"); |
| 109 | #else /* IN6_ARE_ADDR_EQUAL */ |
| 110 | /* |
| 111 | * set each bit in an address and check for unequal; then set |
| 112 | * in the second address and check for equal. Covers all bits, all |
| 113 | * combinations. |
| 114 | */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 115 | { |
| 116 | struct in6_addr a1, a2; |
| 117 | int word, bit; |
| 118 | int rv = 1; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 119 | |
| 120 | memset(&a1, 0, sizeof(a1)); |
| 121 | memset(&a2, 0, sizeof(a2)); |
| 122 | |
| 123 | rv = IN6_ARE_ADDR_EQUAL(&a1, &a2); |
| 124 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 125 | for (word = 0; word < 4; ++word) |
| 126 | for (bit = 0; bit < 32; ++bit) { |
| 127 | uint32_t newbit = 1 << bit; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 128 | |
| 129 | a1.s6_addr32[word] |= newbit; /* unequal */ |
| 130 | rv &= !IN6_ARE_ADDR_EQUAL(&a1, &a2); |
| 131 | a2.s6_addr32[word] |= newbit; /* equal */ |
| 132 | rv &= IN6_ARE_ADDR_EQUAL(&a1, &a2); |
| 133 | } |
| 134 | tst_resm(rv ? TPASS : TFAIL, "IN6_ARE_ADDR_EQUAL"); |
| 135 | } |
| 136 | #endif /* IN6_ARE_ADDR_EQUAL */ |
| 137 | |
| 138 | /* RFC 3542, Section 2.4 */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 139 | for (i = 0; i < PTCOUNT; ++i) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 140 | struct protoent *pe; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 141 | int pass; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 142 | |
| 143 | pe = getprotobyname(ptab[i].prt_name); |
| 144 | pass = pe && pe->p_proto == ptab[i].prt_value; |
| 145 | tst_resm(pass ? TPASS : TFAIL, "\"%s\" protocols entry", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 146 | ptab[i].prt_name); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 147 | } |
| 148 | /* RFC 3542, Section 3.1 */ |
| 149 | csum_test("::1"); |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | * this next-header value shouldn't be a real protocol!! |
| 154 | * 0x9f = 01 0 11111 |
| 155 | * | | | |
| 156 | * | | |--- rest- ~0 |
| 157 | * | |--------- chg - "no change enroute" |
| 158 | * |----------- act - "discard unknown" |
| 159 | */ |
| 160 | #define NH_TEST 0x9f |
| 161 | |
| 162 | struct tprot { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 163 | int tp_pid; /* sender PID */ |
| 164 | int tp_seq; /* sequence # */ |
| 165 | int tp_offset; /* offset of cksum */ |
| 166 | int tp_dlen; /* tp_dat length */ |
| 167 | unsigned char tp_dat[0]; /* user data */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 168 | }; |
| 169 | |
| 170 | unsigned char tpbuf[sizeof(struct tprot) + 2048]; |
| 171 | unsigned char rpbuf[sizeof(struct tprot) + 2048]; |
| 172 | |
| 173 | struct csent { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 174 | int cs_offset; |
| 175 | int cs_dlen; |
| 176 | int cs_setresult; /* setsockopt expected result */ |
| 177 | int cs_seterrno; /* setsockopt expected errno */ |
| 178 | int cs_sndresult; /* send expected result */ |
| 179 | int cs_snderrno; /* send expected errno */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 180 | } cstab[] = { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 181 | { |
| 182 | 0, 5, 0, 0, 0, 0}, { |
| 183 | 6, 30, 0, 0, 0, 0}, { |
| 184 | 3, 20, -1, EINVAL, -1, -1}, /* non-aligned offset */ |
| 185 | { |
| 186 | 4, 5, 0, 0, -1, EINVAL}, /* not enough space */ |
| 187 | { |
| 188 | 50, 5, 0, 0, -1, EINVAL}, /* outside of packet */ |
| 189 | { |
| 190 | 22, 30, 0, 0, 0, 0}, { |
| 191 | 2000, 2004, 0, 0, 0, 0}, /* in a fragment (over Ethernet) */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 192 | }; |
| 193 | |
| 194 | #define CSCOUNT (sizeof(cstab)/sizeof(cstab[0])) |
| 195 | |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 196 | static int recvtprot(int sd, unsigned char *packet, int psize) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 197 | { |
| 198 | struct tprot *tpt; |
| 199 | int cc, total, expected; |
| 200 | int gothead; |
| 201 | |
| 202 | tpt = (struct tprot *)packet; |
| 203 | total = cc = recv(sd, packet, sizeof(struct tprot), 0); |
| 204 | expected = sizeof(struct tprot); /* until we get tp_dlen */ |
| 205 | gothead = total >= sizeof(struct tprot); |
| 206 | if (gothead) |
| 207 | expected += ntohl(tpt->tp_dlen); |
| 208 | if (cc <= 0) |
| 209 | return cc; |
| 210 | while (cc > 0 && total < expected) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 211 | cc = recv(sd, &packet[total], expected - total, 0); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 212 | if (cc >= 0) { |
| 213 | total += cc; |
| 214 | if (!gothead && total >= sizeof(struct tprot)) { |
| 215 | gothead = 1; |
| 216 | expected += ntohl(tpt->tp_dlen); |
| 217 | } |
| 218 | } else |
| 219 | break; |
| 220 | } |
| 221 | if (cc < 0) |
| 222 | return cc; |
| 223 | return total; |
| 224 | } |
| 225 | |
| 226 | unsigned short csum(unsigned short partial, unsigned char *packet, int len) |
| 227 | { |
| 228 | unsigned long sum = partial; |
| 229 | unsigned short *ps; |
| 230 | int i; |
| 231 | |
| 232 | ps = (unsigned short *)packet; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 233 | for (i = 0; i < len / 2; ++i) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 234 | sum += *ps++; |
| 235 | if (len & 1) |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 236 | sum += htons(packet[len - 1] << 8); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 237 | sum = (sum >> 16) + (sum & 0xffff); |
| 238 | sum += (sum >> 16); |
| 239 | return ~sum; |
| 240 | } |
| 241 | |
| 242 | struct ph { |
| 243 | struct in6_addr ph_sa; |
| 244 | struct in6_addr ph_da; |
| 245 | uint32_t ph_len; |
| 246 | uint8_t ph_mbz[3]; |
| 247 | uint8_t ph_nh; |
| 248 | } ph; |
| 249 | |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 250 | static int client(int prot, int sfd) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 251 | { |
| 252 | struct tprot *pttp = (struct tprot *)tpbuf; |
| 253 | struct tprot *prtp = (struct tprot *)rpbuf; |
| 254 | struct sockaddr_in6 rsin6; |
| 255 | static int seq; |
| 256 | int i, sd, cc, cs; |
| 257 | |
| 258 | memset(&rsin6, 0, sizeof(rsin6)); |
| 259 | rsin6.sin6_family = AF_INET6; |
| 260 | rsin6.sin6_addr = in6addr_loopback; |
| 261 | |
| 262 | memset(&ph, 0, sizeof(ph)); |
| 263 | ph.ph_sa = rsin6.sin6_addr; |
| 264 | ph.ph_da = rsin6.sin6_addr; |
| 265 | ph.ph_nh = NH_TEST; |
| 266 | |
| 267 | sd = socket(PF_INET6, SOCK_RAW, NH_TEST); |
| 268 | if (sd < 0) { |
| 269 | tst_resm(TBROK, "can't create raw socket: %s", strerror(errno)); |
| 270 | return -1; |
| 271 | } |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 272 | for (i = 0; i < CSCOUNT; ++i) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 273 | int offset, len, xlen; |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 274 | int rv; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 275 | unsigned char *p, *pend; |
| 276 | |
| 277 | offset = sizeof(struct tprot) + cstab[i].cs_offset; |
| 278 | len = sizeof(struct tprot) + cstab[i].cs_dlen; |
| 279 | |
| 280 | memset(pttp, 0, sizeof(*pttp)); |
| 281 | memset(pttp->tp_dat, 0xA5, cstab[i].cs_dlen); |
| 282 | |
| 283 | pttp->tp_pid = htonl(pid); |
| 284 | pttp->tp_offset = ntohl(offset); |
| 285 | pttp->tp_dlen = ntohl(cstab[i].cs_dlen); |
| 286 | pttp->tp_seq = ntohl(++seq); |
| 287 | |
| 288 | TEST(setsockopt(sd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, |
| 289 | sizeof(offset))); |
| 290 | if (TEST_RETURN != cstab[i].cs_setresult) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 291 | tst_resm(TFAIL | TTERRNO, |
| 292 | "IPV6_CHECKSUM offset %d len %d " |
| 293 | "- result %ld != %d", offset, len, TEST_RETURN, |
| 294 | cstab[i].cs_setresult); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 295 | continue; |
| 296 | } |
| 297 | if (TEST_RETURN < 0) { |
| 298 | tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 299 | offset, len); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 300 | continue; |
| 301 | } |
| 302 | if (TEST_RETURN && TEST_ERRNO != cstab[i].cs_seterrno) { |
| 303 | tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 304 | "- errno %d != %d", offset, len, |
| 305 | TEST_ERRNO, cstab[i].cs_seterrno); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 306 | continue; |
| 307 | } |
| 308 | /* send packet */ |
| 309 | TEST(sendto(sd, pttp, len, 0, (struct sockaddr *)&rsin6, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 310 | sizeof(rsin6))); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 311 | xlen = (cstab[i].cs_sndresult < 0) ? -1 : len; |
| 312 | if (TEST_RETURN != xlen) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 313 | tst_resm(TFAIL | TTERRNO, |
| 314 | "IPV6_CHECKSUM offset %d len %d " |
| 315 | "- sndresult %ld != %d", offset, len, |
| 316 | TEST_RETURN, xlen); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 317 | continue; |
| 318 | } |
| 319 | if (TEST_RETURN < 0 && TEST_ERRNO != cstab[i].cs_snderrno) { |
| 320 | tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 321 | "- snderrno %d != %d", offset, len, |
| 322 | TEST_ERRNO, cstab[i].cs_snderrno); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 323 | continue; |
| 324 | } |
| 325 | if (TEST_RETURN < 0) { |
| 326 | tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 327 | offset, len); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 328 | continue; |
| 329 | } |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 330 | while ((cc = recvtprot(sfd, rpbuf, sizeof(rpbuf)))) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 331 | if (htonl(prtp->tp_pid) == pid && |
| 332 | htonl(prtp->tp_seq) == seq) |
| 333 | break; |
| 334 | } |
| 335 | rv = 1; |
| 336 | pend = rpbuf + sizeof(struct tprot) + ntohl(prtp->tp_dlen); |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 337 | for (p = &prtp->tp_dat[0]; p < pend; ++p) { |
| 338 | if (p == &rpbuf[offset] || p == &rpbuf[offset + 1]) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 339 | continue; |
| 340 | if (*p != 0xa5) { |
| 341 | tst_resm(TFAIL, "IPV6_CHECKSUM corrupt data " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 342 | "0x%02x != 0xa5 at offset %d in packet", |
| 343 | *p, p - rpbuf); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 344 | rv = 0; |
| 345 | break; |
| 346 | } |
| 347 | } |
| 348 | if (rv == 0) |
| 349 | continue; |
| 350 | ph.ph_len = htonl(xlen); |
| 351 | cs = csum(0, (unsigned char *)&ph, sizeof(ph)); |
| 352 | cs = csum(~cs, rpbuf, xlen); |
| 353 | if (!csum(0, rpbuf, xlen)) { |
| 354 | tst_resm(TFAIL, "IPV6_CHECKSUM offset %d len %d (bad " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 355 | "checksum)", offset, len); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 356 | continue; |
| 357 | } |
| 358 | tst_resm(TPASS, "IPV6_CHECKSUM offset %d len %d", offset, len); |
| 359 | } |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 360 | return 0; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 361 | } |
| 362 | |
| 363 | static int listen_fd, connect_fd; |
| 364 | sem_t ilsem; |
| 365 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 366 | void *ilistener(void *arg) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 367 | { |
| 368 | connect_fd = accept(listen_fd, 0, 0); |
| 369 | close(listen_fd); |
| 370 | sem_post(&ilsem); |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 371 | return NULL; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 372 | } |
| 373 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 374 | int isocketpair(int pf, int type, int proto, int fd[2]) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 375 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 376 | pthread_t thid; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 377 | struct sockaddr_in sin4; |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 378 | socklen_t namelen; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 379 | |
| 380 | /* restrict to PF_INET for now */ |
| 381 | if (pf != PF_INET) { |
| 382 | errno = EOPNOTSUPP; |
| 383 | return -1; |
| 384 | } |
| 385 | sem_init(&ilsem, 0, 0); |
| 386 | listen_fd = socket(pf, type, proto); |
| 387 | if (listen_fd < 0) { |
| 388 | perror("socket"); |
| 389 | return -1; |
| 390 | } |
| 391 | memset(&sin4, 0, sizeof(sin4)); |
| 392 | if (bind(listen_fd, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) { |
| 393 | perror("bind"); |
| 394 | return -1; |
| 395 | } |
| 396 | if (listen(listen_fd, 10) < 0) { |
| 397 | perror("listen"); |
| 398 | return -1; |
| 399 | } |
| 400 | namelen = sizeof(sin4); |
| 401 | if (getsockname(listen_fd, (struct sockaddr *)&sin4, &namelen) < 0) { |
| 402 | perror("getsockname"); |
| 403 | return -1; |
| 404 | } |
| 405 | if (pthread_create(&thid, 0, ilistener, 0) < 0) { |
| 406 | perror("pthread_create"); |
| 407 | return -1; |
| 408 | } |
| 409 | |
| 410 | fd[0] = socket(pf, type, proto); |
| 411 | if (fd[0] < 0) { |
| 412 | perror("socket"); |
| 413 | return -1; |
| 414 | } |
| 415 | sin4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 416 | if (connect(fd[0], (struct sockaddr *)&sin4, sizeof(sin4)) < 0) { |
| 417 | perror("connect"); |
| 418 | return -1; |
| 419 | } |
| 420 | sem_wait(&ilsem); |
| 421 | fd[1] = connect_fd; |
| 422 | sem_destroy(&ilsem); |
| 423 | return 0; |
| 424 | } |
| 425 | |
| 426 | #ifndef MAX |
| 427 | #define MAX(a, b) ((a) >= (b) ? (a) : (b)) |
| 428 | #endif /* MAX */ |
| 429 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 430 | int csum_test(char *rhost) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 431 | { |
| 432 | fd_set rset, rset_save; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 433 | int csd[2]; /* control sockets */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 434 | int sd, nfds, maxfd, cc; |
| 435 | struct timeval tv; |
| 436 | |
| 437 | /* rhost == loopback, for now */ |
| 438 | if (strcmp(rhost, "::1")) { |
| 439 | tst_resm(TBROK, "invalid rhost \"%s\"", rhost); |
| 440 | return -1; |
| 441 | } |
| 442 | if (isocketpair(PF_INET, SOCK_STREAM, 0, csd) < 0) { |
| 443 | tst_resm(TBROK, "socketpair: %s", strerror(errno)); |
| 444 | return -1; |
| 445 | } |
| 446 | sd = socket(PF_INET6, SOCK_RAW, NH_TEST); |
| 447 | if (sd < 0) { |
| 448 | int saved_errno = errno; |
| 449 | |
| 450 | if (errno == EPERM && geteuid()) |
| 451 | tst_resm(TBROK, "IPV6_CHECKSUM tests must run as root"); |
| 452 | else |
| 453 | tst_resm(TBROK, "All IPv6_CHECKSUM tests broken: " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 454 | "socket: %s", strerror(saved_errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 455 | return -1; |
| 456 | } |
| 457 | FD_ZERO(&rset_save); |
| 458 | FD_SET(sd, &rset_save); |
| 459 | FD_SET(csd[1], &rset_save); |
| 460 | memcpy(&rset, &rset_save, sizeof(rset)); |
| 461 | maxfd = MAX(sd, csd[1]); |
| 462 | |
| 463 | /* server socket set; now start the client */ |
| 464 | switch (fork()) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 465 | case 0: /* child */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 466 | close(csd[0]); |
| 467 | break; |
| 468 | case -1: |
| 469 | tst_resm(TBROK, "can't fork rserver"); |
| 470 | return -1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 471 | default: /* parent */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 472 | close(sd); |
| 473 | close(csd[1]); |
| 474 | return client(pid, csd[0]); |
| 475 | } |
| 476 | |
| 477 | tv.tv_sec = READ_TIMEOUT; |
| 478 | tv.tv_usec = 0; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 479 | while ((nfds = select(maxfd + 1, &rset, 0, 0, &tv)) >= 0) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 480 | if (nfds < 0) { |
| 481 | if (errno == EINTR) |
| 482 | continue; |
| 483 | exit(0); |
| 484 | } else if (nfds == 0) { |
| 485 | fprintf(stderr, "server read timed out"); |
| 486 | return -1; |
| 487 | } |
| 488 | if (FD_ISSET(sd, &rset)) { |
| 489 | static char packet[2048]; |
| 490 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 491 | cc = recv(sd, packet, sizeof(packet), 0); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 492 | if (cc < 0) { |
| 493 | perror("server recvtprot"); |
| 494 | exit(1); |
| 495 | } |
| 496 | if (cc == 0) |
| 497 | exit(0); |
| 498 | if (write(csd[1], packet, cc) < 0) { |
| 499 | perror("server write UNIX socket"); |
| 500 | exit(0); |
| 501 | } |
| 502 | } |
| 503 | if (FD_ISSET(csd[1], &rset)) { |
| 504 | char buf[2048]; |
| 505 | |
| 506 | cc = read(csd[1], buf, sizeof(buf)); |
| 507 | if (cc == 0) { |
| 508 | exit(0); |
| 509 | } |
| 510 | if (cc < 0) { |
| 511 | perror("server read"); |
| 512 | exit(1); |
| 513 | } |
| 514 | /* handle commands here, if any added later */ |
| 515 | } |
| 516 | memcpy(&rset, &rset_save, sizeof(rset)); |
| 517 | tv.tv_sec = READ_TIMEOUT; |
| 518 | tv.tv_usec = 0; |
| 519 | } |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 520 | return 0; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 521 | } |
| 522 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 523 | void setup(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 524 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 525 | TEST_PAUSE; /* if -P option specified */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 526 | } |
| 527 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 528 | void cleanup(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 529 | { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 530 | } |
| 531 | |
Chris Dearman | ec6edca | 2012-10-17 19:54:01 -0700 | [diff] [blame] | 532 | int TST_TOTAL = PTCOUNT + CSCOUNT; |