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);
 
 |