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 *, t_scalar_t, t_scalar_t, 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 /* Maximum TCP initial cwin (start/restart). */
 273 #define TCP_MAX_INIT_CWND       16
 274 
 275 static int tcp_max_init_cwnd = TCP_MAX_INIT_CWND;
 276 
 277 /*
 278  * Some TCP options can be "set" by requesting them in the option
 279  * buffer. This is needed for XTI feature test though we do not
 280  * allow it in general. We interpret that this mechanism is more
 281  * applicable to OSI protocols and need not be allowed in general.
 282  * This routine filters out options for which it is not allowed (most)
 283  * and lets through those (few) for which it is. [ The XTI interface
 284  * test suite specifics will imply that any XTI_GENERIC level XTI_* if
 285  * ever implemented will have to be allowed here ].
 286  */
 287 static boolean_t
 288 tcp_allow_connopt_set(int level, int name)
 289 {
 290 
 291         switch (level) {
 292         case IPPROTO_TCP:
 293                 switch (name) {
 294                 case TCP_NODELAY:
 295                         return (B_TRUE);
 296                 default:
 297                         return (B_FALSE);
 298                 }
 299                 /*NOTREACHED*/
 300         default:
 301                 return (B_FALSE);
 302         }
 303         /*NOTREACHED*/
 304 }
 305 
 306 /*
 307  * This routine gets default values of certain options whose default
 308  * values are maintained by protocol specific code
 309  */
 310 /* ARGSUSED */
 311 int
 312 tcp_opt_default(queue_t *q, int level, int name, uchar_t *ptr)
 313 {
 314         int32_t *i1 = (int32_t *)ptr;
 315         tcp_stack_t     *tcps = Q_TO_TCP(q)->tcp_tcps;
 316 
 317         switch (level) {
 318         case IPPROTO_TCP:
 319                 switch (name) {
 320                 case TCP_NOTIFY_THRESHOLD:
 321                         *i1 = tcps->tcps_ip_notify_interval;
 322                         break;
 323                 case TCP_ABORT_THRESHOLD:
 324                         *i1 = tcps->tcps_ip_abort_interval;
 325                         break;
 326                 case TCP_CONN_NOTIFY_THRESHOLD:
 327                         *i1 = tcps->tcps_ip_notify_cinterval;
 328                         break;
 329                 case TCP_CONN_ABORT_THRESHOLD:
 330                         *i1 = tcps->tcps_ip_abort_cinterval;
 331                         break;
 332                 default:
 333                         return (-1);
 334                 }
 335                 break;
 336         case IPPROTO_IP:
 337                 switch (name) {
 338                 case IP_TTL:
 339                         *i1 = tcps->tcps_ipv4_ttl;
 340                         break;
 341                 default:
 342                         return (-1);
 343                 }
 344                 break;
 345         case IPPROTO_IPV6:
 346                 switch (name) {
 347                 case IPV6_UNICAST_HOPS:
 348                         *i1 = tcps->tcps_ipv6_hoplimit;
 349                         break;
 350                 default:
 351                         return (-1);
 352                 }
 353                 break;
 354         default:
 355                 return (-1);
 356         }
 357         return (sizeof (int));
 358 }
 359 
 360 /*
 361  * TCP routine to get the values of options.
 362  */
 363 int
 364 tcp_opt_get(conn_t *connp, int level, int name, uchar_t *ptr)
 365 {
 366         int             *i1 = (int *)ptr;
 367         tcp_t           *tcp = connp->conn_tcp;
 368         conn_opt_arg_t  coas;
 369         int             retval;
 370 
 371         coas.coa_connp = connp;
 372         coas.coa_ixa = connp->conn_ixa;
 373         coas.coa_ipp = &connp->conn_xmit_ipp;
 374         coas.coa_ancillary = B_FALSE;
 375         coas.coa_changed = 0;
 376 
 377         switch (level) {
 378         case SOL_SOCKET:
 379                 switch (name) {
 380                 case SO_SND_COPYAVOID:
 381                         *i1 = tcp->tcp_snd_zcopy_on ?
 382                             SO_SND_COPYAVOID : 0;
 383                         return (sizeof (int));
 384                 case SO_ACCEPTCONN:
 385                         *i1 = (tcp->tcp_state == TCPS_LISTEN);
 386                         return (sizeof (int));
 387                 }
 388                 break;
 389         case IPPROTO_TCP:
 390                 switch (name) {
 391                 case TCP_NODELAY:
 392                         *i1 = (tcp->tcp_naglim == 1) ? TCP_NODELAY : 0;
 393                         return (sizeof (int));
 394                 case TCP_MAXSEG:
 395                         *i1 = tcp->tcp_mss;
 396                         return (sizeof (int));
 397                 case TCP_NOTIFY_THRESHOLD:
 398                         *i1 = (int)tcp->tcp_first_timer_threshold;
 399                         return (sizeof (int));
 400                 case TCP_ABORT_THRESHOLD:
 401                         *i1 = tcp->tcp_second_timer_threshold;
 402                         return (sizeof (int));
 403                 case TCP_CONN_NOTIFY_THRESHOLD:
 404                         *i1 = tcp->tcp_first_ctimer_threshold;
 405                         return (sizeof (int));
 406                 case TCP_CONN_ABORT_THRESHOLD:
 407                         *i1 = tcp->tcp_second_ctimer_threshold;
 408                         return (sizeof (int));
 409                 case TCP_INIT_CWND:
 410                         *i1 = tcp->tcp_init_cwnd;
 411                         return (sizeof (int));
 412                 case TCP_KEEPALIVE_THRESHOLD:
 413                         *i1 = tcp->tcp_ka_interval;
 414                         return (sizeof (int));
 415 
 416                 /*
 417                  * TCP_KEEPIDLE expects value in seconds, but
 418                  * tcp_ka_interval is in milliseconds.
 419                  */
 420                 case TCP_KEEPIDLE:
 421                         *i1 = tcp->tcp_ka_interval / 1000;
 422                         return (sizeof (int));
 423                 case TCP_KEEPCNT:
 424                         *i1 = tcp->tcp_ka_cnt;
 425                         return (sizeof (int));
 426 
 427                 /*
 428                  * TCP_KEEPINTVL expects value in seconds, but
 429                  * tcp_ka_rinterval is in milliseconds.
 430                  */
 431                 case TCP_KEEPINTVL:
 432                         *i1 = tcp->tcp_ka_rinterval / 1000;
 433                         return (sizeof (int));
 434                 case TCP_KEEPALIVE_ABORT_THRESHOLD:
 435                         *i1 = tcp->tcp_ka_abort_thres;
 436                         return (sizeof (int));
 437                 case TCP_CORK:
 438                         *i1 = tcp->tcp_cork;
 439                         return (sizeof (int));
 440                 case TCP_RTO_INITIAL:
 441                         *i1 = tcp->tcp_rto_initial;
 442                         return (sizeof (uint32_t));
 443                 case TCP_RTO_MIN:
 444                         *i1 = tcp->tcp_rto_min;
 445                         return (sizeof (uint32_t));
 446                 case TCP_RTO_MAX:
 447                         *i1 = tcp->tcp_rto_max;
 448                         return (sizeof (uint32_t));
 449                 case TCP_LINGER2:
 450                         *i1 = tcp->tcp_fin_wait_2_flush_interval / SECONDS;
 451                         return (sizeof (int));
 452                 }
 453                 break;
 454         case IPPROTO_IP:
 455                 if (connp->conn_family != AF_INET)
 456                         return (-1);
 457                 switch (name) {
 458                 case IP_OPTIONS:
 459                 case T_IP_OPTIONS:
 460                         /* Caller ensures enough space */
 461                         return (ip_opt_get_user(connp, ptr));
 462                 default:
 463                         break;
 464                 }
 465                 break;
 466 
 467         case IPPROTO_IPV6:
 468                 /*
 469                  * IPPROTO_IPV6 options are only supported for sockets
 470                  * that are using IPv6 on the wire.
 471                  */
 472                 if (connp->conn_ipversion != IPV6_VERSION) {
 473                         return (-1);
 474                 }
 475                 switch (name) {
 476                 case IPV6_PATHMTU:
 477                         if (tcp->tcp_state < TCPS_ESTABLISHED)
 478                                 return (-1);
 479                         break;
 480                 }
 481                 break;
 482         }
 483         mutex_enter(&connp->conn_lock);
 484         retval = conn_opt_get(&coas, level, name, ptr);
 485         mutex_exit(&connp->conn_lock);
 486         return (retval);
 487 }
 488 
 489 /*
 490  * We declare as 'int' rather than 'void' to satisfy pfi_t arg requirements.
 491  * Parameters are assumed to be verified by the caller.
 492  */
 493 /* ARGSUSED */
 494 int
 495 tcp_opt_set(conn_t *connp, uint_t optset_context, int level, int name,
 496     uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
 497     void *thisdg_attrs, cred_t *cr)
 498 {
 499         tcp_t   *tcp = connp->conn_tcp;
 500         int     *i1 = (int *)invalp;
 501         boolean_t onoff = (*i1 == 0) ? 0 : 1;
 502         boolean_t checkonly;
 503         int     reterr;
 504         tcp_stack_t     *tcps = tcp->tcp_tcps;
 505         conn_opt_arg_t  coas;
 506         uint32_t        val = *((uint32_t *)invalp);
 507 
 508         coas.coa_connp = connp;
 509         coas.coa_ixa = connp->conn_ixa;
 510         coas.coa_ipp = &connp->conn_xmit_ipp;
 511         coas.coa_ancillary = B_FALSE;
 512         coas.coa_changed = 0;
 513 
 514         switch (optset_context) {
 515         case SETFN_OPTCOM_CHECKONLY:
 516                 checkonly = B_TRUE;
 517                 /*
 518                  * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
 519                  * inlen != 0 implies value supplied and
 520                  *      we have to "pretend" to set it.
 521                  * inlen == 0 implies that there is no
 522                  *      value part in T_CHECK request and just validation
 523                  * done elsewhere should be enough, we just return here.
 524                  */
 525                 if (inlen == 0) {
 526                         *outlenp = 0;
 527                         return (0);
 528                 }
 529                 break;
 530         case SETFN_OPTCOM_NEGOTIATE:
 531                 checkonly = B_FALSE;
 532                 break;
 533         case SETFN_UD_NEGOTIATE: /* error on conn-oriented transports ? */
 534         case SETFN_CONN_NEGOTIATE:
 535                 checkonly = B_FALSE;
 536                 /*
 537                  * Negotiating local and "association-related" options
 538                  * from other (T_CONN_REQ, T_CONN_RES,T_UNITDATA_REQ)
 539                  * primitives is allowed by XTI, but we choose
 540                  * to not implement this style negotiation for Internet
 541                  * protocols (We interpret it is a must for OSI world but
 542                  * optional for Internet protocols) for all options.
 543                  * [ Will do only for the few options that enable test
 544                  * suites that our XTI implementation of this feature
 545                  * works for transports that do allow it ]
 546                  */
 547                 if (!tcp_allow_connopt_set(level, name)) {
 548                         *outlenp = 0;
 549                         return (EINVAL);
 550                 }
 551                 break;
 552         default:
 553                 /*
 554                  * We should never get here
 555                  */
 556                 *outlenp = 0;
 557                 return (EINVAL);
 558         }
 559 
 560         ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) ||
 561             (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0));
 562 
 563         /*
 564          * For TCP, we should have no ancillary data sent down
 565          * (sendmsg isn't supported for SOCK_STREAM), so thisdg_attrs
 566          * has to be zero.
 567          */
 568         ASSERT(thisdg_attrs == NULL);
 569 
 570         /*
 571          * For fixed length options, no sanity check
 572          * of passed in length is done. It is assumed *_optcom_req()
 573          * routines do the right thing.
 574          */
 575         switch (level) {
 576         case SOL_SOCKET:
 577                 switch (name) {
 578                 case SO_KEEPALIVE:
 579                         if (checkonly) {
 580                                 /* check only case */
 581                                 break;
 582                         }
 583 
 584                         if (!onoff) {
 585                                 if (connp->conn_keepalive) {
 586                                         if (tcp->tcp_ka_tid != 0) {
 587                                                 (void) TCP_TIMER_CANCEL(tcp,
 588                                                     tcp->tcp_ka_tid);
 589                                                 tcp->tcp_ka_tid = 0;
 590                                         }
 591                                         connp->conn_keepalive = 0;
 592                                 }
 593                                 break;
 594                         }
 595                         if (!connp->conn_keepalive) {
 596                                 /* Crank up the keepalive timer */
 597                                 tcp->tcp_ka_last_intrvl = 0;
 598                                 tcp->tcp_ka_tid = TCP_TIMER(tcp,
 599                                     tcp_keepalive_timer, tcp->tcp_ka_interval);
 600                                 connp->conn_keepalive = 1;
 601                         }
 602                         break;
 603                 case SO_SNDBUF: {
 604                         if (*i1 > tcps->tcps_max_buf) {
 605                                 *outlenp = 0;
 606                                 return (ENOBUFS);
 607                         }
 608                         if (checkonly)
 609                                 break;
 610 
 611                         connp->conn_sndbuf = *i1;
 612                         if (tcps->tcps_snd_lowat_fraction != 0) {
 613                                 connp->conn_sndlowat = connp->conn_sndbuf /
 614                                     tcps->tcps_snd_lowat_fraction;
 615                         }
 616                         (void) tcp_maxpsz_set(tcp, B_TRUE);
 617                         /*
 618                          * If we are flow-controlled, recheck the condition.
 619                          * There are apps that increase SO_SNDBUF size when
 620                          * flow-controlled (EWOULDBLOCK), and expect the flow
 621                          * control condition to be lifted right away.
 622                          */
 623                         mutex_enter(&tcp->tcp_non_sq_lock);
 624                         if (tcp->tcp_flow_stopped &&
 625                             TCP_UNSENT_BYTES(tcp) < connp->conn_sndbuf) {
 626                                 tcp_clrqfull(tcp);
 627                         }
 628                         mutex_exit(&tcp->tcp_non_sq_lock);
 629                         *outlenp = inlen;
 630                         return (0);
 631                 }
 632                 case SO_RCVBUF:
 633                         if (*i1 > tcps->tcps_max_buf) {
 634                                 *outlenp = 0;
 635                                 return (ENOBUFS);
 636                         }
 637                         /* Silently ignore zero */
 638                         if (!checkonly && *i1 != 0) {
 639                                 *i1 = MSS_ROUNDUP(*i1, tcp->tcp_mss);
 640                                 (void) tcp_rwnd_set(tcp, *i1);
 641                         }
 642                         /*
 643                          * XXX should we return the rwnd here
 644                          * and tcp_opt_get ?
 645                          */
 646                         *outlenp = inlen;
 647                         return (0);
 648                 case SO_SND_COPYAVOID:
 649                         if (!checkonly) {
 650                                 if (tcp->tcp_loopback ||
 651                                     (onoff != 1) || !tcp_zcopy_check(tcp)) {
 652                                         *outlenp = 0;
 653                                         return (EOPNOTSUPP);
 654                                 }
 655                                 tcp->tcp_snd_zcopy_aware = 1;
 656                         }
 657                         *outlenp = inlen;
 658                         return (0);
 659                 }
 660                 break;
 661         case IPPROTO_TCP:
 662                 switch (name) {
 663                 case TCP_NODELAY:
 664                         if (!checkonly)
 665                                 tcp->tcp_naglim = *i1 ? 1 : tcp->tcp_mss;
 666                         break;
 667                 case TCP_NOTIFY_THRESHOLD:
 668                         if (!checkonly)
 669                                 tcp->tcp_first_timer_threshold = *i1;
 670                         break;
 671                 case TCP_ABORT_THRESHOLD:
 672                         if (!checkonly)
 673                                 tcp->tcp_second_timer_threshold = *i1;
 674                         break;
 675                 case TCP_CONN_NOTIFY_THRESHOLD:
 676                         if (!checkonly)
 677                                 tcp->tcp_first_ctimer_threshold = *i1;
 678                         break;
 679                 case TCP_CONN_ABORT_THRESHOLD:
 680                         if (!checkonly)
 681                                 tcp->tcp_second_ctimer_threshold = *i1;
 682                         break;
 683                 case TCP_RECVDSTADDR:
 684                         if (tcp->tcp_state > TCPS_LISTEN) {
 685                                 *outlenp = 0;
 686                                 return (EOPNOTSUPP);
 687                         }
 688                         /* Setting done in conn_opt_set */
 689                         break;
 690                 case TCP_INIT_CWND:
 691                         if (checkonly)
 692                                 break;
 693 
 694                         /*
 695                          * Only allow socket with network configuration
 696                          * privilege to set the initial cwnd to be larger
 697                          * than allowed by RFC 3390.
 698                          */
 699                         if (val > MIN(4, MAX(2, 4380 / tcp->tcp_mss))) {
 700                                 if ((reterr = secpolicy_ip_config(cr, B_TRUE))
 701                                     != 0) {
 702                                         *outlenp = 0;
 703                                         return (reterr);
 704                                 }
 705                                 if (val > tcp_max_init_cwnd) {
 706                                         *outlenp = 0;
 707                                         return (EINVAL);
 708                                 }
 709                         }
 710 
 711                         tcp->tcp_init_cwnd = val;
 712 
 713                         /*
 714                          * If the socket is connected, AND no outbound data
 715                          * has been sent, reset the actual cwnd values.
 716                          */
 717                         if (tcp->tcp_state == TCPS_ESTABLISHED &&
 718                             tcp->tcp_iss == tcp->tcp_snxt - 1) {
 719                                 tcp->tcp_cwnd =
 720                                     MIN(tcp->tcp_rwnd, val * tcp->tcp_mss);
 721                         }
 722                         break;
 723 
 724                 /*
 725                  * TCP_KEEPIDLE is in seconds but TCP_KEEPALIVE_THRESHOLD
 726                  * is in milliseconds. TCP_KEEPIDLE is introduced for
 727                  * compatibility with other Unix flavors.
 728                  * We can fall through TCP_KEEPALIVE_THRESHOLD logic after
 729                  * converting the input to milliseconds.
 730                  */
 731                 case TCP_KEEPIDLE:
 732                         *i1 *= 1000;
 733                         /* FALLTHRU */
 734 
 735                 case TCP_KEEPALIVE_THRESHOLD:
 736                         if (checkonly)
 737                                 break;
 738 
 739                         if (*i1 < tcps->tcps_keepalive_interval_low ||
 740                             *i1 > tcps->tcps_keepalive_interval_high) {
 741                                 *outlenp = 0;
 742                                 return (EINVAL);
 743                         }
 744                         if (*i1 != tcp->tcp_ka_interval) {
 745                                 tcp->tcp_ka_interval = *i1;
 746                                 /*
 747                                  * Check if we need to restart the
 748                                  * keepalive timer.
 749                                  */
 750                                 if (tcp->tcp_ka_tid != 0) {
 751                                         ASSERT(connp->conn_keepalive);
 752                                         (void) TCP_TIMER_CANCEL(tcp,
 753                                             tcp->tcp_ka_tid);
 754                                         tcp->tcp_ka_last_intrvl = 0;
 755                                         tcp->tcp_ka_tid = TCP_TIMER(tcp,
 756                                             tcp_keepalive_timer,
 757                                             tcp->tcp_ka_interval);
 758                                 }
 759                         }
 760                         break;
 761 
 762                 /*
 763                  * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt.
 764                  * So setting TCP_KEEPCNT or TCP_KEEPINTVL can affect all the
 765                  * three members - tcp_ka_abort_thres, tcp_ka_rinterval and
 766                  * tcp_ka_cnt.
 767                  */
 768                 case TCP_KEEPCNT:
 769                         if (checkonly)
 770                                 break;
 771 
 772                         if (*i1 == 0) {
 773                                 return (EINVAL);
 774                         } else if (tcp->tcp_ka_rinterval == 0) {
 775                                 if ((tcp->tcp_ka_abort_thres / *i1) <
 776                                     tcp->tcp_rto_min ||
 777                                     (tcp->tcp_ka_abort_thres / *i1) >
 778                                     tcp->tcp_rto_max)
 779                                         return (EINVAL);
 780 
 781                                 tcp->tcp_ka_rinterval =
 782                                     tcp->tcp_ka_abort_thres / *i1;
 783                         } else {
 784                                 if ((*i1 * tcp->tcp_ka_rinterval) <
 785                                     tcps->tcps_keepalive_abort_interval_low ||
 786                                     (*i1 * tcp->tcp_ka_rinterval) >
 787                                     tcps->tcps_keepalive_abort_interval_high)
 788                                         return (EINVAL);
 789                                 tcp->tcp_ka_abort_thres =
 790                                     (*i1 * tcp->tcp_ka_rinterval);
 791                         }
 792                         tcp->tcp_ka_cnt = *i1;
 793                         break;
 794                 case TCP_KEEPINTVL:
 795                         /*
 796                          * TCP_KEEPINTVL is specified in seconds, but
 797                          * tcp_ka_rinterval is in milliseconds.
 798                          */
 799 
 800                         if (checkonly)
 801                                 break;
 802 
 803                         if ((*i1 * 1000) < tcp->tcp_rto_min ||
 804                             (*i1 * 1000) > tcp->tcp_rto_max)
 805                                 return (EINVAL);
 806 
 807                         if (tcp->tcp_ka_cnt == 0) {
 808                                 tcp->tcp_ka_cnt =
 809                                     tcp->tcp_ka_abort_thres / (*i1 * 1000);
 810                         } else {
 811                                 if ((*i1 * tcp->tcp_ka_cnt * 1000) <
 812                                     tcps->tcps_keepalive_abort_interval_low ||
 813                                     (*i1 * tcp->tcp_ka_cnt * 1000) >
 814                                     tcps->tcps_keepalive_abort_interval_high)
 815                                         return (EINVAL);
 816                                 tcp->tcp_ka_abort_thres =
 817                                     (*i1 * tcp->tcp_ka_cnt * 1000);
 818                         }
 819                         tcp->tcp_ka_rinterval = *i1 * 1000;
 820                         break;
 821                 case TCP_KEEPALIVE_ABORT_THRESHOLD:
 822                         if (!checkonly) {
 823                                 if (*i1 <
 824                                     tcps->tcps_keepalive_abort_interval_low ||
 825                                     *i1 >
 826                                     tcps->tcps_keepalive_abort_interval_high) {
 827                                         *outlenp = 0;
 828                                         return (EINVAL);
 829                                 }
 830                                 tcp->tcp_ka_abort_thres = *i1;
 831                                 tcp->tcp_ka_cnt = 0;
 832                                 tcp->tcp_ka_rinterval = 0;
 833                         }
 834                         break;
 835                 case TCP_CORK:
 836                         if (!checkonly) {
 837                                 /*
 838                                  * if tcp->tcp_cork was set and is now
 839                                  * being unset, we have to make sure that
 840                                  * the remaining data gets sent out. Also
 841                                  * unset tcp->tcp_cork so that tcp_wput_data()
 842                                  * can send data even if it is less than mss
 843                                  */
 844                                 if (tcp->tcp_cork && onoff == 0 &&
 845                                     tcp->tcp_unsent > 0) {
 846                                         tcp->tcp_cork = B_FALSE;
 847                                         tcp_wput_data(tcp, NULL, B_FALSE);
 848                                 }
 849                                 tcp->tcp_cork = onoff;
 850                         }
 851                         break;
 852                 case TCP_RTO_INITIAL: {
 853                         clock_t rto;
 854 
 855                         if (checkonly || val == 0)
 856                                 break;
 857 
 858                         /*
 859                          * Sanity checks
 860                          *
 861                          * The initial RTO should be bounded by the minimum
 862                          * and maximum RTO.  And it should also be smaller
 863                          * than the connect attempt abort timeout.  Otherwise,
 864                          * the connection won't be aborted in a period
 865                          * reasonably close to that timeout.
 866                          */
 867                         if (val < tcp->tcp_rto_min || val > tcp->tcp_rto_max ||
 868                             val > tcp->tcp_second_ctimer_threshold ||
 869                             val < tcps->tcps_rexmit_interval_initial_low ||
 870                             val > tcps->tcps_rexmit_interval_initial_high) {
 871                                 *outlenp = 0;
 872                                 return (EINVAL);
 873                         }
 874                         tcp->tcp_rto_initial = val;
 875 
 876                         /*
 877                          * If TCP has not sent anything, need to re-calculate
 878                          * tcp_rto.  Otherwise, this option change does not
 879                          * really affect anything.
 880                          */
 881                         if (tcp->tcp_state >= TCPS_SYN_SENT)
 882                                 break;
 883 
 884                         tcp->tcp_rtt_sa = tcp->tcp_rto_initial << 2;
 885                         tcp->tcp_rtt_sd = tcp->tcp_rto_initial >> 1;
 886                         rto = (tcp->tcp_rtt_sa >> 3) + tcp->tcp_rtt_sd +
 887                             tcps->tcps_rexmit_interval_extra +
 888                             (tcp->tcp_rtt_sa >> 5) +
 889                             tcps->tcps_conn_grace_period;
 890                         TCP_SET_RTO(tcp, rto);
 891                         break;
 892                 }
 893                 case TCP_RTO_MIN:
 894                         if (checkonly || val == 0)
 895                                 break;
 896 
 897                         if (val < tcps->tcps_rexmit_interval_min_low ||
 898                             val > tcps->tcps_rexmit_interval_min_high ||
 899                             val > tcp->tcp_rto_max) {
 900                                 *outlenp = 0;
 901                                 return (EINVAL);
 902                         }
 903                         tcp->tcp_rto_min = val;
 904                         if (tcp->tcp_rto < val)
 905                                 tcp->tcp_rto = val;
 906                         break;
 907                 case TCP_RTO_MAX:
 908                         if (checkonly || val == 0)
 909                                 break;
 910 
 911                         /*
 912                          * Sanity checks
 913                          *
 914                          * The maximum RTO should not be larger than the
 915                          * connection abort timeout.  Otherwise, the
 916                          * connection won't be aborted in a period reasonably
 917                          * close to that timeout.
 918                          */
 919                         if (val < tcps->tcps_rexmit_interval_max_low ||
 920                             val > tcps->tcps_rexmit_interval_max_high ||
 921                             val < tcp->tcp_rto_min ||
 922                             val > tcp->tcp_second_timer_threshold) {
 923                                 *outlenp = 0;
 924                                 return (EINVAL);
 925                         }
 926                         tcp->tcp_rto_max = val;
 927                         if (tcp->tcp_rto > val)
 928                                 tcp->tcp_rto = val;
 929                         break;
 930                 case TCP_LINGER2:
 931                         if (checkonly || *i1 == 0)
 932                                 break;
 933 
 934                         /*
 935                          * Note that the option value's unit is second.  And
 936                          * the value should be bigger than the private
 937                          * parameter tcp_fin_wait_2_flush_interval's lower
 938                          * bound and smaller than the current value of that
 939                          * parameter.  It should be smaller than the current
 940                          * value to avoid an app setting TCP_LINGER2 to a big
 941                          * value, causing resource to be held up too long in
 942                          * FIN-WAIT-2 state.
 943                          */
 944                         if (*i1 < 0 ||
 945                             tcps->tcps_fin_wait_2_flush_interval_low/SECONDS >
 946                             *i1 ||
 947                             tcps->tcps_fin_wait_2_flush_interval/SECONDS <
 948                             *i1) {
 949                                 *outlenp = 0;
 950                                 return (EINVAL);
 951                         }
 952                         tcp->tcp_fin_wait_2_flush_interval = *i1 * SECONDS;
 953                         break;
 954                 default:
 955                         break;
 956                 }
 957                 break;
 958         case IPPROTO_IP:
 959                 if (connp->conn_family != AF_INET) {
 960                         *outlenp = 0;
 961                         return (EINVAL);
 962                 }
 963                 switch (name) {
 964                 case IP_SEC_OPT:
 965                         /*
 966                          * We should not allow policy setting after
 967                          * we start listening for connections.
 968                          */
 969                         if (tcp->tcp_state == TCPS_LISTEN) {
 970                                 return (EINVAL);
 971                         }
 972                         break;
 973                 }
 974                 break;
 975         case IPPROTO_IPV6:
 976                 /*
 977                  * IPPROTO_IPV6 options are only supported for sockets
 978                  * that are using IPv6 on the wire.
 979                  */
 980                 if (connp->conn_ipversion != IPV6_VERSION) {
 981                         *outlenp = 0;
 982                         return (EINVAL);
 983                 }
 984 
 985                 switch (name) {
 986                 case IPV6_RECVPKTINFO:
 987                         if (!checkonly) {
 988                                 /* Force it to be sent up with the next msg */
 989                                 tcp->tcp_recvifindex = 0;
 990                         }
 991                         break;
 992                 case IPV6_RECVTCLASS:
 993                         if (!checkonly) {
 994                                 /* Force it to be sent up with the next msg */
 995                                 tcp->tcp_recvtclass = 0xffffffffU;
 996                         }
 997                         break;
 998                 case IPV6_RECVHOPLIMIT:
 999                         if (!checkonly) {
1000                                 /* Force it to be sent up with the next msg */
1001                                 tcp->tcp_recvhops = 0xffffffffU;
1002                         }
1003                         break;
1004                 case IPV6_PKTINFO:
1005                         /* This is an extra check for TCP */
1006                         if (inlen == sizeof (struct in6_pktinfo)) {
1007                                 struct in6_pktinfo *pkti;
1008 
1009                                 pkti = (struct in6_pktinfo *)invalp;
1010                                 /*
1011                                  * RFC 3542 states that ipi6_addr must be
1012                                  * the unspecified address when setting the
1013                                  * IPV6_PKTINFO sticky socket option on a
1014                                  * TCP socket.
1015                                  */
1016                                 if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr))
1017                                         return (EINVAL);
1018                         }
1019                         break;
1020                 case IPV6_SEC_OPT:
1021                         /*
1022                          * We should not allow policy setting after
1023                          * we start listening for connections.
1024                          */
1025                         if (tcp->tcp_state == TCPS_LISTEN) {
1026                                 return (EINVAL);
1027                         }
1028                         break;
1029                 }
1030                 break;
1031         }
1032         reterr = conn_opt_set(&coas, level, name, inlen, invalp,
1033             checkonly, cr);
1034         if (reterr != 0) {
1035                 *outlenp = 0;
1036                 return (reterr);
1037         }
1038 
1039         /*
1040          * Common case of OK return with outval same as inval
1041          */
1042         if (invalp != outvalp) {
1043                 /* don't trust bcopy for identical src/dst */
1044                 (void) bcopy(invalp, outvalp, inlen);
1045         }
1046         *outlenp = inlen;
1047 
1048         if (coas.coa_changed & COA_HEADER_CHANGED) {
1049                 /* If we are connected we rebuilt the headers */
1050                 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) &&
1051                     !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) {
1052                         reterr = tcp_build_hdrs(tcp);
1053                         if (reterr != 0)
1054                                 return (reterr);
1055                 }
1056         }
1057         if (coas.coa_changed & COA_ROUTE_CHANGED) {
1058                 in6_addr_t nexthop;
1059 
1060                 /*
1061                  * If we are connected we re-cache the information.
1062                  * We ignore errors to preserve BSD behavior.
1063                  * Note that we don't redo IPsec policy lookup here
1064                  * since the final destination (or source) didn't change.
1065                  */
1066                 ip_attr_nexthop(&connp->conn_xmit_ipp, connp->conn_ixa,
1067                     &connp->conn_faddr_v6, &nexthop);
1068 
1069                 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) &&
1070                     !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) {
1071                         (void) ip_attr_connect(connp, connp->conn_ixa,
1072                             &connp->conn_laddr_v6, &connp->conn_faddr_v6,
1073                             &nexthop, connp->conn_fport, NULL, NULL,
1074                             IPDF_VERIFY_DST);
1075                 }
1076         }
1077         if ((coas.coa_changed & COA_SNDBUF_CHANGED) && !IPCL_IS_NONSTR(connp)) {
1078                 connp->conn_wq->q_hiwat = connp->conn_sndbuf;
1079         }
1080         if (coas.coa_changed & COA_WROFF_CHANGED) {
1081                 connp->conn_wroff = connp->conn_ht_iphc_allocated +
1082                     tcps->tcps_wroff_xtra;
1083                 (void) proto_set_tx_wroff(connp->conn_rq, connp,
1084                     connp->conn_wroff);
1085         }
1086         if (coas.coa_changed & COA_OOBINLINE_CHANGED) {
1087                 if (IPCL_IS_NONSTR(connp))
1088                         proto_set_rx_oob_opt(connp, onoff);
1089         }
1090         return (0);
1091 }