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_06 |
| 22 | * |
| 23 | * Test Description: |
| 24 | * Tests for RFC 3542 section 4 socket options and ancillary data |
| 25 | * |
| 26 | * Usage: <for command-line> |
| 27 | * asapi_06 |
| 28 | * |
| 29 | * HISTORY |
| 30 | * 05/2005 written by David L Stevens |
| 31 | * |
| 32 | * RESTRICTIONS: |
| 33 | * None. |
| 34 | * |
| 35 | */ |
| 36 | |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 37 | #include "config.h" |
| 38 | |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 39 | #include <stdio.h> |
| 40 | #include <unistd.h> |
| 41 | #include <errno.h> |
| 42 | #include <netdb.h> |
| 43 | #include <libgen.h> |
| 44 | #include <pthread.h> |
| 45 | #include <semaphore.h> |
| 46 | |
| 47 | #include <sys/time.h> |
| 48 | #include <netinet/in.h> |
| 49 | #include <netinet/ip6.h> |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 50 | #include <sys/types.h> |
| 51 | #include <sys/socket.h> |
| 52 | #include <net/if.h> |
| 53 | #include <sys/ioctl.h> |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 54 | #ifdef HAVE_IFADDRS_H |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 55 | #include <ifaddrs.h> |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 56 | #endif |
subrata_modak | aa588ae | 2008-09-18 13:18:36 +0000 | [diff] [blame] | 57 | #include <arpa/inet.h> |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 58 | |
| 59 | #include "test.h" |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 60 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 61 | char *TCID = "asapi_06"; /* Test program identifier. */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 62 | |
| 63 | int TST_TOTAL = 1; |
| 64 | |
| 65 | pid_t pid; |
| 66 | |
| 67 | struct { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 68 | char *prt_name; |
| 69 | int prt_value; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 70 | } ptab[] = { |
| 71 | }; |
| 72 | |
| 73 | #define PTCOUNT (sizeof(ptab)/sizeof(ptab[0])) |
| 74 | |
| 75 | #define READ_TIMEOUT 5 /* secs */ |
| 76 | |
| 77 | void do_tests(void); |
| 78 | void setup(void), cleanup(void); |
| 79 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 80 | int main(int argc, char *argv[]) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 81 | { |
Cyril Hrubis | 0b9589f | 2014-05-27 17:40:33 +0200 | [diff] [blame] | 82 | const char *msg; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 83 | int lc; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 84 | |
| 85 | /* Parse standard options given to run the test. */ |
| 86 | msg = parse_opts(argc, argv, 0, 0); |
Garrett Cooper | df3eb16 | 2010-11-28 22:44:32 -0800 | [diff] [blame] | 87 | if (msg != NULL) { |
Garrett Cooper | 5374050 | 2010-12-16 00:04:01 -0800 | [diff] [blame] | 88 | tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | pid = getpid(); |
| 92 | |
| 93 | setup(); |
| 94 | |
| 95 | for (lc = 0; TEST_LOOPING(lc); ++lc) |
| 96 | do_tests(); |
| 97 | |
| 98 | cleanup(); |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 99 | |
| 100 | tst_exit(); |
| 101 | } |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 102 | |
| 103 | #define NH_TEST 0x9f |
| 104 | |
| 105 | #ifndef IPV6_RECVPKTINFO |
| 106 | #define IPV6_RECVPKTINFO -1 |
| 107 | #endif |
| 108 | #ifndef IPV6_RECVHOPLIMIT |
| 109 | #define IPV6_RECVHOPLIMIT -1 |
| 110 | #endif |
| 111 | #ifndef IPV6_RECVRTHDR |
| 112 | #define IPV6_RECVRTHDR -1 |
| 113 | #endif |
| 114 | #ifndef IPV6_RECVHOPOPTS |
| 115 | #define IPV6_RECVHOPOPTS -1 |
| 116 | #endif |
| 117 | #ifndef IPV6_RECVDSTOPTS |
| 118 | #define IPV6_RECVDSTOPTS -1 |
| 119 | #endif |
| 120 | #ifndef IPV6_RECVTCLASS |
| 121 | #define IPV6_RECVTCLASS -1 |
| 122 | #endif |
| 123 | #ifndef IPV6_TCLASS |
| 124 | #define IPV6_TCLASS -1 |
| 125 | #endif |
| 126 | #ifndef IPV6_2292PKTINFO |
| 127 | #define IPV6_2292PKTINFO -1 |
| 128 | #endif |
| 129 | #ifndef IPV6_2292HOPLIMIT |
| 130 | #define IPV6_2292HOPLIMIT -1 |
| 131 | #endif |
| 132 | #ifndef IPV6_2292RTHDR |
| 133 | #define IPV6_2292RTHDR -1 |
| 134 | #endif |
| 135 | #ifndef IPV6_2292HOPOPTS |
| 136 | #define IPV6_2292HOPOPTS -1 |
| 137 | #endif |
| 138 | #ifndef IPV6_2292DSTOPTS |
| 139 | #define IPV6_2292DSTOPTS -1 |
| 140 | #endif |
| 141 | |
| 142 | union soval { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 143 | struct in6_pktinfo sou_pktinfo; |
| 144 | int sou_hoplimit; |
| 145 | struct sockaddr_in6 sou_nexthop; |
| 146 | struct ip6_rthdr sou_rthdr; |
| 147 | struct ip6_hbh sou_hopopts; |
| 148 | struct ip6_dest sou_dstopts; |
| 149 | struct ip6_dest sou_rthdrdstopts; |
| 150 | int sou_tclass; |
| 151 | int sou_bool; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 152 | }; |
| 153 | |
| 154 | /* in6_addr initializer for loopback interface */ |
| 155 | #define IN6_LOOP {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } |
| 156 | #define IN6_ANY {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } |
| 157 | |
subrata_modak | 005dc01 | 2008-12-12 13:39:59 +0000 | [diff] [blame] | 158 | /* so_clrval and so_setval members are initilized in the body */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 159 | struct soent { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 160 | char *so_tname; |
| 161 | int so_opt; |
| 162 | int so_dorecv; /* do receive test? */ |
| 163 | int so_cmtype; |
| 164 | int so_clear; /* get fresh socket? */ |
| 165 | union soval so_clrval; |
| 166 | union soval so_setval; |
| 167 | socklen_t so_valsize; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 168 | } sotab[] = { |
| 169 | /* RFC 3542, Section 4 */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 170 | { |
| 171 | "IPV6_RECVPKTINFO", IPV6_RECVPKTINFO, 1, IPV6_PKTINFO, 1, { { { { { |
| 172 | 0}}}}}, { { { { { |
| 173 | 0}}}}}, sizeof(int)}, { |
| 174 | "IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT, 1, IPV6_HOPLIMIT, 1, { { { { { |
| 175 | 0}}}}}, { { { { { |
| 176 | 0}}}}}, sizeof(int)}, { |
| 177 | "IPV6_RECVRTHDR", IPV6_RECVRTHDR, 0, IPV6_RTHDR, 1, { { { { { |
| 178 | 0}}}}}, { { { { { |
| 179 | 0}}}}}, sizeof(int)}, { |
| 180 | "IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS, 0, IPV6_HOPOPTS, 1, { { { { { |
| 181 | 0}}}}}, { { { { { |
| 182 | 0}}}}}, sizeof(int)}, { |
| 183 | "IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS, 0, IPV6_DSTOPTS, 1, { { { { { |
| 184 | 0}}}}}, { { { { { |
| 185 | 0}}}}}, sizeof(int)}, { |
| 186 | "IPV6_RECVTCLASS", IPV6_RECVTCLASS, 1, IPV6_TCLASS, 1, { { { { { |
| 187 | 0}}}}}, { { { { { |
| 188 | 0}}}}}, sizeof(int)}, |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 189 | /* make sure TCLASS stays when setting another opt */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 190 | { |
| 191 | "IPV6_RECVTCLASS (2)", IPV6_RECVHOPLIMIT, 1, IPV6_TCLASS, 0, { { { { { |
| 192 | 0}}}}}, { { { { { |
| 193 | 0}}}}}, sizeof(int)}, |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 194 | /* OLD values */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 195 | { |
| 196 | "IPV6_2292PKTINFO", IPV6_2292PKTINFO, 1, IPV6_2292PKTINFO, 1, { { { { { |
| 197 | 0}}}}}, { { { { { |
| 198 | 0}}}}}, sizeof(int)}, { |
| 199 | "IPV6_2292HOPLIMIT", IPV6_2292HOPLIMIT, 1, IPV6_2292HOPLIMIT, 1, { { { { { |
| 200 | 0}}}}}, { { { { { |
| 201 | 0}}}}}, sizeof(int)}, { |
| 202 | "IPV6_2292RTHDR", IPV6_2292RTHDR, 0, IPV6_2292RTHDR, 1, { { { { { |
| 203 | 0}}}}}, { { { { { |
| 204 | 0}}}}}, sizeof(int)}, { |
| 205 | "IPV6_2292HOPOPTS", IPV6_2292HOPOPTS, 0, IPV6_2292HOPOPTS, 1, { { { { { |
| 206 | 0}}}}}, { { { { { |
| 207 | 0}}}}}, sizeof(int)}, { |
| 208 | "IPV6_2292DSTOPTS", IPV6_2292DSTOPTS, 0, IPV6_2292DSTOPTS, 1, { { { { { |
| 209 | 0}}}}}, { { { { { |
| 210 | 0}}}}}, sizeof(int)},}; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 211 | |
| 212 | #define SOCOUNT (sizeof(sotab)/sizeof(sotab[0])) |
| 213 | |
| 214 | struct soprot { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 215 | int sop_pid; /* sender PID */ |
| 216 | int sop_seq; /* sequence # */ |
| 217 | int sop_dlen; /* tp_dat length */ |
| 218 | unsigned char sop_dat[0]; /* user data */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 219 | }; |
| 220 | |
| 221 | unsigned char tpbuf[sizeof(struct soprot) + 2048]; |
| 222 | unsigned char rpbuf[sizeof(struct soprot) + 2048]; |
| 223 | |
| 224 | unsigned char control[2048]; |
| 225 | int clen; |
| 226 | |
| 227 | int seq; |
| 228 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 229 | int setupso(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 230 | { |
| 231 | /* add routing headers, other ancillary data here */ |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | struct cme { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 236 | int cm_len; |
| 237 | int cm_level; |
| 238 | int cm_type; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 239 | union { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 240 | uint32_t cmu_tclass; |
mreed10 | 1c06925 | 2006-09-22 19:57:07 +0000 | [diff] [blame] | 241 | uint32_t cmu_hops; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 242 | } cmu; |
| 243 | } cmtab[] = { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 244 | { |
| 245 | sizeof(uint32_t), SOL_IPV6, IPV6_TCLASS, { |
| 246 | 0x12} |
| 247 | } |
| 248 | , { |
| 249 | sizeof(uint32_t), SOL_IPV6, IPV6_HOPLIMIT, { |
| 250 | 0x21} |
| 251 | } |
| 252 | ,}; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 253 | |
| 254 | #define CMCOUNT (sizeof(cmtab)/sizeof(cmtab[0])) |
| 255 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 256 | ssize_t sendall(int st) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 257 | { |
| 258 | struct sockaddr_in6 sin6; |
| 259 | struct msghdr msg; |
| 260 | struct iovec iov; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 261 | struct soprot *psop; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 262 | unsigned char *pd; |
| 263 | int i, ctotal; |
| 264 | |
| 265 | psop = (struct soprot *)tpbuf; |
| 266 | psop->sop_pid = htonl(getpid()); |
| 267 | psop->sop_seq = ++seq; |
| 268 | psop->sop_dlen = 0; |
| 269 | |
| 270 | memset(&sin6, 0, sizeof(sin6)); |
| 271 | sin6.sin6_family = AF_INET6; |
| 272 | sin6.sin6_addr = in6addr_loopback; |
| 273 | |
| 274 | memset(&msg, 0, sizeof(msg)); |
| 275 | msg.msg_name = &sin6; |
| 276 | msg.msg_namelen = sizeof(sin6); |
| 277 | iov.iov_base = tpbuf; |
| 278 | iov.iov_len = sizeof(struct soprot) + ntohl(psop->sop_dlen); |
| 279 | msg.msg_iov = &iov; |
| 280 | msg.msg_iovlen = 1; |
| 281 | |
| 282 | pd = control; |
| 283 | ctotal = 0; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 284 | for (i = 0; i < CMCOUNT; ++i) { |
| 285 | struct cmsghdr *pcmsg = (struct cmsghdr *)pd; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 286 | |
| 287 | pcmsg->cmsg_len = CMSG_LEN(cmtab[i].cm_len); |
| 288 | pcmsg->cmsg_level = cmtab[i].cm_level; |
| 289 | pcmsg->cmsg_type = cmtab[i].cm_type; |
| 290 | memcpy(CMSG_DATA(pcmsg), &cmtab[i].cmu, cmtab[i].cm_len); |
| 291 | pd += CMSG_SPACE(cmtab[i].cm_len); |
| 292 | ctotal += CMSG_SPACE(cmtab[i].cm_len); |
| 293 | } |
| 294 | msg.msg_control = ctotal ? control : 0; |
| 295 | msg.msg_controllen = ctotal; |
| 296 | |
| 297 | return sendmsg(st, &msg, 0); |
| 298 | } |
| 299 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 300 | void so_test(struct soent *psoe) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 301 | { |
| 302 | struct sockaddr_in6 sin6; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 303 | union soval sobuf; |
| 304 | socklen_t valsize; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 305 | static int sr = -1; |
| 306 | int st; |
| 307 | |
Garrett Cooper | 8fb1cdb | 2010-11-28 22:56:35 -0800 | [diff] [blame] | 308 | if (psoe->so_opt == -1) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 309 | tst_resm(TBROK, "%s not present at compile time", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 310 | psoe->so_tname); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 311 | return; |
| 312 | } |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 313 | if (psoe->so_clear || sr < 0) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 314 | if (sr < 0) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 315 | close(sr); |
| 316 | sr = socket(PF_INET6, SOCK_RAW, NH_TEST); |
| 317 | if (sr < 0) { |
| 318 | tst_resm(TBROK, "%s socket: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 319 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 320 | return; |
| 321 | } |
| 322 | } |
| 323 | memset(&sin6, 0, sizeof(sin6)); |
| 324 | sin6.sin6_family = AF_INET6; |
| 325 | sin6.sin6_addr = in6addr_loopback; |
| 326 | if (bind(sr, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { |
| 327 | tst_resm(TBROK, "%s: bind: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 328 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 329 | } |
| 330 | if (setsockopt(sr, SOL_IPV6, psoe->so_opt, &psoe->so_clrval, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 331 | psoe->so_valsize) < 0) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 332 | tst_resm(TBROK, "%s: setsockopt: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 333 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 334 | return; |
| 335 | } |
| 336 | TEST(setsockopt(sr, SOL_IPV6, psoe->so_opt, &psoe->so_setval, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 337 | psoe->so_valsize)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 338 | if (TEST_RETURN != 0) { |
| 339 | tst_resm(TFAIL, "%s set-get: setsockopt: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 340 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 341 | return; |
| 342 | } |
| 343 | valsize = psoe->so_valsize; |
vapier | 0559d69 | 2006-08-21 07:02:02 +0000 | [diff] [blame] | 344 | TEST(getsockopt(sr, SOL_IPV6, psoe->so_opt, &sobuf, &valsize)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 345 | if (TEST_RETURN != 0) { |
| 346 | tst_resm(TBROK, "%s set-get: getsockopt: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 347 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 348 | return; |
| 349 | } else if (memcmp(&psoe->so_setval, &sobuf, psoe->so_valsize)) |
| 350 | tst_resm(TFAIL, "%s set-get optval != setval", psoe->so_tname); |
| 351 | else |
| 352 | tst_resm(TPASS, "%s set-get", psoe->so_tname); |
| 353 | |
| 354 | st = socket(PF_INET6, SOCK_RAW, NH_TEST); |
| 355 | if (st < 0) { |
| 356 | tst_resm(TBROK, "%s transmit socket: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 357 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 358 | return; |
| 359 | } |
| 360 | if (sendall(st) < 0) { |
| 361 | tst_resm(TBROK, "%s transmit sendto: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 362 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 363 | close(st); |
| 364 | return; |
| 365 | } |
| 366 | close(st); |
| 367 | |
| 368 | /* receiver processing */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 369 | { |
| 370 | fd_set rfds, rfds_saved; |
| 371 | int nfds, cc; |
| 372 | int gotone; |
| 373 | struct timeval tv; |
| 374 | struct msghdr msg; |
| 375 | unsigned char cmsg[2048]; |
| 376 | struct cmsghdr *pcmsg; |
| 377 | struct iovec iov; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 378 | |
| 379 | FD_ZERO(&rfds_saved); |
| 380 | FD_SET(sr, &rfds_saved); |
| 381 | |
| 382 | tv.tv_sec = 0; |
| 383 | tv.tv_usec = 250000; |
| 384 | |
| 385 | while (1) { |
| 386 | memcpy(&rfds, &rfds_saved, sizeof(rfds)); |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 387 | nfds = select(sr + 1, &rfds, 0, 0, &tv); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 388 | if (nfds < 0) { |
| 389 | if (errno == EINTR) |
| 390 | continue; |
| 391 | tst_resm(TBROK, "%s select: %s", psoe->so_tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 392 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 393 | return; |
| 394 | } |
| 395 | if (nfds == 0) { |
| 396 | tst_resm(TBROK, "%s recvmsg timed out", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 397 | psoe->so_tname); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 398 | return; |
| 399 | } |
| 400 | /* else, nfds == 1 */ |
| 401 | if (!FD_ISSET(sr, &rfds)) |
| 402 | continue; |
| 403 | |
| 404 | memset(&msg, 0, sizeof(msg)); |
| 405 | iov.iov_base = rpbuf; |
| 406 | iov.iov_len = sizeof(rpbuf); |
| 407 | msg.msg_iov = &iov; |
| 408 | msg.msg_iovlen = 1; |
| 409 | msg.msg_control = cmsg; |
| 410 | msg.msg_controllen = sizeof(cmsg); |
| 411 | |
| 412 | cc = recvmsg(sr, &msg, 0); |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 413 | if (cc < 0) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 414 | tst_resm(TBROK, "%s recvmsg: %s", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 415 | psoe->so_tname, strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 416 | return; |
| 417 | } |
| 418 | /* check pid & seq here */ |
| 419 | break; |
| 420 | } |
| 421 | gotone = 0; |
subrata_modak | 0102c2c | 2008-09-18 13:17:31 +0000 | [diff] [blame] | 422 | for (pcmsg = CMSG_FIRSTHDR(&msg); pcmsg != NULL; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 423 | pcmsg = CMSG_NXTHDR(&msg, pcmsg)) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 424 | if (!psoe->so_dorecv) |
| 425 | break; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 426 | gotone = pcmsg->cmsg_level == SOL_IPV6 && |
| 427 | pcmsg->cmsg_type == psoe->so_cmtype; |
| 428 | if (gotone) |
| 429 | break; |
| 430 | else if (psoe->so_clear) { |
| 431 | tst_resm(TFAIL, "%s receive: extraneous data " |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 432 | "in control: level %d type %d len %zu", |
| 433 | psoe->so_tname, pcmsg->cmsg_level, |
| 434 | pcmsg->cmsg_type, pcmsg->cmsg_len); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 435 | return; |
| 436 | } |
| 437 | } |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 438 | /* check contents here */ |
| 439 | if (psoe->so_dorecv) |
| 440 | tst_resm(gotone ? TPASS : TFAIL, "%s receive", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 441 | psoe->so_tname); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 442 | } |
| 443 | } |
| 444 | |
| 445 | #define IPV6_ADDR_NODE 1 |
| 446 | #define IPV6_ADDR_LINK 2 |
| 447 | #define IPV6_ADDR_GLOBAL 3 |
| 448 | |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 449 | #ifdef HAVE_IFADDRS_H |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 450 | static int ipv6_addr_scope(struct in6_addr *pin6) |
| 451 | { |
| 452 | if ((ntohl(pin6->s6_addr32[0]) & 0xFFC00000) == 0xFE800000) |
| 453 | return IPV6_ADDR_LINK; |
| 454 | if (memcmp(pin6, &in6addr_loopback, sizeof(*pin6)) == 0) |
| 455 | return IPV6_ADDR_NODE; |
| 456 | return IPV6_ADDR_GLOBAL; |
| 457 | } |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 458 | #endif /* HAVE_IFADDRS_H */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 459 | |
| 460 | int getsock(char *tname, struct sockaddr_in6 *psin6_arg, int scope) |
| 461 | { |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 462 | #ifdef HAVE_IFADDRS_H |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 463 | static struct ifaddrs *pifa_head; |
| 464 | struct ifaddrs *pifa; |
| 465 | struct sockaddr_in6 *psin6; |
| 466 | char strbuf[128]; |
| 467 | int ifindex = 0; |
| 468 | int s; |
| 469 | |
| 470 | if (!pifa_head && getifaddrs(&pifa_head)) { |
| 471 | tst_resm(TBROK, "%s: getifaddrs failed", tname); |
| 472 | return -1; |
| 473 | } |
| 474 | if (psin6_arg) |
| 475 | ifindex = psin6_arg->sin6_scope_id; |
| 476 | |
| 477 | /* first, find a global address */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 478 | for (pifa = pifa_head; pifa; pifa = pifa->ifa_next) { |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 479 | int this_scope; |
| 480 | |
| 481 | if (!(pifa->ifa_flags & IFF_UP)) |
| 482 | continue; |
| 483 | if (pifa->ifa_addr->sa_family != AF_INET6) |
| 484 | continue; |
| 485 | psin6 = (struct sockaddr_in6 *)pifa->ifa_addr; |
| 486 | this_scope = ipv6_addr_scope(&psin6->sin6_addr); |
| 487 | if (this_scope && |
| 488 | ((this_scope < 0 && -this_scope == scope) || |
| 489 | (this_scope > 0 && this_scope != scope))) |
| 490 | continue; |
| 491 | psin6->sin6_scope_id = if_nametoindex(pifa->ifa_name); |
| 492 | if ((ifindex < 0 && -ifindex == psin6->sin6_scope_id) || |
| 493 | (ifindex > 0 && ifindex != psin6->sin6_scope_id)) |
| 494 | continue; |
| 495 | s = socket(PF_INET6, SOCK_DGRAM, 0); |
| 496 | if (s < 0) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 497 | tst_resm(TBROK, "%s: socket %s", tname, |
| 498 | strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 499 | return -1; |
| 500 | } |
| 501 | if (bind(s, pifa->ifa_addr, sizeof(struct sockaddr_in6)) < 0) { |
| 502 | tst_resm(TBROK, "%s: bind \"%s\": %s", tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 503 | inet_ntop(AF_INET6, &psin6->sin6_addr, strbuf, |
| 504 | sizeof(strbuf)), strerror(errno)); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 505 | return -1; |
| 506 | } |
| 507 | if (psin6_arg) { |
| 508 | *psin6_arg = *psin6; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 509 | psin6_arg->sin6_scope_id = |
| 510 | if_nametoindex(pifa->ifa_name); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 511 | } |
| 512 | return s; |
| 513 | } |
| 514 | { |
| 515 | char *scopestr, *intfstr; |
| 516 | |
| 517 | switch (scope) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 518 | case IPV6_ADDR_NODE: |
| 519 | scopestr = " node-local"; |
| 520 | break; |
| 521 | case IPV6_ADDR_LINK: |
| 522 | scopestr = " link-local"; |
| 523 | break; |
| 524 | case IPV6_ADDR_GLOBAL: |
| 525 | scopestr = " global"; |
| 526 | break; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 527 | default: |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 528 | scopestr = ""; |
| 529 | break; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 530 | } |
| 531 | if (ifindex < 0) { |
| 532 | intfstr = " not on ifindex"; |
| 533 | ifindex = -ifindex; |
| 534 | } else if (ifindex) |
| 535 | intfstr = " on ifindex"; |
| 536 | else |
| 537 | intfstr = 0; |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 538 | |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 539 | if (intfstr) |
| 540 | tst_resm(TBROK, "%s: getsock : no%s addresses%s %d", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 541 | tname, scopestr, intfstr, ifindex); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 542 | else |
| 543 | tst_resm(TBROK, "%s: getsock : no%s addresses", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 544 | tname, scopestr); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 545 | } |
| 546 | return -1; |
subrata_modak | 5256819 | 2008-12-12 13:43:40 +0000 | [diff] [blame] | 547 | #else /* HAVE_IFADDRS_H */ |
| 548 | return -1; |
| 549 | #endif |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 550 | } |
| 551 | |
| 552 | #ifdef notyet |
| 553 | /* |
| 554 | * RFC 3542 IPV6_PKTINFO not in mainline yet (as of 2.6.15). The get/set |
| 555 | * tests are below, and comments for some further tests to be added later |
| 556 | */ |
| 557 | void test_pktinfo(void) |
| 558 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 559 | int s_snd, s_rcv[3] = { -1, -1, -1 }; |
| 560 | struct sockaddr_in6 sa_rcv[3]; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 561 | int s, i; |
| 562 | struct ifaddrs *pifa_head, *pifa; |
| 563 | struct sockaddr_in6 *psin6; |
| 564 | char strbuf[128]; |
| 565 | char *tname = "IPV6_PKTINFO"; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 566 | struct in6_pktinfo pi, pi_tmp; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 567 | int sinlen; |
| 568 | int optlen; |
| 569 | |
| 570 | s_snd = getsock(tname, 0, IPV6_ADDR_GLOBAL); |
| 571 | if (s_snd < 0) { |
| 572 | tst_resm(TBROK, "%s: can't create send socket", tname); |
| 573 | return; |
| 574 | } |
| 575 | /* global-scope address, interface X */ |
| 576 | sa_rcv[0].sin6_scope_id = 0; |
| 577 | s_rcv[0] = getsock(tname, &sa_rcv[0], IPV6_ADDR_GLOBAL); |
| 578 | if (s_rcv[0] == -1) { |
| 579 | tst_resm(TBROK, "%s: only link-scope addresses", tname); |
| 580 | return; |
| 581 | } |
| 582 | /* link-local-scope address, interface X */ |
| 583 | sa_rcv[1].sin6_scope_id = sa_rcv[0].sin6_scope_id; |
| 584 | s_rcv[1] = getsock(tname, &sa_rcv[1], IPV6_ADDR_LINK); |
| 585 | if (s_rcv[1] < 0) { |
| 586 | tst_resm(TBROK, "%s: no link-local address on ifindex %d", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 587 | tname, sa_rcv[0].sin6_scope_id); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 588 | return; |
| 589 | } |
| 590 | /* link-local-scope address, interface Y */ |
| 591 | sa_rcv[2].sin6_scope_id = -sa_rcv[0].sin6_scope_id; |
| 592 | s_rcv[2] = getsock(tname, &sa_rcv[2], IPV6_ADDR_LINK); |
| 593 | if (s_rcv[2] < 0) { |
| 594 | tst_resm(TBROK, "%s: only one interface?", tname); |
| 595 | return; |
| 596 | } |
| 597 | /* send to rcv1 to verify communication */ |
| 598 | /* force to rcv2 w/ PKTINFO */ |
| 599 | /* TESTS: */ |
| 600 | /* sticky set-get */ |
| 601 | tname = "IPV6_PKTINFO set"; |
| 602 | pi.ipi6_addr = sa_rcv[1].sin6_addr; |
| 603 | pi.ipi6_ifindex = sa_rcv[1].sin6_scope_id; |
| 604 | TEST(setsockopt(s_snd, SOL_IPV6, IPV6_PKTINFO, &pi, sizeof(pi))); |
| 605 | if (TEST_RETURN != 0) |
| 606 | tst_resm(TFAIL, "%s: %s", tname, strerror(errno)); |
| 607 | else |
| 608 | tst_resm(TPASS, "%s", tname); |
| 609 | |
| 610 | tname = "IPV6_PKTINFO get"; |
| 611 | optlen = sizeof(pi_tmp); |
| 612 | TEST(getsockopt(s_snd, SOL_IPV6, IPV6_PKTINFO, &pi_tmp, &optlen)); |
| 613 | if (TEST_RETURN != 0) |
| 614 | tst_resm(TFAIL, "%s: %s", tname, strerror(errno)); |
| 615 | else if (memcmp(&pi, &pi_tmp, sizeof(pi)) != 0) { |
| 616 | char strbuf2[64]; |
| 617 | tst_resm(TFAIL, "%s: {\"%s\",%d} != {\"%s\",%d}", tname, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 618 | inet_ntop(AF_INET6, &pi_tmp.ipi6_addr, strbuf, |
| 619 | sizeof(strbuf)), pi_tmp.ipi6_ifindex, |
| 620 | inet_ntop(AF_INET6, &pi.ipi6_addr, strbuf2, |
| 621 | sizeof(strbuf2)), pi.ipi6_ifindex); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 622 | } else |
| 623 | tst_resm(TPASS, "%s", tname); |
| 624 | /* ancillary data override */ |
| 625 | /* link-local, wrong interface */ |
| 626 | tname = "IPV6_PKTINFO invalid {lladdr, intf}"; |
| 627 | pi.ipi6_addr = sa_rcv[1].sin6_addr; |
| 628 | pi.ipi6_ifindex = sa_rcv[2].sin6_scope_id; |
| 629 | TEST(setsockopt(s_snd, SOL_IPV6, IPV6_PKTINFO, &pi, sizeof(pi))); |
| 630 | if (TEST_RETURN == 0) |
| 631 | tst_resm(TFAIL, "%s returns success, should be -1, EINVAL", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 632 | tname); |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 633 | else if (TEST_ERRNO != EINVAL) |
| 634 | tst_resm(TFAIL, "%s errno %d != %d", tname, TEST_ERRNO, EINVAL); |
| 635 | else |
| 636 | tst_resm(TPASS, "%s", tname); |
| 637 | /* nonexistent interface */ |
| 638 | /* non-local address */ |
| 639 | /* clear address */ |
| 640 | /* clear interface */ |
| 641 | /* sendmsg() sin6_scope differs with ancillary data interface */ |
| 642 | } |
| 643 | #endif /* notyet */ |
| 644 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 645 | void do_tests(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 646 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 647 | int i; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 648 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 649 | for (i = 0; i < SOCOUNT; ++i) { |
subrata_modak | 005dc01 | 2008-12-12 13:39:59 +0000 | [diff] [blame] | 650 | sotab[i].so_clrval.sou_bool = 0; |
| 651 | sotab[i].so_setval.sou_bool = 1; |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 652 | so_test(&sotab[i]); |
| 653 | } |
| 654 | #ifdef notyet |
| 655 | test_pktinfo(); |
| 656 | #endif /* notyet - see test_pktinfo() comment above */ |
| 657 | } |
| 658 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 659 | void setup(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 660 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 661 | TEST_PAUSE; /* if -P option specified */ |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 662 | } |
| 663 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 664 | void cleanup(void) |
mridge | 949c5b1 | 2006-01-03 23:01:28 +0000 | [diff] [blame] | 665 | { |
Markos Chandras | c0762b8 | 2012-01-03 13:23:39 +0000 | [diff] [blame] | 666 | } |