4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/stream.h>
28 #define _SUN_TPI_VERSION 2
29 #include <sys/tihdr.h>
30 #include <sys/socket.h>
31 #include <sys/xti_xtiopt.h>
32 #include <sys/xti_inet.h>
33 #include <sys/policy.h>
34
35 #include <inet/common.h>
36 #include <netinet/ip6.h>
37 #include <inet/ip.h>
38
39 #include <netinet/in.h>
40 #include <netinet/tcp.h>
41 #include <inet/optcom.h>
42 #include <inet/proto_set.h>
43 #include <inet/tcp_impl.h>
46
47 /*
48 * Table of all known options handled on a TCP protocol stack.
49 *
50 * Note: This table contains options processed by both TCP and IP levels
51 * and is the superset of options that can be performed on a TCP over IP
52 * stack.
53 */
54 opdes_t tcp_opt_arr[] = {
55
56 { SO_LINGER, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
57 sizeof (struct linger), 0 },
58
59 { SO_DEBUG, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
60 { SO_KEEPALIVE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
61 { SO_DONTROUTE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62 { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
63 },
64 { SO_BROADCAST, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
65 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
66 { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
67 { SO_TYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
68 { SO_SNDBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
69 { SO_RCVBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
70 { SO_SNDTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
71 sizeof (struct timeval), 0 },
72 { SO_RCVTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
73 sizeof (struct timeval), 0 },
74 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
75 },
76 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
77 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
78 0 },
79 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
80 0 },
81 { SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
82 0 },
83 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
84 0 },
85 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
467 * that are using IPv6 on the wire.
468 */
469 if (connp->conn_ipversion != IPV6_VERSION) {
470 return (-1);
471 }
472 switch (name) {
473 case IPV6_PATHMTU:
474 if (tcp->tcp_state < TCPS_ESTABLISHED)
475 return (-1);
476 break;
477 }
478 break;
479 }
480 mutex_enter(&connp->conn_lock);
481 retval = conn_opt_get(&coas, level, name, ptr);
482 mutex_exit(&connp->conn_lock);
483 return (retval);
484 }
485
486 /*
487 * We declare as 'int' rather than 'void' to satisfy pfi_t arg requirements.
488 * Parameters are assumed to be verified by the caller.
489 */
490 /* ARGSUSED */
491 int
492 tcp_opt_set(conn_t *connp, uint_t optset_context, int level, int name,
493 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
494 void *thisdg_attrs, cred_t *cr)
495 {
496 tcp_t *tcp = connp->conn_tcp;
497 int *i1 = (int *)invalp;
498 boolean_t onoff = (*i1 == 0) ? 0 : 1;
499 boolean_t checkonly;
500 int reterr;
501 tcp_stack_t *tcps = tcp->tcp_tcps;
502 conn_opt_arg_t coas;
503 uint32_t val = *((uint32_t *)invalp);
504
505 coas.coa_connp = connp;
506 coas.coa_ixa = connp->conn_ixa;
636 *i1 = MSS_ROUNDUP(*i1, tcp->tcp_mss);
637 (void) tcp_rwnd_set(tcp, *i1);
638 }
639 /*
640 * XXX should we return the rwnd here
641 * and tcp_opt_get ?
642 */
643 *outlenp = inlen;
644 return (0);
645 case SO_SND_COPYAVOID:
646 if (!checkonly) {
647 if (tcp->tcp_loopback ||
648 (onoff != 1) || !tcp_zcopy_check(tcp)) {
649 *outlenp = 0;
650 return (EOPNOTSUPP);
651 }
652 tcp->tcp_snd_zcopy_aware = 1;
653 }
654 *outlenp = inlen;
655 return (0);
656 }
657 break;
658 case IPPROTO_TCP:
659 switch (name) {
660 case TCP_NODELAY:
661 if (!checkonly)
662 tcp->tcp_naglim = *i1 ? 1 : tcp->tcp_mss;
663 break;
664 case TCP_NOTIFY_THRESHOLD:
665 if (!checkonly)
666 tcp->tcp_first_timer_threshold = *i1;
667 break;
668 case TCP_ABORT_THRESHOLD:
669 if (!checkonly)
670 tcp->tcp_second_timer_threshold = *i1;
671 break;
672 case TCP_CONN_NOTIFY_THRESHOLD:
673 if (!checkonly)
674 tcp->tcp_first_ctimer_threshold = *i1;
675 break;
676 case TCP_CONN_ABORT_THRESHOLD:
752 tcp->tcp_ka_tid = TCP_TIMER(tcp,
753 tcp_keepalive_timer,
754 tcp->tcp_ka_interval);
755 }
756 }
757 break;
758
759 /*
760 * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt.
761 * So setting TCP_KEEPCNT or TCP_KEEPINTVL can affect all the
762 * three members - tcp_ka_abort_thres, tcp_ka_rinterval and
763 * tcp_ka_cnt.
764 */
765 case TCP_KEEPCNT:
766 if (checkonly)
767 break;
768
769 if (*i1 == 0) {
770 return (EINVAL);
771 } else if (tcp->tcp_ka_rinterval == 0) {
772 if ((tcp->tcp_ka_abort_thres / *i1) <
773 tcp->tcp_rto_min ||
774 (tcp->tcp_ka_abort_thres / *i1) >
775 tcp->tcp_rto_max)
776 return (EINVAL);
777
778 tcp->tcp_ka_rinterval =
779 tcp->tcp_ka_abort_thres / *i1;
780 } else {
781 if ((*i1 * tcp->tcp_ka_rinterval) <
782 tcps->tcps_keepalive_abort_interval_low ||
783 (*i1 * tcp->tcp_ka_rinterval) >
784 tcps->tcps_keepalive_abort_interval_high)
785 return (EINVAL);
786 tcp->tcp_ka_abort_thres =
787 (*i1 * tcp->tcp_ka_rinterval);
788 }
789 tcp->tcp_ka_cnt = *i1;
790 break;
791 case TCP_KEEPINTVL:
792 /*
793 * TCP_KEEPINTVL is specified in seconds, but
794 * tcp_ka_rinterval is in milliseconds.
795 */
796
797 if (checkonly)
798 break;
799
936 * parameter. It should be smaller than the current
937 * value to avoid an app setting TCP_LINGER2 to a big
938 * value, causing resource to be held up too long in
939 * FIN-WAIT-2 state.
940 */
941 if (*i1 < 0 ||
942 tcps->tcps_fin_wait_2_flush_interval_low/SECONDS >
943 *i1 ||
944 tcps->tcps_fin_wait_2_flush_interval/SECONDS <
945 *i1) {
946 *outlenp = 0;
947 return (EINVAL);
948 }
949 tcp->tcp_fin_wait_2_flush_interval = *i1 * SECONDS;
950 break;
951 default:
952 break;
953 }
954 break;
955 case IPPROTO_IP:
956 if (connp->conn_family != AF_INET) {
957 *outlenp = 0;
958 return (EINVAL);
959 }
960 switch (name) {
961 case IP_SEC_OPT:
962 /*
963 * We should not allow policy setting after
964 * we start listening for connections.
965 */
966 if (tcp->tcp_state == TCPS_LISTEN) {
967 return (EINVAL);
968 }
969 break;
970 }
971 break;
972 case IPPROTO_IPV6:
973 /*
974 * IPPROTO_IPV6 options are only supported for sockets
975 * that are using IPv6 on the wire.
976 */
977 if (connp->conn_ipversion != IPV6_VERSION) {
978 *outlenp = 0;
979 return (EINVAL);
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2016 Joyent, Inc.
25 */
26
27 #include <sys/types.h>
28 #include <sys/stream.h>
29 #define _SUN_TPI_VERSION 2
30 #include <sys/tihdr.h>
31 #include <sys/socket.h>
32 #include <sys/xti_xtiopt.h>
33 #include <sys/xti_inet.h>
34 #include <sys/policy.h>
35
36 #include <inet/common.h>
37 #include <netinet/ip6.h>
38 #include <inet/ip.h>
39
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <inet/optcom.h>
43 #include <inet/proto_set.h>
44 #include <inet/tcp_impl.h>
47
48 /*
49 * Table of all known options handled on a TCP protocol stack.
50 *
51 * Note: This table contains options processed by both TCP and IP levels
52 * and is the superset of options that can be performed on a TCP over IP
53 * stack.
54 */
55 opdes_t tcp_opt_arr[] = {
56
57 { SO_LINGER, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
58 sizeof (struct linger), 0 },
59
60 { SO_DEBUG, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
61 { SO_KEEPALIVE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
62 { SO_DONTROUTE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
63 { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
64 },
65 { SO_BROADCAST, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
66 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
67 { SO_REUSEPORT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
68 { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
69 { SO_TYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
70 { SO_SNDBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
71 { SO_RCVBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
72 { SO_SNDTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
73 sizeof (struct timeval), 0 },
74 { SO_RCVTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0,
75 sizeof (struct timeval), 0 },
76 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
77 },
78 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
79 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
80 0 },
81 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
82 0 },
83 { SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
84 0 },
85 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
86 0 },
87 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
469 * that are using IPv6 on the wire.
470 */
471 if (connp->conn_ipversion != IPV6_VERSION) {
472 return (-1);
473 }
474 switch (name) {
475 case IPV6_PATHMTU:
476 if (tcp->tcp_state < TCPS_ESTABLISHED)
477 return (-1);
478 break;
479 }
480 break;
481 }
482 mutex_enter(&connp->conn_lock);
483 retval = conn_opt_get(&coas, level, name, ptr);
484 mutex_exit(&connp->conn_lock);
485 return (retval);
486 }
487
488 /*
489 * Set a TCP connection's participation in SO_REUSEPORT. This operation is
490 * performed under the protection of the squeue via tcp_setsockopt.
491 * The manipulation of tcp_rg_bind, as part of this operation, is subject to
492 * these constraints:
493 * 1. Prior to bind(), tcp_rg_bind can be set/cleared in tcp_set_reuseport
494 * under the protection of the squeue.
495 * 2. Once the connection has been bound, the tcp_rg_bind pointer must not be
496 * altered until such time as tcp_free() cleans up the connection.
497 * 3. A connection undergoing bind, which matches to a connection participating
498 * in port-reuse, will switch its tcp_rg_bind pointer when it joins the
499 * group of an existing connection in tcp_bindi().
500 */
501 static int
502 tcp_set_reuseport(conn_t *connp, boolean_t do_enable)
503 {
504 tcp_t *tcp = connp->conn_tcp;
505 struct tcp_rg_s *rg;
506
507 if (!IPCL_IS_NONSTR(connp)) {
508 if (do_enable) {
509 /*
510 * SO_REUSEPORT cannot be enabled on sockets which have
511 * fallen back to the STREAMS API.
512 */
513 return (EINVAL);
514 } else {
515 /*
516 * A connection with SO_REUSEPORT enabled should be
517 * prevented from falling back to STREAMS mode via
518 * logic in tcp_fallback. It is legal, however, for
519 * fallen-back connections to affirm the disabled state
520 * of SO_REUSEPORT.
521 */
522 ASSERT(connp->conn_reuseport == 0);
523 return (0);
524 }
525 }
526 if (tcp->tcp_state <= TCPS_CLOSED) {
527 return (EINVAL);
528 }
529 if (connp->conn_reuseport == 0 && do_enable) {
530 /* disabled -> enabled */
531 if (tcp->tcp_rg_bind != NULL) {
532 tcp_rg_setactive(tcp->tcp_rg_bind, do_enable);
533 } else {
534 /*
535 * Connection state is not a concern when initially
536 * populating tcp_rg_bind. Setting it to non-NULL on a
537 * bound or listening connection would only mean that
538 * new reused-port binds become a possibility.
539 */
540 if ((rg = tcp_rg_init(tcp)) == NULL) {
541 return (ENOMEM);
542 }
543 tcp->tcp_rg_bind = rg;
544 }
545 connp->conn_reuseport = 1;
546 } else if (connp->conn_reuseport != 0 && !do_enable) {
547 /* enabled -> disabled */
548 ASSERT(tcp->tcp_rg_bind != NULL);
549 if (tcp->tcp_state == TCPS_IDLE) {
550 /*
551 * If the connection has not been bound yet, discard
552 * the reuse group state. Since disabling SO_REUSEPORT
553 * on a bound socket will _not_ prevent others from
554 * reusing the port, the presence of tcp_rg_bind is
555 * used to determine reuse availability, not
556 * conn_reuseport.
557 *
558 * This allows proper behavior for examples such as:
559 *
560 * setsockopt(fd1, ... SO_REUSEPORT, &on_val...);
561 * bind(fd1, &myaddr, ...);
562 * setsockopt(fd1, ... SO_REUSEPORT, &off_val...);
563 *
564 * setsockopt(fd2, ... SO_REUSEPORT, &on_val...);
565 * bind(fd2, &myaddr, ...); // <- SHOULD SUCCEED
566 *
567 */
568 rg = tcp->tcp_rg_bind;
569 tcp->tcp_rg_bind = NULL;
570 VERIFY(tcp_rg_remove(rg, tcp));
571 tcp_rg_destroy(rg);
572 } else {
573 /*
574 * If a connection has been bound, it's no longer safe
575 * to manipulate tcp_rg_bind until connection clean-up
576 * during tcp_free. Just mark the member status of the
577 * connection as inactive.
578 */
579 tcp_rg_setactive(tcp->tcp_rg_bind, do_enable);
580 }
581 connp->conn_reuseport = 0;
582 }
583 return (0);
584 }
585
586 /*
587 * We declare as 'int' rather than 'void' to satisfy pfi_t arg requirements.
588 * Parameters are assumed to be verified by the caller.
589 */
590 /* ARGSUSED */
591 int
592 tcp_opt_set(conn_t *connp, uint_t optset_context, int level, int name,
593 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
594 void *thisdg_attrs, cred_t *cr)
595 {
596 tcp_t *tcp = connp->conn_tcp;
597 int *i1 = (int *)invalp;
598 boolean_t onoff = (*i1 == 0) ? 0 : 1;
599 boolean_t checkonly;
600 int reterr;
601 tcp_stack_t *tcps = tcp->tcp_tcps;
602 conn_opt_arg_t coas;
603 uint32_t val = *((uint32_t *)invalp);
604
605 coas.coa_connp = connp;
606 coas.coa_ixa = connp->conn_ixa;
736 *i1 = MSS_ROUNDUP(*i1, tcp->tcp_mss);
737 (void) tcp_rwnd_set(tcp, *i1);
738 }
739 /*
740 * XXX should we return the rwnd here
741 * and tcp_opt_get ?
742 */
743 *outlenp = inlen;
744 return (0);
745 case SO_SND_COPYAVOID:
746 if (!checkonly) {
747 if (tcp->tcp_loopback ||
748 (onoff != 1) || !tcp_zcopy_check(tcp)) {
749 *outlenp = 0;
750 return (EOPNOTSUPP);
751 }
752 tcp->tcp_snd_zcopy_aware = 1;
753 }
754 *outlenp = inlen;
755 return (0);
756 case SO_REUSEPORT:
757 if (!checkonly) {
758 return (tcp_set_reuseport(connp, *i1 != 0));
759 }
760 return (0);
761 }
762 break;
763 case IPPROTO_TCP:
764 switch (name) {
765 case TCP_NODELAY:
766 if (!checkonly)
767 tcp->tcp_naglim = *i1 ? 1 : tcp->tcp_mss;
768 break;
769 case TCP_NOTIFY_THRESHOLD:
770 if (!checkonly)
771 tcp->tcp_first_timer_threshold = *i1;
772 break;
773 case TCP_ABORT_THRESHOLD:
774 if (!checkonly)
775 tcp->tcp_second_timer_threshold = *i1;
776 break;
777 case TCP_CONN_NOTIFY_THRESHOLD:
778 if (!checkonly)
779 tcp->tcp_first_ctimer_threshold = *i1;
780 break;
781 case TCP_CONN_ABORT_THRESHOLD:
857 tcp->tcp_ka_tid = TCP_TIMER(tcp,
858 tcp_keepalive_timer,
859 tcp->tcp_ka_interval);
860 }
861 }
862 break;
863
864 /*
865 * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt.
866 * So setting TCP_KEEPCNT or TCP_KEEPINTVL can affect all the
867 * three members - tcp_ka_abort_thres, tcp_ka_rinterval and
868 * tcp_ka_cnt.
869 */
870 case TCP_KEEPCNT:
871 if (checkonly)
872 break;
873
874 if (*i1 == 0) {
875 return (EINVAL);
876 } else if (tcp->tcp_ka_rinterval == 0) {
877 /*
878 * When TCP_KEEPCNT is specified without first
879 * specifying a TCP_KEEPINTVL, we infer an
880 * interval based on a tunable specific to our
881 * stack: the tcp_keepalive_abort_interval.
882 * (Or the TCP_KEEPALIVE_ABORT_THRESHOLD, in
883 * the unlikely event that that has been set.)
884 * Given the abort interval's default value of
885 * 480 seconds, low TCP_KEEPCNT values can
886 * result in intervals that exceed the default
887 * maximum RTO of 60 seconds. Rather than
888 * fail in these cases, we (implicitly) clamp
889 * the interval at the maximum RTO; if the
890 * TCP_KEEPCNT is shortly followed by a
891 * TCP_KEEPINTVL (as we expect), the abort
892 * threshold will be recalculated correctly --
893 * and if a TCP_KEEPINTVL is not forthcoming,
894 * keep-alive will at least operate reasonably
895 * given the underconfigured state.
896 */
897 uint32_t interval;
898
899 interval = tcp->tcp_ka_abort_thres / *i1;
900
901 if (interval < tcp->tcp_rto_min)
902 interval = tcp->tcp_rto_min;
903
904 if (interval > tcp->tcp_rto_max)
905 interval = tcp->tcp_rto_max;
906
907 tcp->tcp_ka_rinterval = interval;
908 } else {
909 if ((*i1 * tcp->tcp_ka_rinterval) <
910 tcps->tcps_keepalive_abort_interval_low ||
911 (*i1 * tcp->tcp_ka_rinterval) >
912 tcps->tcps_keepalive_abort_interval_high)
913 return (EINVAL);
914 tcp->tcp_ka_abort_thres =
915 (*i1 * tcp->tcp_ka_rinterval);
916 }
917 tcp->tcp_ka_cnt = *i1;
918 break;
919 case TCP_KEEPINTVL:
920 /*
921 * TCP_KEEPINTVL is specified in seconds, but
922 * tcp_ka_rinterval is in milliseconds.
923 */
924
925 if (checkonly)
926 break;
927
1064 * parameter. It should be smaller than the current
1065 * value to avoid an app setting TCP_LINGER2 to a big
1066 * value, causing resource to be held up too long in
1067 * FIN-WAIT-2 state.
1068 */
1069 if (*i1 < 0 ||
1070 tcps->tcps_fin_wait_2_flush_interval_low/SECONDS >
1071 *i1 ||
1072 tcps->tcps_fin_wait_2_flush_interval/SECONDS <
1073 *i1) {
1074 *outlenp = 0;
1075 return (EINVAL);
1076 }
1077 tcp->tcp_fin_wait_2_flush_interval = *i1 * SECONDS;
1078 break;
1079 default:
1080 break;
1081 }
1082 break;
1083 case IPPROTO_IP:
1084 switch (name) {
1085 case IP_SEC_OPT:
1086 /*
1087 * We should not allow policy setting after
1088 * we start listening for connections.
1089 */
1090 if (tcp->tcp_state == TCPS_LISTEN) {
1091 return (EINVAL);
1092 }
1093 break;
1094 }
1095 break;
1096 case IPPROTO_IPV6:
1097 /*
1098 * IPPROTO_IPV6 options are only supported for sockets
1099 * that are using IPv6 on the wire.
1100 */
1101 if (connp->conn_ipversion != IPV6_VERSION) {
1102 *outlenp = 0;
1103 return (EINVAL);
|