1 /*
   2  * CDDL HEADER START
   3  *
   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>
  44 
  45 static int      tcp_opt_default(queue_t *, int, int, uchar_t *);
  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 },
  86 
  87 { SO_DOMAIN,    SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
  88 
  89 { SO_PROTOTYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
  90 
  91 { TCP_NODELAY,  IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
  92         },
  93 { TCP_MAXSEG,   IPPROTO_TCP, OA_R, OA_R, OP_NP, 0, sizeof (uint_t),
  94         536 },
  95 
  96 { TCP_NOTIFY_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP,
  97         OP_DEF_FN, sizeof (int), -1 /* not initialized */ },
  98 
  99 { TCP_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP,
 100         OP_DEF_FN, sizeof (int), -1 /* not initialized */ },
 101 
 102 { TCP_CONN_NOTIFY_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP,
 103         OP_DEF_FN, sizeof (int), -1 /* not initialized */ },
 104 
 105 { TCP_CONN_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP,
 106         OP_DEF_FN, sizeof (int), -1 /* not initialized */ },
 107 
 108 { TCP_RECVDSTADDR, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int),
 109         0 },
 110 
 111 { TCP_ANONPRIVBIND, IPPROTO_TCP, OA_R, OA_RW, OP_PRIVPORT, 0,
 112         sizeof (int), 0 },
 113 
 114 { TCP_EXCLBIND, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
 115         },
 116 
 117 { TCP_INIT_CWND, IPPROTO_TCP, OA_RW, OA_RW, OP_CONFIG, 0,
 118         sizeof (int), 0 },
 119 
 120 { TCP_KEEPALIVE_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0,
 121         sizeof (int), 0 },
 122 
 123 { TCP_KEEPIDLE, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 124 
 125 { TCP_KEEPCNT, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 126 
 127 { TCP_KEEPINTVL, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 128 
 129 { TCP_KEEPALIVE_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0,
 130         sizeof (int), 0 },
 131 
 132 { TCP_CORK, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 133 
 134 { TCP_RTO_INITIAL, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 },
 135 
 136 { TCP_RTO_MIN, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 },
 137 
 138 { TCP_RTO_MAX, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 },
 139 
 140 { TCP_LINGER2, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 141 
 142 { IP_OPTIONS,   IPPROTO_IP, OA_RW, OA_RW, OP_NP,
 143         (OP_VARLEN|OP_NODEFAULT),
 144         IP_MAX_OPT_LENGTH + IP_ADDR_LEN, -1 /* not initialized */ },
 145 { T_IP_OPTIONS, IPPROTO_IP, OA_RW, OA_RW, OP_NP,
 146         (OP_VARLEN|OP_NODEFAULT),
 147         IP_MAX_OPT_LENGTH + IP_ADDR_LEN, -1 /* not initialized */ },
 148 
 149 { IP_TOS,       IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 150 { T_IP_TOS,     IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 151 { IP_TTL,       IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
 152         sizeof (int), -1 /* not initialized */ },
 153 
 154 { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
 155         sizeof (ipsec_req_t), -1 /* not initialized */ },
 156 
 157 { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
 158         sizeof (int),   0 /* no ifindex */ },
 159 
 160 { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
 161         sizeof (int), 0 },
 162 
 163 { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
 164         sizeof (int), -1 /* not initialized */ },
 165 
 166 { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 167         sizeof (int),   0 /* no ifindex */ },
 168 
 169 { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 170 
 171 { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
 172         sizeof (in_addr_t),     -1 /* not initialized  */ },
 173 
 174 { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0,
 175         sizeof (int), 0 },
 176 
 177 { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 178         (OP_NODEFAULT|OP_VARLEN),
 179         sizeof (struct in6_pktinfo), -1 /* not initialized */ },
 180 { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 181         OP_NODEFAULT,
 182         sizeof (sin6_t), -1 /* not initialized */ },
 183 { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 184         (OP_VARLEN|OP_NODEFAULT), 255*8,
 185         -1 /* not initialized */ },
 186 { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 187         (OP_VARLEN|OP_NODEFAULT), 255*8,
 188         -1 /* not initialized */ },
 189 { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 190         (OP_VARLEN|OP_NODEFAULT), 255*8,
 191         -1 /* not initialized */ },
 192 { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 193         (OP_VARLEN|OP_NODEFAULT), 255*8,
 194         -1 /* not initialized */ },
 195 { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 196         OP_NODEFAULT,
 197         sizeof (int), -1 /* not initialized */ },
 198 { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP,
 199         OP_NODEFAULT,
 200         sizeof (struct ip6_mtuinfo), -1 /* not initialized */ },
 201 { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 202         sizeof (int), 0 },
 203 { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 204         sizeof (int), 0 },
 205 { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 206         sizeof (int), 0 },
 207 
 208 /* Enable receipt of ancillary data */
 209 { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 210         sizeof (int), 0 },
 211 { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 212         sizeof (int), 0 },
 213 { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 214         sizeof (int), 0 },
 215 { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 216         sizeof (int), 0 },
 217 { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 218         sizeof (int), 0 },
 219 { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 220         sizeof (int), 0 },
 221 { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 222         sizeof (int), 0 },
 223 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 224         sizeof (int), 0 },
 225 
 226 { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
 227         sizeof (ipsec_req_t), -1 /* not initialized */ },
 228 { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0,
 229         sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
 230 };
 231 
 232 /*
 233  * Table of all supported levels
 234  * Note: Some levels (e.g. XTI_GENERIC) may be valid but may not have
 235  * any supported options so we need this info separately.
 236  *
 237  * This is needed only for topmost tpi providers and is used only by
 238  * XTI interfaces.
 239  */
 240 optlevel_t      tcp_valid_levels_arr[] = {
 241         XTI_GENERIC,
 242         SOL_SOCKET,
 243         IPPROTO_TCP,
 244         IPPROTO_IP,
 245         IPPROTO_IPV6
 246 };
 247 
 248 
 249 #define TCP_OPT_ARR_CNT         A_CNT(tcp_opt_arr)
 250 #define TCP_VALID_LEVELS_CNT    A_CNT(tcp_valid_levels_arr)
 251 
 252 uint_t tcp_max_optsize; /* initialized when TCP driver is loaded */
 253 
 254 /*
 255  * Initialize option database object for TCP
 256  *
 257  * This object represents database of options to search passed to
 258  * {sock,tpi}optcom_req() interface routine to take care of option
 259  * management and associated methods.
 260  */
 261 
 262 optdb_obj_t tcp_opt_obj = {
 263         tcp_opt_default,        /* TCP default value function pointer */
 264         tcp_tpi_opt_get,        /* TCP get function pointer */
 265         tcp_tpi_opt_set,        /* TCP set function pointer */
 266         TCP_OPT_ARR_CNT,        /* TCP option database count of entries */
 267         tcp_opt_arr,            /* TCP option database */
 268         TCP_VALID_LEVELS_CNT,   /* TCP valid level count of entries */
 269         tcp_valid_levels_arr    /* TCP valid level array */
 270 };
 271 
 272 static int tcp_max_init_cwnd = TCP_MAX_INIT_CWND;
 273 
 274 /*
 275  * Some TCP options can be "set" by requesting them in the option
 276  * buffer. This is needed for XTI feature test though we do not
 277  * allow it in general. We interpret that this mechanism is more
 278  * applicable to OSI protocols and need not be allowed in general.
 279  * This routine filters out options for which it is not allowed (most)
 280  * and lets through those (few) for which it is. [ The XTI interface
 281  * test suite specifics will imply that any XTI_GENERIC level XTI_* if
 282  * ever implemented will have to be allowed here ].
 283  */
 284 static boolean_t
 285 tcp_allow_connopt_set(int level, int name)
 286 {
 287 
 288         switch (level) {
 289         case IPPROTO_TCP:
 290                 switch (name) {
 291                 case TCP_NODELAY:
 292                         return (B_TRUE);
 293                 default:
 294                         return (B_FALSE);
 295                 }
 296                 /*NOTREACHED*/
 297         default:
 298                 return (B_FALSE);
 299         }
 300         /*NOTREACHED*/
 301 }
 302 
 303 /*
 304  * This routine gets default values of certain options whose default
 305  * values are maintained by protocol specific code
 306  */
 307 /* ARGSUSED */
 308 static int
 309 tcp_opt_default(queue_t *q, int level, int name, uchar_t *ptr)
 310 {
 311         int32_t *i1 = (int32_t *)ptr;
 312         tcp_stack_t     *tcps = Q_TO_TCP(q)->tcp_tcps;
 313 
 314         switch (level) {
 315         case IPPROTO_TCP:
 316                 switch (name) {
 317                 case TCP_NOTIFY_THRESHOLD:
 318                         *i1 = tcps->tcps_ip_notify_interval;
 319                         break;
 320                 case TCP_ABORT_THRESHOLD:
 321                         *i1 = tcps->tcps_ip_abort_interval;
 322                         break;
 323                 case TCP_CONN_NOTIFY_THRESHOLD:
 324                         *i1 = tcps->tcps_ip_notify_cinterval;
 325                         break;
 326                 case TCP_CONN_ABORT_THRESHOLD:
 327                         *i1 = tcps->tcps_ip_abort_cinterval;
 328                         break;
 329                 default:
 330                         return (-1);
 331                 }
 332                 break;
 333         case IPPROTO_IP:
 334                 switch (name) {
 335                 case IP_TTL:
 336                         *i1 = tcps->tcps_ipv4_ttl;
 337                         break;
 338                 default:
 339                         return (-1);
 340                 }
 341                 break;
 342         case IPPROTO_IPV6:
 343                 switch (name) {
 344                 case IPV6_UNICAST_HOPS:
 345                         *i1 = tcps->tcps_ipv6_hoplimit;
 346                         break;
 347                 default:
 348                         return (-1);
 349                 }
 350                 break;
 351         default:
 352                 return (-1);
 353         }
 354         return (sizeof (int));
 355 }
 356 
 357 /*
 358  * TCP routine to get the values of options.
 359  */
 360 int
 361 tcp_opt_get(conn_t *connp, int level, int name, uchar_t *ptr)
 362 {
 363         int             *i1 = (int *)ptr;
 364         tcp_t           *tcp = connp->conn_tcp;
 365         conn_opt_arg_t  coas;
 366         int             retval;
 367 
 368         coas.coa_connp = connp;
 369         coas.coa_ixa = connp->conn_ixa;
 370         coas.coa_ipp = &connp->conn_xmit_ipp;
 371         coas.coa_ancillary = B_FALSE;
 372         coas.coa_changed = 0;
 373 
 374         switch (level) {
 375         case SOL_SOCKET:
 376                 switch (name) {
 377                 case SO_SND_COPYAVOID:
 378                         *i1 = tcp->tcp_snd_zcopy_on ?
 379                             SO_SND_COPYAVOID : 0;
 380                         return (sizeof (int));
 381                 case SO_ACCEPTCONN:
 382                         *i1 = (tcp->tcp_state == TCPS_LISTEN);
 383                         return (sizeof (int));
 384                 }
 385                 break;
 386         case IPPROTO_TCP:
 387                 switch (name) {
 388                 case TCP_NODELAY:
 389                         *i1 = (tcp->tcp_naglim == 1) ? TCP_NODELAY : 0;
 390                         return (sizeof (int));
 391                 case TCP_MAXSEG:
 392                         *i1 = tcp->tcp_mss;
 393                         return (sizeof (int));
 394                 case TCP_NOTIFY_THRESHOLD:
 395                         *i1 = (int)tcp->tcp_first_timer_threshold;
 396                         return (sizeof (int));
 397                 case TCP_ABORT_THRESHOLD:
 398                         *i1 = tcp->tcp_second_timer_threshold;
 399                         return (sizeof (int));
 400                 case TCP_CONN_NOTIFY_THRESHOLD:
 401                         *i1 = tcp->tcp_first_ctimer_threshold;
 402                         return (sizeof (int));
 403                 case TCP_CONN_ABORT_THRESHOLD:
 404                         *i1 = tcp->tcp_second_ctimer_threshold;
 405                         return (sizeof (int));
 406                 case TCP_INIT_CWND:
 407                         *i1 = tcp->tcp_init_cwnd;
 408                         return (sizeof (int));
 409                 case TCP_KEEPALIVE_THRESHOLD:
 410                         *i1 = tcp->tcp_ka_interval;
 411                         return (sizeof (int));
 412 
 413                 /*
 414                  * TCP_KEEPIDLE expects value in seconds, but
 415                  * tcp_ka_interval is in milliseconds.
 416                  */
 417                 case TCP_KEEPIDLE:
 418                         *i1 = tcp->tcp_ka_interval / 1000;
 419                         return (sizeof (int));
 420                 case TCP_KEEPCNT:
 421                         *i1 = tcp->tcp_ka_cnt;
 422                         return (sizeof (int));
 423 
 424                 /*
 425                  * TCP_KEEPINTVL expects value in seconds, but
 426                  * tcp_ka_rinterval is in milliseconds.
 427                  */
 428                 case TCP_KEEPINTVL:
 429                         *i1 = tcp->tcp_ka_rinterval / 1000;
 430                         return (sizeof (int));
 431                 case TCP_KEEPALIVE_ABORT_THRESHOLD:
 432                         *i1 = tcp->tcp_ka_abort_thres;
 433                         return (sizeof (int));
 434                 case TCP_CORK:
 435                         *i1 = tcp->tcp_cork;
 436                         return (sizeof (int));
 437                 case TCP_RTO_INITIAL:
 438                         *i1 = tcp->tcp_rto_initial;
 439                         return (sizeof (uint32_t));
 440                 case TCP_RTO_MIN:
 441                         *i1 = tcp->tcp_rto_min;
 442                         return (sizeof (uint32_t));
 443                 case TCP_RTO_MAX:
 444                         *i1 = tcp->tcp_rto_max;
 445                         return (sizeof (uint32_t));
 446                 case TCP_LINGER2:
 447                         *i1 = tcp->tcp_fin_wait_2_flush_interval / SECONDS;
 448                         return (sizeof (int));
 449                 }
 450                 break;
 451         case IPPROTO_IP:
 452                 if (connp->conn_family != AF_INET)
 453                         return (-1);
 454                 switch (name) {
 455                 case IP_OPTIONS:
 456                 case T_IP_OPTIONS:
 457                         /* Caller ensures enough space */
 458                         return (ip_opt_get_user(connp, ptr));
 459                 default:
 460                         break;
 461                 }
 462                 break;
 463 
 464         case IPPROTO_IPV6:
 465                 /*
 466                  * IPPROTO_IPV6 options are only supported for sockets
 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;
 507         coas.coa_ipp = &connp->conn_xmit_ipp;
 508         coas.coa_ancillary = B_FALSE;
 509         coas.coa_changed = 0;
 510 
 511         switch (optset_context) {
 512         case SETFN_OPTCOM_CHECKONLY:
 513                 checkonly = B_TRUE;
 514                 /*
 515                  * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
 516                  * inlen != 0 implies value supplied and
 517                  *      we have to "pretend" to set it.
 518                  * inlen == 0 implies that there is no
 519                  *      value part in T_CHECK request and just validation
 520                  * done elsewhere should be enough, we just return here.
 521                  */
 522                 if (inlen == 0) {
 523                         *outlenp = 0;
 524                         return (0);
 525                 }
 526                 break;
 527         case SETFN_OPTCOM_NEGOTIATE:
 528                 checkonly = B_FALSE;
 529                 break;
 530         case SETFN_UD_NEGOTIATE: /* error on conn-oriented transports ? */
 531         case SETFN_CONN_NEGOTIATE:
 532                 checkonly = B_FALSE;
 533                 /*
 534                  * Negotiating local and "association-related" options
 535                  * from other (T_CONN_REQ, T_CONN_RES,T_UNITDATA_REQ)
 536                  * primitives is allowed by XTI, but we choose
 537                  * to not implement this style negotiation for Internet
 538                  * protocols (We interpret it is a must for OSI world but
 539                  * optional for Internet protocols) for all options.
 540                  * [ Will do only for the few options that enable test
 541                  * suites that our XTI implementation of this feature
 542                  * works for transports that do allow it ]
 543                  */
 544                 if (!tcp_allow_connopt_set(level, name)) {
 545                         *outlenp = 0;
 546                         return (EINVAL);
 547                 }
 548                 break;
 549         default:
 550                 /*
 551                  * We should never get here
 552                  */
 553                 *outlenp = 0;
 554                 return (EINVAL);
 555         }
 556 
 557         ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) ||
 558             (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0));
 559 
 560         /*
 561          * For TCP, we should have no ancillary data sent down
 562          * (sendmsg isn't supported for SOCK_STREAM), so thisdg_attrs
 563          * has to be zero.
 564          */
 565         ASSERT(thisdg_attrs == NULL);
 566 
 567         /*
 568          * For fixed length options, no sanity check
 569          * of passed in length is done. It is assumed *_optcom_req()
 570          * routines do the right thing.
 571          */
 572         switch (level) {
 573         case SOL_SOCKET:
 574                 switch (name) {
 575                 case SO_KEEPALIVE:
 576                         if (checkonly) {
 577                                 /* check only case */
 578                                 break;
 579                         }
 580 
 581                         if (!onoff) {
 582                                 if (connp->conn_keepalive) {
 583                                         if (tcp->tcp_ka_tid != 0) {
 584                                                 (void) TCP_TIMER_CANCEL(tcp,
 585                                                     tcp->tcp_ka_tid);
 586                                                 tcp->tcp_ka_tid = 0;
 587                                         }
 588                                         connp->conn_keepalive = 0;
 589                                 }
 590                                 break;
 591                         }
 592                         if (!connp->conn_keepalive) {
 593                                 /* Crank up the keepalive timer */
 594                                 tcp->tcp_ka_last_intrvl = 0;
 595                                 tcp->tcp_ka_tid = TCP_TIMER(tcp,
 596                                     tcp_keepalive_timer, tcp->tcp_ka_interval);
 597                                 connp->conn_keepalive = 1;
 598                         }
 599                         break;
 600                 case SO_SNDBUF: {
 601                         if (*i1 > tcps->tcps_max_buf) {
 602                                 *outlenp = 0;
 603                                 return (ENOBUFS);
 604                         }
 605                         if (checkonly)
 606                                 break;
 607 
 608                         connp->conn_sndbuf = *i1;
 609                         if (tcps->tcps_snd_lowat_fraction != 0) {
 610                                 connp->conn_sndlowat = connp->conn_sndbuf /
 611                                     tcps->tcps_snd_lowat_fraction;
 612                         }
 613                         (void) tcp_maxpsz_set(tcp, B_TRUE);
 614                         /*
 615                          * If we are flow-controlled, recheck the condition.
 616                          * There are apps that increase SO_SNDBUF size when
 617                          * flow-controlled (EWOULDBLOCK), and expect the flow
 618                          * control condition to be lifted right away.
 619                          */
 620                         mutex_enter(&tcp->tcp_non_sq_lock);
 621                         if (tcp->tcp_flow_stopped &&
 622                             TCP_UNSENT_BYTES(tcp) < connp->conn_sndbuf) {
 623                                 tcp_clrqfull(tcp);
 624                         }
 625                         mutex_exit(&tcp->tcp_non_sq_lock);
 626                         *outlenp = inlen;
 627                         return (0);
 628                 }
 629                 case SO_RCVBUF:
 630                         if (*i1 > tcps->tcps_max_buf) {
 631                                 *outlenp = 0;
 632                                 return (ENOBUFS);
 633                         }
 634                         /* Silently ignore zero */
 635                         if (!checkonly && *i1 != 0) {
 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:
 677                         if (!checkonly)
 678                                 tcp->tcp_second_ctimer_threshold = *i1;
 679                         break;
 680                 case TCP_RECVDSTADDR:
 681                         if (tcp->tcp_state > TCPS_LISTEN) {
 682                                 *outlenp = 0;
 683                                 return (EOPNOTSUPP);
 684                         }
 685                         /* Setting done in conn_opt_set */
 686                         break;
 687                 case TCP_INIT_CWND:
 688                         if (checkonly)
 689                                 break;
 690 
 691                         /*
 692                          * Only allow socket with network configuration
 693                          * privilege to set the initial cwnd to be larger
 694                          * than allowed by RFC 3390.
 695                          */
 696                         if (val > MIN(4, MAX(2, 4380 / tcp->tcp_mss))) {
 697                                 if ((reterr = secpolicy_ip_config(cr, B_TRUE))
 698                                     != 0) {
 699                                         *outlenp = 0;
 700                                         return (reterr);
 701                                 }
 702                                 if (val > tcp_max_init_cwnd) {
 703                                         *outlenp = 0;
 704                                         return (EINVAL);
 705                                 }
 706                         }
 707 
 708                         tcp->tcp_init_cwnd = val;
 709 
 710                         /*
 711                          * If the socket is connected, AND no outbound data
 712                          * has been sent, reset the actual cwnd values.
 713                          */
 714                         if (tcp->tcp_state == TCPS_ESTABLISHED &&
 715                             tcp->tcp_iss == tcp->tcp_snxt - 1) {
 716                                 tcp->tcp_cwnd =
 717                                     MIN(tcp->tcp_rwnd, val * tcp->tcp_mss);
 718                         }
 719                         break;
 720 
 721                 /*
 722                  * TCP_KEEPIDLE is in seconds but TCP_KEEPALIVE_THRESHOLD
 723                  * is in milliseconds. TCP_KEEPIDLE is introduced for
 724                  * compatibility with other Unix flavors.
 725                  * We can fall through TCP_KEEPALIVE_THRESHOLD logic after
 726                  * converting the input to milliseconds.
 727                  */
 728                 case TCP_KEEPIDLE:
 729                         *i1 *= 1000;
 730                         /* FALLTHRU */
 731 
 732                 case TCP_KEEPALIVE_THRESHOLD:
 733                         if (checkonly)
 734                                 break;
 735 
 736                         if (*i1 < tcps->tcps_keepalive_interval_low ||
 737                             *i1 > tcps->tcps_keepalive_interval_high) {
 738                                 *outlenp = 0;
 739                                 return (EINVAL);
 740                         }
 741                         if (*i1 != tcp->tcp_ka_interval) {
 742                                 tcp->tcp_ka_interval = *i1;
 743                                 /*
 744                                  * Check if we need to restart the
 745                                  * keepalive timer.
 746                                  */
 747                                 if (tcp->tcp_ka_tid != 0) {
 748                                         ASSERT(connp->conn_keepalive);
 749                                         (void) TCP_TIMER_CANCEL(tcp,
 750                                             tcp->tcp_ka_tid);
 751                                         tcp->tcp_ka_last_intrvl = 0;
 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 
 800                         if ((*i1 * 1000) < tcp->tcp_rto_min ||
 801                             (*i1 * 1000) > tcp->tcp_rto_max)
 802                                 return (EINVAL);
 803 
 804                         if (tcp->tcp_ka_cnt == 0) {
 805                                 tcp->tcp_ka_cnt =
 806                                     tcp->tcp_ka_abort_thres / (*i1 * 1000);
 807                         } else {
 808                                 if ((*i1 * tcp->tcp_ka_cnt * 1000) <
 809                                     tcps->tcps_keepalive_abort_interval_low ||
 810                                     (*i1 * tcp->tcp_ka_cnt * 1000) >
 811                                     tcps->tcps_keepalive_abort_interval_high)
 812                                         return (EINVAL);
 813                                 tcp->tcp_ka_abort_thres =
 814                                     (*i1 * tcp->tcp_ka_cnt * 1000);
 815                         }
 816                         tcp->tcp_ka_rinterval = *i1 * 1000;
 817                         break;
 818                 case TCP_KEEPALIVE_ABORT_THRESHOLD:
 819                         if (!checkonly) {
 820                                 if (*i1 <
 821                                     tcps->tcps_keepalive_abort_interval_low ||
 822                                     *i1 >
 823                                     tcps->tcps_keepalive_abort_interval_high) {
 824                                         *outlenp = 0;
 825                                         return (EINVAL);
 826                                 }
 827                                 tcp->tcp_ka_abort_thres = *i1;
 828                                 tcp->tcp_ka_cnt = 0;
 829                                 tcp->tcp_ka_rinterval = 0;
 830                         }
 831                         break;
 832                 case TCP_CORK:
 833                         if (!checkonly) {
 834                                 /*
 835                                  * if tcp->tcp_cork was set and is now
 836                                  * being unset, we have to make sure that
 837                                  * the remaining data gets sent out. Also
 838                                  * unset tcp->tcp_cork so that tcp_wput_data()
 839                                  * can send data even if it is less than mss
 840                                  */
 841                                 if (tcp->tcp_cork && onoff == 0 &&
 842                                     tcp->tcp_unsent > 0) {
 843                                         tcp->tcp_cork = B_FALSE;
 844                                         tcp_wput_data(tcp, NULL, B_FALSE);
 845                                 }
 846                                 tcp->tcp_cork = onoff;
 847                         }
 848                         break;
 849                 case TCP_RTO_INITIAL: {
 850                         clock_t rto;
 851 
 852                         if (checkonly || val == 0)
 853                                 break;
 854 
 855                         /*
 856                          * Sanity checks
 857                          *
 858                          * The initial RTO should be bounded by the minimum
 859                          * and maximum RTO.  And it should also be smaller
 860                          * than the connect attempt abort timeout.  Otherwise,
 861                          * the connection won't be aborted in a period
 862                          * reasonably close to that timeout.
 863                          */
 864                         if (val < tcp->tcp_rto_min || val > tcp->tcp_rto_max ||
 865                             val > tcp->tcp_second_ctimer_threshold ||
 866                             val < tcps->tcps_rexmit_interval_initial_low ||
 867                             val > tcps->tcps_rexmit_interval_initial_high) {
 868                                 *outlenp = 0;
 869                                 return (EINVAL);
 870                         }
 871                         tcp->tcp_rto_initial = val;
 872 
 873                         /*
 874                          * If TCP has not sent anything, need to re-calculate
 875                          * tcp_rto.  Otherwise, this option change does not
 876                          * really affect anything.
 877                          */
 878                         if (tcp->tcp_state >= TCPS_SYN_SENT)
 879                                 break;
 880 
 881                         tcp->tcp_rtt_sa = tcp->tcp_rto_initial << 2;
 882                         tcp->tcp_rtt_sd = tcp->tcp_rto_initial >> 1;
 883                         rto = (tcp->tcp_rtt_sa >> 3) + tcp->tcp_rtt_sd +
 884                             tcps->tcps_rexmit_interval_extra +
 885                             (tcp->tcp_rtt_sa >> 5) +
 886                             tcps->tcps_conn_grace_period;
 887                         TCP_SET_RTO(tcp, rto);
 888                         break;
 889                 }
 890                 case TCP_RTO_MIN:
 891                         if (checkonly || val == 0)
 892                                 break;
 893 
 894                         if (val < tcps->tcps_rexmit_interval_min_low ||
 895                             val > tcps->tcps_rexmit_interval_min_high ||
 896                             val > tcp->tcp_rto_max) {
 897                                 *outlenp = 0;
 898                                 return (EINVAL);
 899                         }
 900                         tcp->tcp_rto_min = val;
 901                         if (tcp->tcp_rto < val)
 902                                 tcp->tcp_rto = val;
 903                         break;
 904                 case TCP_RTO_MAX:
 905                         if (checkonly || val == 0)
 906                                 break;
 907 
 908                         /*
 909                          * Sanity checks
 910                          *
 911                          * The maximum RTO should not be larger than the
 912                          * connection abort timeout.  Otherwise, the
 913                          * connection won't be aborted in a period reasonably
 914                          * close to that timeout.
 915                          */
 916                         if (val < tcps->tcps_rexmit_interval_max_low ||
 917                             val > tcps->tcps_rexmit_interval_max_high ||
 918                             val < tcp->tcp_rto_min ||
 919                             val > tcp->tcp_second_timer_threshold) {
 920                                 *outlenp = 0;
 921                                 return (EINVAL);
 922                         }
 923                         tcp->tcp_rto_max = val;
 924                         if (tcp->tcp_rto > val)
 925                                 tcp->tcp_rto = val;
 926                         break;
 927                 case TCP_LINGER2:
 928                         if (checkonly || *i1 == 0)
 929                                 break;
 930 
 931                         /*
 932                          * Note that the option value's unit is second.  And
 933                          * the value should be bigger than the private
 934                          * parameter tcp_fin_wait_2_flush_interval's lower
 935                          * bound and smaller than the current value of that
 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);
 980                 }
 981 
 982                 switch (name) {
 983                 case IPV6_RECVPKTINFO:
 984                         if (!checkonly) {
 985                                 /* Force it to be sent up with the next msg */
 986                                 tcp->tcp_recvifindex = 0;
 987                         }
 988                         break;
 989                 case IPV6_RECVTCLASS:
 990                         if (!checkonly) {
 991                                 /* Force it to be sent up with the next msg */
 992                                 tcp->tcp_recvtclass = 0xffffffffU;
 993                         }
 994                         break;
 995                 case IPV6_RECVHOPLIMIT:
 996                         if (!checkonly) {
 997                                 /* Force it to be sent up with the next msg */
 998                                 tcp->tcp_recvhops = 0xffffffffU;
 999                         }
1000                         break;
1001                 case IPV6_PKTINFO:
1002                         /* This is an extra check for TCP */
1003                         if (inlen == sizeof (struct in6_pktinfo)) {
1004                                 struct in6_pktinfo *pkti;
1005 
1006                                 pkti = (struct in6_pktinfo *)invalp;
1007                                 /*
1008                                  * RFC 3542 states that ipi6_addr must be
1009                                  * the unspecified address when setting the
1010                                  * IPV6_PKTINFO sticky socket option on a
1011                                  * TCP socket.
1012                                  */
1013                                 if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr))
1014                                         return (EINVAL);
1015                         }
1016                         break;
1017                 case IPV6_SEC_OPT:
1018                         /*
1019                          * We should not allow policy setting after
1020                          * we start listening for connections.
1021                          */
1022                         if (tcp->tcp_state == TCPS_LISTEN) {
1023                                 return (EINVAL);
1024                         }
1025                         break;
1026                 }
1027                 break;
1028         }
1029         reterr = conn_opt_set(&coas, level, name, inlen, invalp,
1030             checkonly, cr);
1031         if (reterr != 0) {
1032                 *outlenp = 0;
1033                 return (reterr);
1034         }
1035 
1036         /*
1037          * Common case of OK return with outval same as inval
1038          */
1039         if (invalp != outvalp) {
1040                 /* don't trust bcopy for identical src/dst */
1041                 (void) bcopy(invalp, outvalp, inlen);
1042         }
1043         *outlenp = inlen;
1044 
1045         if (coas.coa_changed & COA_HEADER_CHANGED) {
1046                 /* If we are connected we rebuilt the headers */
1047                 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) &&
1048                     !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) {
1049                         reterr = tcp_build_hdrs(tcp);
1050                         if (reterr != 0)
1051                                 return (reterr);
1052                 }
1053         }
1054         if (coas.coa_changed & COA_ROUTE_CHANGED) {
1055                 in6_addr_t nexthop;
1056 
1057                 /*
1058                  * If we are connected we re-cache the information.
1059                  * We ignore errors to preserve BSD behavior.
1060                  * Note that we don't redo IPsec policy lookup here
1061                  * since the final destination (or source) didn't change.
1062                  */
1063                 ip_attr_nexthop(&connp->conn_xmit_ipp, connp->conn_ixa,
1064                     &connp->conn_faddr_v6, &nexthop);
1065 
1066                 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) &&
1067                     !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) {
1068                         (void) ip_attr_connect(connp, connp->conn_ixa,
1069                             &connp->conn_laddr_v6, &connp->conn_faddr_v6,
1070                             &nexthop, connp->conn_fport, NULL, NULL,
1071                             IPDF_VERIFY_DST);
1072                 }
1073         }
1074         if ((coas.coa_changed & COA_SNDBUF_CHANGED) && !IPCL_IS_NONSTR(connp)) {
1075                 connp->conn_wq->q_hiwat = connp->conn_sndbuf;
1076         }
1077         if (coas.coa_changed & COA_WROFF_CHANGED) {
1078                 connp->conn_wroff = connp->conn_ht_iphc_allocated +
1079                     tcps->tcps_wroff_xtra;
1080                 (void) proto_set_tx_wroff(connp->conn_rq, connp,
1081                     connp->conn_wroff);
1082         }
1083         if (coas.coa_changed & COA_OOBINLINE_CHANGED) {
1084                 if (IPCL_IS_NONSTR(connp))
1085                         proto_set_rx_oob_opt(connp, onoff);
1086         }
1087         return (0);
1088 }