1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * TCP-AO selftest library. Provides helpers to unshare network 4 * namespaces, create veth, assign ip addresses, set routes, 5 * manipulate socket options, read network counter and etc. 6 * Author: Dmitry Safonov <dima@arista.com> 7 */ 8 #ifndef _AOLIB_H_ 9 #define _AOLIB_H_ 10 11 #include <arpa/inet.h> 12 #include <errno.h> 13 #include <linux/snmp.h> 14 #include <linux/tcp.h> 15 #include <netinet/in.h> 16 #include <stdarg.h> 17 #include <stdbool.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <sys/syscall.h> 22 #include <unistd.h> 23 24 #include "../../../../../include/linux/stringify.h" 25 #include "../../../../../include/linux/bits.h" 26 27 #ifndef SOL_TCP 28 /* can't include <netinet/tcp.h> as including <linux/tcp.h> */ 29 # define SOL_TCP 6 /* TCP level */ 30 #endif 31 32 /* Working around ksft, see the comment in lib/setup.c */ 33 extern void __test_msg(const char *buf); 34 extern void __test_ok(const char *buf); 35 extern void __test_fail(const char *buf); 36 extern void __test_xfail(const char *buf); 37 extern void __test_error(const char *buf); 38 extern void __test_skip(const char *buf); 39 40 __attribute__((__format__(__printf__, 2, 3))) 41 static inline void __test_print(void (*fn)(const char *), const char *fmt, ...) 42 { 43 #define TEST_MSG_BUFFER_SIZE 4096 44 char buf[TEST_MSG_BUFFER_SIZE]; 45 va_list arg; 46 47 va_start(arg, fmt); 48 vsnprintf(buf, sizeof(buf), fmt, arg); 49 va_end(arg); 50 fn(buf); 51 } 52 53 #define test_print(fmt, ...) \ 54 __test_print(__test_msg, "%ld[%s:%u] " fmt "\n", \ 55 syscall(SYS_gettid), \ 56 __FILE__, __LINE__, ##__VA_ARGS__) 57 58 #define test_ok(fmt, ...) \ 59 __test_print(__test_ok, fmt "\n", ##__VA_ARGS__) 60 #define test_skip(fmt, ...) \ 61 __test_print(__test_skip, fmt "\n", ##__VA_ARGS__) 62 #define test_xfail(fmt, ...) \ 63 __test_print(__test_xfail, fmt "\n", ##__VA_ARGS__) 64 65 #define test_fail(fmt, ...) \ 66 do { \ 67 if (errno) \ 68 __test_print(__test_fail, fmt ": %m\n", ##__VA_ARGS__); \ 69 else \ 70 __test_print(__test_fail, fmt "\n", ##__VA_ARGS__); \ 71 test_failed(); \ 72 } while (0) 73 74 #define KSFT_FAIL 1 75 #define test_error(fmt, ...) \ 76 do { \ 77 if (errno) \ 78 __test_print(__test_error, "%ld[%s:%u] " fmt ": %m\n", \ 79 syscall(SYS_gettid), __FILE__, __LINE__, \ 80 ##__VA_ARGS__); \ 81 else \ 82 __test_print(__test_error, "%ld[%s:%u] " fmt "\n", \ 83 syscall(SYS_gettid), __FILE__, __LINE__, \ 84 ##__VA_ARGS__); \ 85 exit(KSFT_FAIL); \ 86 } while (0) 87 88 enum test_fault { 89 FAULT_TIMEOUT = 1, 90 FAULT_KEYREJECT, 91 FAULT_PREINSTALL_AO, 92 FAULT_PREINSTALL_MD5, 93 FAULT_POSTINSTALL, 94 FAULT_BUSY, 95 FAULT_CURRNEXT, 96 FAULT_FIXME, 97 }; 98 typedef enum test_fault fault_t; 99 100 enum test_needs_kconfig { 101 KCONFIG_NET_NS = 0, /* required */ 102 KCONFIG_VETH, /* required */ 103 KCONFIG_TCP_AO, /* required */ 104 KCONFIG_TCP_MD5, /* optional, for TCP-MD5 features */ 105 KCONFIG_NET_VRF, /* optional, for L3/VRF testing */ 106 __KCONFIG_LAST__ 107 }; 108 extern bool kernel_config_has(enum test_needs_kconfig k); 109 extern const char *tests_skip_reason[__KCONFIG_LAST__]; 110 static inline bool should_skip_test(const char *tst_name, 111 enum test_needs_kconfig k) 112 { 113 if (kernel_config_has(k)) 114 return false; 115 test_skip("%s: %s", tst_name, tests_skip_reason[k]); 116 return true; 117 } 118 119 union tcp_addr { 120 struct in_addr a4; 121 struct in6_addr a6; 122 }; 123 124 typedef void *(*thread_fn)(void *); 125 extern void test_failed(void); 126 extern void __test_init(unsigned int ntests, int family, unsigned int prefix, 127 union tcp_addr addr1, union tcp_addr addr2, 128 thread_fn peer1, thread_fn peer2); 129 130 static inline void test_init2(unsigned int ntests, 131 thread_fn peer1, thread_fn peer2, 132 int family, unsigned int prefix, 133 const char *addr1, const char *addr2) 134 { 135 union tcp_addr taddr1, taddr2; 136 137 if (inet_pton(family, addr1, &taddr1) != 1) 138 test_error("Can't convert ip address %s", addr1); 139 if (inet_pton(family, addr2, &taddr2) != 1) 140 test_error("Can't convert ip address %s", addr2); 141 142 __test_init(ntests, family, prefix, taddr1, taddr2, peer1, peer2); 143 } 144 extern void test_add_destructor(void (*d)(void)); 145 146 /* To adjust optmem socket limit, approximately estimate a number, 147 * that is bigger than sizeof(struct tcp_ao_key). 148 */ 149 #define KERNEL_TCP_AO_KEY_SZ_ROUND_UP 300 150 151 extern void test_set_optmem(size_t value); 152 extern size_t test_get_optmem(void); 153 154 extern const struct sockaddr_in6 addr_any6; 155 extern const struct sockaddr_in addr_any4; 156 157 #ifdef IPV6_TEST 158 # define __TEST_CLIENT_IP(n) ("2001:db8:" __stringify(n) "::1") 159 # define TEST_CLIENT_IP __TEST_CLIENT_IP(1) 160 # define TEST_WRONG_IP "2001:db8:253::1" 161 # define TEST_SERVER_IP "2001:db8:254::1" 162 # define TEST_NETWORK "2001::" 163 # define TEST_PREFIX 128 164 # define TEST_FAMILY AF_INET6 165 # define SOCKADDR_ANY addr_any6 166 # define sockaddr_af struct sockaddr_in6 167 #else 168 # define __TEST_CLIENT_IP(n) ("10.0." __stringify(n) ".1") 169 # define TEST_CLIENT_IP __TEST_CLIENT_IP(1) 170 # define TEST_WRONG_IP "10.0.253.1" 171 # define TEST_SERVER_IP "10.0.254.1" 172 # define TEST_NETWORK "10.0.0.0" 173 # define TEST_PREFIX 32 174 # define TEST_FAMILY AF_INET 175 # define SOCKADDR_ANY addr_any4 176 # define sockaddr_af struct sockaddr_in 177 #endif 178 179 static inline union tcp_addr gen_tcp_addr(union tcp_addr net, size_t n) 180 { 181 union tcp_addr ret = net; 182 183 #ifdef IPV6_TEST 184 ret.a6.s6_addr32[3] = htonl(n & (BIT(32) - 1)); 185 ret.a6.s6_addr32[2] = htonl((n >> 32) & (BIT(32) - 1)); 186 #else 187 ret.a4.s_addr = htonl(ntohl(net.a4.s_addr) + n); 188 #endif 189 190 return ret; 191 } 192 193 static inline void tcp_addr_to_sockaddr_in(void *dest, 194 const union tcp_addr *src, 195 unsigned int port) 196 { 197 sockaddr_af *out = dest; 198 199 memset(out, 0, sizeof(*out)); 200 #ifdef IPV6_TEST 201 out->sin6_family = AF_INET6; 202 out->sin6_port = port; 203 out->sin6_addr = src->a6; 204 #else 205 out->sin_family = AF_INET; 206 out->sin_port = port; 207 out->sin_addr = src->a4; 208 #endif 209 } 210 211 static inline void test_init(unsigned int ntests, 212 thread_fn peer1, thread_fn peer2) 213 { 214 test_init2(ntests, peer1, peer2, TEST_FAMILY, TEST_PREFIX, 215 TEST_SERVER_IP, TEST_CLIENT_IP); 216 } 217 extern void synchronize_threads(void); 218 extern void switch_ns(int fd); 219 220 extern __thread union tcp_addr this_ip_addr; 221 extern __thread union tcp_addr this_ip_dest; 222 extern int test_family; 223 224 extern void randomize_buffer(void *buf, size_t buflen); 225 extern int open_netns(void); 226 extern int unshare_open_netns(void); 227 extern const char veth_name[]; 228 extern int add_veth(const char *name, int nsfda, int nsfdb); 229 extern int add_vrf(const char *name, uint32_t tabid, int ifindex, int nsfd); 230 extern int ip_addr_add(const char *intf, int family, 231 union tcp_addr addr, uint8_t prefix); 232 extern int ip_route_add(const char *intf, int family, 233 union tcp_addr src, union tcp_addr dst); 234 extern int ip_route_add_vrf(const char *intf, int family, 235 union tcp_addr src, union tcp_addr dst, 236 uint8_t vrf); 237 extern int link_set_up(const char *intf); 238 239 extern const unsigned int test_server_port; 240 extern int test_wait_fd(int sk, time_t sec, bool write); 241 extern int __test_connect_socket(int sk, const char *device, 242 void *addr, size_t addr_sz, time_t timeout); 243 extern int __test_listen_socket(int backlog, void *addr, size_t addr_sz); 244 245 static inline int test_listen_socket(const union tcp_addr taddr, 246 unsigned int port, int backlog) 247 { 248 sockaddr_af addr; 249 250 tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port)); 251 return __test_listen_socket(backlog, (void *)&addr, sizeof(addr)); 252 } 253 254 /* 255 * In order for selftests to work under CONFIG_CRYPTO_FIPS=y, 256 * the password should be loger than 14 bytes, see hmac_setkey() 257 */ 258 #define TEST_TCP_AO_MINKEYLEN 14 259 #define DEFAULT_TEST_PASSWORD "In this hour, I do not believe that any darkness will endure." 260 261 #ifndef DEFAULT_TEST_ALGO 262 #define DEFAULT_TEST_ALGO "cmac(aes128)" 263 #endif 264 265 #ifdef IPV6_TEST 266 #define DEFAULT_TEST_PREFIX 128 267 #else 268 #define DEFAULT_TEST_PREFIX 32 269 #endif 270 271 /* 272 * Timeout on syscalls where failure is not expected. 273 * You may want to rise it if the test machine is very busy. 274 */ 275 #ifndef TEST_TIMEOUT_SEC 276 #define TEST_TIMEOUT_SEC 5 277 #endif 278 279 /* 280 * Timeout on connect() where a failure is expected. 281 * If set to 0 - kernel will try to retransmit SYN number of times, set in 282 * /proc/sys/net/ipv4/tcp_syn_retries 283 * By default set to 1 to make tests pass faster on non-busy machine. 284 */ 285 #ifndef TEST_RETRANSMIT_SEC 286 #define TEST_RETRANSMIT_SEC 1 287 #endif 288 289 static inline int _test_connect_socket(int sk, const union tcp_addr taddr, 290 unsigned int port, time_t timeout) 291 { 292 sockaddr_af addr; 293 294 tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port)); 295 return __test_connect_socket(sk, veth_name, 296 (void *)&addr, sizeof(addr), timeout); 297 } 298 299 static inline int test_connect_socket(int sk, const union tcp_addr taddr, 300 unsigned int port) 301 { 302 return _test_connect_socket(sk, taddr, port, TEST_TIMEOUT_SEC); 303 } 304 305 extern int __test_set_md5(int sk, void *addr, size_t addr_sz, 306 uint8_t prefix, int vrf, const char *password); 307 static inline int test_set_md5(int sk, const union tcp_addr in_addr, 308 uint8_t prefix, int vrf, const char *password) 309 { 310 sockaddr_af addr; 311 312 if (prefix > DEFAULT_TEST_PREFIX) 313 prefix = DEFAULT_TEST_PREFIX; 314 315 tcp_addr_to_sockaddr_in(&addr, &in_addr, 0); 316 return __test_set_md5(sk, (void *)&addr, sizeof(addr), 317 prefix, vrf, password); 318 } 319 320 extern int test_prepare_key_sockaddr(struct tcp_ao_add *ao, const char *alg, 321 void *addr, size_t addr_sz, bool set_current, bool set_rnext, 322 uint8_t prefix, uint8_t vrf, 323 uint8_t sndid, uint8_t rcvid, uint8_t maclen, 324 uint8_t keyflags, uint8_t keylen, const char *key); 325 326 static inline int test_prepare_key(struct tcp_ao_add *ao, 327 const char *alg, union tcp_addr taddr, 328 bool set_current, bool set_rnext, 329 uint8_t prefix, uint8_t vrf, 330 uint8_t sndid, uint8_t rcvid, uint8_t maclen, 331 uint8_t keyflags, uint8_t keylen, const char *key) 332 { 333 sockaddr_af addr; 334 335 tcp_addr_to_sockaddr_in(&addr, &taddr, 0); 336 return test_prepare_key_sockaddr(ao, alg, (void *)&addr, sizeof(addr), 337 set_current, set_rnext, prefix, vrf, sndid, rcvid, 338 maclen, keyflags, keylen, key); 339 } 340 341 static inline int test_prepare_def_key(struct tcp_ao_add *ao, 342 const char *key, uint8_t keyflags, 343 union tcp_addr in_addr, uint8_t prefix, uint8_t vrf, 344 uint8_t sndid, uint8_t rcvid) 345 { 346 if (prefix > DEFAULT_TEST_PREFIX) 347 prefix = DEFAULT_TEST_PREFIX; 348 349 return test_prepare_key(ao, DEFAULT_TEST_ALGO, in_addr, false, false, 350 prefix, vrf, sndid, rcvid, 0, keyflags, 351 strlen(key), key); 352 } 353 354 extern int test_get_one_ao(int sk, struct tcp_ao_getsockopt *out, 355 void *addr, size_t addr_sz, 356 uint8_t prefix, uint8_t sndid, uint8_t rcvid); 357 extern int test_get_ao_info(int sk, struct tcp_ao_info_opt *out); 358 extern int test_set_ao_info(int sk, struct tcp_ao_info_opt *in); 359 extern int test_cmp_getsockopt_setsockopt(const struct tcp_ao_add *a, 360 const struct tcp_ao_getsockopt *b); 361 extern int test_cmp_getsockopt_setsockopt_ao(const struct tcp_ao_info_opt *a, 362 const struct tcp_ao_info_opt *b); 363 364 static inline int test_verify_socket_key(int sk, struct tcp_ao_add *key) 365 { 366 struct tcp_ao_getsockopt key2 = {}; 367 int err; 368 369 err = test_get_one_ao(sk, &key2, &key->addr, sizeof(key->addr), 370 key->prefix, key->sndid, key->rcvid); 371 if (err) 372 return err; 373 374 return test_cmp_getsockopt_setsockopt(key, &key2); 375 } 376 377 static inline int test_add_key_vrf(int sk, 378 const char *key, uint8_t keyflags, 379 union tcp_addr in_addr, uint8_t prefix, 380 uint8_t vrf, uint8_t sndid, uint8_t rcvid) 381 { 382 struct tcp_ao_add tmp = {}; 383 int err; 384 385 err = test_prepare_def_key(&tmp, key, keyflags, in_addr, prefix, 386 vrf, sndid, rcvid); 387 if (err) 388 return err; 389 390 err = setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)); 391 if (err < 0) 392 return -errno; 393 394 return test_verify_socket_key(sk, &tmp); 395 } 396 397 static inline int test_add_key(int sk, const char *key, 398 union tcp_addr in_addr, uint8_t prefix, 399 uint8_t sndid, uint8_t rcvid) 400 { 401 return test_add_key_vrf(sk, key, 0, in_addr, prefix, 0, sndid, rcvid); 402 } 403 404 static inline int test_verify_socket_ao(int sk, struct tcp_ao_info_opt *ao) 405 { 406 struct tcp_ao_info_opt ao2 = {}; 407 int err; 408 409 err = test_get_ao_info(sk, &ao2); 410 if (err) 411 return err; 412 413 return test_cmp_getsockopt_setsockopt_ao(ao, &ao2); 414 } 415 416 static inline int test_set_ao_flags(int sk, bool ao_required, bool accept_icmps) 417 { 418 struct tcp_ao_info_opt ao = {}; 419 int err; 420 421 err = test_get_ao_info(sk, &ao); 422 /* Maybe ao_info wasn't allocated yet */ 423 if (err && err != -ENOENT) 424 return err; 425 426 ao.ao_required = !!ao_required; 427 ao.accept_icmps = !!accept_icmps; 428 err = test_set_ao_info(sk, &ao); 429 if (err) 430 return err; 431 432 return test_verify_socket_ao(sk, &ao); 433 } 434 435 extern ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec); 436 extern ssize_t test_client_loop(int sk, char *buf, size_t buf_sz, 437 const size_t msg_len, time_t timeout_sec); 438 extern int test_client_verify(int sk, const size_t msg_len, const size_t nr, 439 time_t timeout_sec); 440 441 struct tcp_ao_key_counters { 442 uint8_t sndid; 443 uint8_t rcvid; 444 uint64_t pkt_good; 445 uint64_t pkt_bad; 446 }; 447 448 struct tcp_ao_counters { 449 /* per-netns */ 450 uint64_t netns_ao_good; 451 uint64_t netns_ao_bad; 452 uint64_t netns_ao_key_not_found; 453 uint64_t netns_ao_required; 454 uint64_t netns_ao_dropped_icmp; 455 /* per-socket */ 456 uint64_t ao_info_pkt_good; 457 uint64_t ao_info_pkt_bad; 458 uint64_t ao_info_pkt_key_not_found; 459 uint64_t ao_info_pkt_ao_required; 460 uint64_t ao_info_pkt_dropped_icmp; 461 /* per-key */ 462 size_t nr_keys; 463 struct tcp_ao_key_counters *key_cnts; 464 }; 465 extern int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out); 466 467 #define TEST_CNT_KEY_GOOD BIT(0) 468 #define TEST_CNT_KEY_BAD BIT(1) 469 #define TEST_CNT_SOCK_GOOD BIT(2) 470 #define TEST_CNT_SOCK_BAD BIT(3) 471 #define TEST_CNT_SOCK_KEY_NOT_FOUND BIT(4) 472 #define TEST_CNT_SOCK_AO_REQUIRED BIT(5) 473 #define TEST_CNT_SOCK_DROPPED_ICMP BIT(6) 474 #define TEST_CNT_NS_GOOD BIT(7) 475 #define TEST_CNT_NS_BAD BIT(8) 476 #define TEST_CNT_NS_KEY_NOT_FOUND BIT(9) 477 #define TEST_CNT_NS_AO_REQUIRED BIT(10) 478 #define TEST_CNT_NS_DROPPED_ICMP BIT(11) 479 typedef uint16_t test_cnt; 480 481 #define TEST_CNT_AO_GOOD (TEST_CNT_SOCK_GOOD | TEST_CNT_NS_GOOD) 482 #define TEST_CNT_AO_BAD (TEST_CNT_SOCK_BAD | TEST_CNT_NS_BAD) 483 #define TEST_CNT_AO_KEY_NOT_FOUND (TEST_CNT_SOCK_KEY_NOT_FOUND | \ 484 TEST_CNT_NS_KEY_NOT_FOUND) 485 #define TEST_CNT_AO_REQUIRED (TEST_CNT_SOCK_AO_REQUIRED | \ 486 TEST_CNT_NS_AO_REQUIRED) 487 #define TEST_CNT_AO_DROPPED_ICMP (TEST_CNT_SOCK_DROPPED_ICMP | \ 488 TEST_CNT_NS_DROPPED_ICMP) 489 #define TEST_CNT_GOOD (TEST_CNT_KEY_GOOD | TEST_CNT_AO_GOOD) 490 #define TEST_CNT_BAD (TEST_CNT_KEY_BAD | TEST_CNT_AO_BAD) 491 492 extern int __test_tcp_ao_counters_cmp(const char *tst_name, 493 struct tcp_ao_counters *before, struct tcp_ao_counters *after, 494 test_cnt expected); 495 extern int test_tcp_ao_key_counters_cmp(const char *tst_name, 496 struct tcp_ao_counters *before, struct tcp_ao_counters *after, 497 test_cnt expected, int sndid, int rcvid); 498 extern void test_tcp_ao_counters_free(struct tcp_ao_counters *cnts); 499 /* 500 * Frees buffers allocated in test_get_tcp_ao_counters(). 501 * The function doesn't expect new keys or keys removed between calls 502 * to test_get_tcp_ao_counters(). Check key counters manually if they 503 * may change. 504 */ 505 static inline int test_tcp_ao_counters_cmp(const char *tst_name, 506 struct tcp_ao_counters *before, 507 struct tcp_ao_counters *after, 508 test_cnt expected) 509 { 510 int ret; 511 512 ret = __test_tcp_ao_counters_cmp(tst_name, before, after, expected); 513 if (ret) 514 goto out; 515 ret = test_tcp_ao_key_counters_cmp(tst_name, before, after, 516 expected, -1, -1); 517 out: 518 test_tcp_ao_counters_free(before); 519 test_tcp_ao_counters_free(after); 520 return ret; 521 } 522 523 struct netstat; 524 extern struct netstat *netstat_read(void); 525 extern void netstat_free(struct netstat *ns); 526 extern void netstat_print_diff(struct netstat *nsa, struct netstat *nsb); 527 extern uint64_t netstat_get(struct netstat *ns, 528 const char *name, bool *not_found); 529 530 static inline uint64_t netstat_get_one(const char *name, bool *not_found) 531 { 532 struct netstat *ns = netstat_read(); 533 uint64_t ret; 534 535 ret = netstat_get(ns, name, not_found); 536 537 netstat_free(ns); 538 return ret; 539 } 540 541 struct tcp_sock_queue { 542 uint32_t seq; 543 void *buf; 544 }; 545 546 struct tcp_sock_state { 547 struct tcp_info info; 548 struct tcp_repair_window trw; 549 struct tcp_sock_queue out; 550 int outq_len; /* output queue size (not sent + not acked) */ 551 int outq_nsd_len; /* output queue size (not sent only) */ 552 struct tcp_sock_queue in; 553 int inq_len; 554 int mss; 555 int timestamp; 556 }; 557 558 extern void __test_sock_checkpoint(int sk, struct tcp_sock_state *state, 559 void *addr, size_t addr_size); 560 static inline void test_sock_checkpoint(int sk, struct tcp_sock_state *state, 561 sockaddr_af *saddr) 562 { 563 __test_sock_checkpoint(sk, state, saddr, sizeof(*saddr)); 564 } 565 extern void test_ao_checkpoint(int sk, struct tcp_ao_repair *state); 566 extern void __test_sock_restore(int sk, const char *device, 567 struct tcp_sock_state *state, 568 void *saddr, void *daddr, size_t addr_size); 569 static inline void test_sock_restore(int sk, struct tcp_sock_state *state, 570 sockaddr_af *saddr, 571 const union tcp_addr daddr, 572 unsigned int dport) 573 { 574 sockaddr_af addr; 575 576 tcp_addr_to_sockaddr_in(&addr, &daddr, htons(dport)); 577 __test_sock_restore(sk, veth_name, state, saddr, &addr, sizeof(addr)); 578 } 579 extern void test_ao_restore(int sk, struct tcp_ao_repair *state); 580 extern void test_sock_state_free(struct tcp_sock_state *state); 581 extern void test_enable_repair(int sk); 582 extern void test_disable_repair(int sk); 583 extern void test_kill_sk(int sk); 584 static inline int test_add_repaired_key(int sk, 585 const char *key, uint8_t keyflags, 586 union tcp_addr in_addr, uint8_t prefix, 587 uint8_t sndid, uint8_t rcvid) 588 { 589 struct tcp_ao_add tmp = {}; 590 int err; 591 592 err = test_prepare_def_key(&tmp, key, keyflags, in_addr, prefix, 593 0, sndid, rcvid); 594 if (err) 595 return err; 596 597 tmp.set_current = 1; 598 tmp.set_rnext = 1; 599 if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0) 600 return -errno; 601 602 return test_verify_socket_key(sk, &tmp); 603 } 604 605 #endif /* _AOLIB_H_ */ 606