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 * Copyright 2019 Joyent, Inc. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 27 * Copyright 2024 Oxide Computer Company 28 */ 29 30 #include <sys/types.h> 31 #include <sys/stream.h> 32 #define _SUN_TPI_VERSION 2 33 #include <sys/tihdr.h> 34 #include <sys/socket.h> 35 #include <sys/xti_xtiopt.h> 36 #include <sys/xti_inet.h> 37 #include <sys/policy.h> 38 39 #include <inet/cc.h> 40 #include <inet/common.h> 41 #include <netinet/ip6.h> 42 #include <inet/ip.h> 43 44 #include <netinet/in.h> 45 #include <netinet/tcp.h> 46 #include <inet/optcom.h> 47 #include <inet/proto_set.h> 48 #include <inet/tcp_impl.h> 49 50 static int tcp_opt_default(queue_t *, int, int, uchar_t *); 51 52 /* 53 * Table of all known options handled on a TCP protocol stack. 54 * 55 * Note: This table contains options processed by both TCP and IP levels 56 * and is the superset of options that can be performed on a TCP over IP 57 * stack. 58 */ 59 opdes_t tcp_opt_arr[] = { 60 61 { SO_LINGER, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, 62 sizeof (struct linger), 0 }, 63 64 { SO_DEBUG, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 65 { SO_KEEPALIVE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 66 { SO_DONTROUTE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 67 { SO_USELOOPBACK, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 68 }, 69 { SO_BROADCAST, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 70 { SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 71 { SO_OOBINLINE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 72 { SO_TYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 }, 73 { SO_SNDBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 74 { SO_RCVBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 75 { SO_SNDTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, 76 sizeof (struct timeval), 0 }, 77 { SO_RCVTIMEO, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, 78 sizeof (struct timeval), 0 }, 79 { SO_DGRAM_ERRIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 80 }, 81 { SO_SND_COPYAVOID, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 82 { SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 83 0 }, 84 { SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 85 0 }, 86 { SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 87 0 }, 88 { SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int), 89 0 }, 90 { SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 91 92 { SO_DOMAIN, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 }, 93 94 { SO_PROTOTYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 }, 95 96 { TCP_NODELAY, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 97 }, 98 { TCP_MAXSEG, IPPROTO_TCP, OA_R, OA_R, OP_NP, 0, sizeof (uint_t), 99 536 }, 100 101 { TCP_NOTIFY_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 102 OP_DEF_FN, sizeof (int), -1 /* not initialized */ }, 103 104 { TCP_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 105 OP_DEF_FN, sizeof (int), -1 /* not initialized */ }, 106 107 { TCP_CONN_NOTIFY_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 108 OP_DEF_FN, sizeof (int), -1 /* not initialized */ }, 109 110 { TCP_CONN_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 111 OP_DEF_FN, sizeof (int), -1 /* not initialized */ }, 112 113 { TCP_RECVDSTADDR, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 114 0 }, 115 116 { TCP_ANONPRIVBIND, IPPROTO_TCP, OA_R, OA_RW, OP_PRIVPORT, 0, 117 sizeof (int), 0 }, 118 119 { TCP_EXCLBIND, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 120 }, 121 122 { TCP_INIT_CWND, IPPROTO_TCP, OA_RW, OA_RW, OP_CONFIG, 0, 123 sizeof (int), 0 }, 124 125 { TCP_KEEPALIVE_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, 126 sizeof (int), 0 }, 127 128 { TCP_KEEPIDLE, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 129 130 { TCP_KEEPCNT, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 131 132 { TCP_KEEPINTVL, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 133 134 { TCP_KEEPALIVE_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, 135 sizeof (int), 0 }, 136 137 { TCP_CORK, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 138 139 { TCP_QUICKACK, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 140 141 { TCP_RTO_INITIAL, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 }, 142 143 { TCP_RTO_MIN, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 }, 144 145 { TCP_RTO_MAX, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (uint32_t), 0 }, 146 147 { TCP_LINGER2, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 148 149 { TCP_CONGESTION, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 150 OP_VARLEN, CC_ALGO_NAME_MAX, 0 }, 151 152 { IP_OPTIONS, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 153 (OP_VARLEN|OP_NODEFAULT), 154 IP_MAX_OPT_LENGTH + IP_ADDR_LEN, -1 /* not initialized */ }, 155 { T_IP_OPTIONS, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 156 (OP_VARLEN|OP_NODEFAULT), 157 IP_MAX_OPT_LENGTH + IP_ADDR_LEN, -1 /* not initialized */ }, 158 159 { IP_TOS, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 160 { T_IP_TOS, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 161 { IP_TTL, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN, 162 sizeof (int), -1 /* not initialized */ }, 163 { IP_RECVTOS, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 164 165 { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT, 166 sizeof (ipsec_req_t), -1 /* not initialized */ }, 167 168 { IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, 169 sizeof (int), 0 /* no ifindex */ }, 170 171 { IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0, 172 sizeof (int), 0 }, 173 174 { IP_MINTTL, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 175 176 { IPV6_UNICAST_HOPS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_DEF_FN, 177 sizeof (int), -1 /* not initialized */ }, 178 179 { IPV6_BOUND_IF, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 180 sizeof (int), 0 /* no ifindex */ }, 181 182 { IP_DONTFRAG, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 }, 183 184 { IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0, 185 sizeof (in_addr_t), -1 /* not initialized */ }, 186 187 { IPV6_UNSPEC_SRC, IPPROTO_IPV6, OA_R, OA_RW, OP_RAW, 0, 188 sizeof (int), 0 }, 189 190 { IPV6_PKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 191 (OP_NODEFAULT|OP_VARLEN), 192 sizeof (struct in6_pktinfo), -1 /* not initialized */ }, 193 { IPV6_NEXTHOP, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 194 OP_NODEFAULT, 195 sizeof (sin6_t), -1 /* not initialized */ }, 196 { IPV6_HOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 197 (OP_VARLEN|OP_NODEFAULT), 255*8, 198 -1 /* not initialized */ }, 199 { IPV6_DSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 200 (OP_VARLEN|OP_NODEFAULT), 255*8, 201 -1 /* not initialized */ }, 202 { IPV6_RTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 203 (OP_VARLEN|OP_NODEFAULT), 255*8, 204 -1 /* not initialized */ }, 205 { IPV6_RTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 206 (OP_VARLEN|OP_NODEFAULT), 255*8, 207 -1 /* not initialized */ }, 208 { IPV6_TCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 209 OP_NODEFAULT, 210 sizeof (int), -1 /* not initialized */ }, 211 { IPV6_PATHMTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 212 OP_NODEFAULT, 213 sizeof (struct ip6_mtuinfo), -1 /* not initialized */ }, 214 { IPV6_DONTFRAG, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 215 sizeof (int), 0 }, 216 { IPV6_USE_MIN_MTU, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 217 sizeof (int), 0 }, 218 { IPV6_V6ONLY, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 219 sizeof (int), 0 }, 220 221 /* Enable receipt of ancillary data */ 222 { IPV6_RECVPKTINFO, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 223 sizeof (int), 0 }, 224 { IPV6_RECVHOPLIMIT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 225 sizeof (int), 0 }, 226 { IPV6_RECVHOPOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 227 sizeof (int), 0 }, 228 { _OLD_IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 229 sizeof (int), 0 }, 230 { IPV6_RECVDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 231 sizeof (int), 0 }, 232 { IPV6_RECVRTHDR, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 233 sizeof (int), 0 }, 234 { IPV6_RECVRTHDRDSTOPTS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 235 sizeof (int), 0 }, 236 { IPV6_RECVTCLASS, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 237 sizeof (int), 0 }, 238 239 { IPV6_SEC_OPT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, OP_NODEFAULT, 240 sizeof (ipsec_req_t), -1 /* not initialized */ }, 241 { IPV6_SRC_PREFERENCES, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 242 sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT }, 243 244 { IPV6_MINHOPCOUNT, IPPROTO_IPV6, OA_RW, OA_RW, OP_NP, 0, 245 sizeof (int), 0 }, 246 }; 247 248 /* 249 * Table of all supported levels 250 * Note: Some levels (e.g. XTI_GENERIC) may be valid but may not have 251 * any supported options so we need this info separately. 252 * 253 * This is needed only for topmost tpi providers and is used only by 254 * XTI interfaces. 255 */ 256 optlevel_t tcp_valid_levels_arr[] = { 257 XTI_GENERIC, 258 SOL_SOCKET, 259 IPPROTO_TCP, 260 IPPROTO_IP, 261 IPPROTO_IPV6 262 }; 263 264 265 #define TCP_OPT_ARR_CNT A_CNT(tcp_opt_arr) 266 #define TCP_VALID_LEVELS_CNT A_CNT(tcp_valid_levels_arr) 267 268 uint_t tcp_max_optsize; /* initialized when TCP driver is loaded */ 269 270 /* 271 * Initialize option database object for TCP 272 * 273 * This object represents database of options to search passed to 274 * {sock,tpi}optcom_req() interface routine to take care of option 275 * management and associated methods. 276 */ 277 278 optdb_obj_t tcp_opt_obj = { 279 tcp_opt_default, /* TCP default value function pointer */ 280 tcp_tpi_opt_get, /* TCP get function pointer */ 281 tcp_tpi_opt_set, /* TCP set function pointer */ 282 TCP_OPT_ARR_CNT, /* TCP option database count of entries */ 283 tcp_opt_arr, /* TCP option database */ 284 TCP_VALID_LEVELS_CNT, /* TCP valid level count of entries */ 285 tcp_valid_levels_arr /* TCP valid level array */ 286 }; 287 288 static int tcp_max_init_cwnd = TCP_MAX_INIT_CWND; 289 290 /* 291 * Some TCP options can be "set" by requesting them in the option 292 * buffer. This is needed for XTI feature test though we do not 293 * allow it in general. We interpret that this mechanism is more 294 * applicable to OSI protocols and need not be allowed in general. 295 * This routine filters out options for which it is not allowed (most) 296 * and lets through those (few) for which it is. [ The XTI interface 297 * test suite specifics will imply that any XTI_GENERIC level XTI_* if 298 * ever implemented will have to be allowed here ]. 299 */ 300 static boolean_t 301 tcp_allow_connopt_set(int level, int name) 302 { 303 304 switch (level) { 305 case IPPROTO_TCP: 306 switch (name) { 307 case TCP_NODELAY: 308 return (B_TRUE); 309 default: 310 return (B_FALSE); 311 } 312 /*NOTREACHED*/ 313 default: 314 return (B_FALSE); 315 } 316 /*NOTREACHED*/ 317 } 318 319 /* 320 * This routine gets default values of certain options whose default 321 * values are maintained by protocol specific code 322 */ 323 /* ARGSUSED */ 324 static int 325 tcp_opt_default(queue_t *q, int level, int name, uchar_t *ptr) 326 { 327 int32_t *i1 = (int32_t *)ptr; 328 tcp_stack_t *tcps = Q_TO_TCP(q)->tcp_tcps; 329 330 switch (level) { 331 case IPPROTO_TCP: 332 switch (name) { 333 case TCP_NOTIFY_THRESHOLD: 334 *i1 = tcps->tcps_ip_notify_interval; 335 break; 336 case TCP_ABORT_THRESHOLD: 337 *i1 = tcps->tcps_ip_abort_interval; 338 break; 339 case TCP_CONN_NOTIFY_THRESHOLD: 340 *i1 = tcps->tcps_ip_notify_cinterval; 341 break; 342 case TCP_CONN_ABORT_THRESHOLD: 343 *i1 = tcps->tcps_ip_abort_cinterval; 344 break; 345 default: 346 return (-1); 347 } 348 break; 349 case IPPROTO_IP: 350 switch (name) { 351 case IP_TTL: 352 *i1 = tcps->tcps_ipv4_ttl; 353 break; 354 default: 355 return (-1); 356 } 357 break; 358 case IPPROTO_IPV6: 359 switch (name) { 360 case IPV6_UNICAST_HOPS: 361 *i1 = tcps->tcps_ipv6_hoplimit; 362 break; 363 default: 364 return (-1); 365 } 366 break; 367 default: 368 return (-1); 369 } 370 return (sizeof (int)); 371 } 372 373 /* 374 * TCP routine to get the values of options. 375 */ 376 int 377 tcp_opt_get(conn_t *connp, int level, int name, uchar_t *ptr) 378 { 379 int *i1 = (int *)ptr; 380 tcp_t *tcp = connp->conn_tcp; 381 conn_opt_arg_t coas; 382 int retval; 383 384 coas.coa_connp = connp; 385 coas.coa_ixa = connp->conn_ixa; 386 coas.coa_ipp = &connp->conn_xmit_ipp; 387 coas.coa_ancillary = B_FALSE; 388 coas.coa_changed = 0; 389 390 switch (level) { 391 case SOL_SOCKET: 392 switch (name) { 393 case SO_SND_COPYAVOID: 394 *i1 = tcp->tcp_snd_zcopy_on ? 395 SO_SND_COPYAVOID : 0; 396 return (sizeof (int)); 397 case SO_ACCEPTCONN: 398 *i1 = (tcp->tcp_state == TCPS_LISTEN); 399 return (sizeof (int)); 400 } 401 break; 402 case IPPROTO_TCP: 403 switch (name) { 404 case TCP_NODELAY: 405 *i1 = (tcp->tcp_naglim == 1) ? TCP_NODELAY : 0; 406 return (sizeof (int)); 407 case TCP_MAXSEG: 408 *i1 = tcp->tcp_mss; 409 return (sizeof (int)); 410 case TCP_NOTIFY_THRESHOLD: 411 *i1 = (int)tcp->tcp_first_timer_threshold; 412 return (sizeof (int)); 413 case TCP_ABORT_THRESHOLD: 414 *i1 = tcp->tcp_second_timer_threshold; 415 return (sizeof (int)); 416 case TCP_CONN_NOTIFY_THRESHOLD: 417 *i1 = tcp->tcp_first_ctimer_threshold; 418 return (sizeof (int)); 419 case TCP_CONN_ABORT_THRESHOLD: 420 *i1 = tcp->tcp_second_ctimer_threshold; 421 return (sizeof (int)); 422 case TCP_INIT_CWND: 423 *i1 = tcp->tcp_init_cwnd; 424 return (sizeof (int)); 425 case TCP_KEEPALIVE_THRESHOLD: 426 *i1 = tcp->tcp_ka_interval; 427 return (sizeof (int)); 428 429 /* 430 * TCP_KEEPIDLE expects value in seconds, but 431 * tcp_ka_interval is in milliseconds. 432 */ 433 case TCP_KEEPIDLE: 434 *i1 = tcp->tcp_ka_interval / 1000; 435 return (sizeof (int)); 436 case TCP_KEEPCNT: 437 *i1 = tcp->tcp_ka_cnt; 438 return (sizeof (int)); 439 440 /* 441 * TCP_KEEPINTVL expects value in seconds, but 442 * tcp_ka_rinterval is in milliseconds. 443 */ 444 case TCP_KEEPINTVL: 445 *i1 = tcp->tcp_ka_rinterval / 1000; 446 return (sizeof (int)); 447 case TCP_KEEPALIVE_ABORT_THRESHOLD: 448 *i1 = tcp->tcp_ka_abort_thres; 449 return (sizeof (int)); 450 case TCP_CONGESTION: { 451 size_t len = strlcpy((char *)ptr, CC_ALGO(tcp)->name, 452 CC_ALGO_NAME_MAX); 453 if (len >= CC_ALGO_NAME_MAX) 454 return (-1); 455 return (len + 1); 456 } 457 case TCP_CORK: 458 *i1 = tcp->tcp_cork; 459 return (sizeof (int)); 460 case TCP_QUICKACK: 461 *i1 = tcp->tcp_quickack; 462 return (sizeof (int)); 463 case TCP_RTO_INITIAL: 464 *i1 = tcp->tcp_rto_initial; 465 return (sizeof (uint32_t)); 466 case TCP_RTO_MIN: 467 *i1 = tcp->tcp_rto_min; 468 return (sizeof (uint32_t)); 469 case TCP_RTO_MAX: 470 *i1 = tcp->tcp_rto_max; 471 return (sizeof (uint32_t)); 472 case TCP_LINGER2: 473 *i1 = tcp->tcp_fin_wait_2_flush_interval / SECONDS; 474 return (sizeof (int)); 475 } 476 break; 477 case IPPROTO_IP: 478 if (connp->conn_family != AF_INET) 479 return (-1); 480 switch (name) { 481 case IP_OPTIONS: 482 case T_IP_OPTIONS: 483 /* Caller ensures enough space */ 484 return (ip_opt_get_user(connp, ptr)); 485 default: 486 break; 487 } 488 break; 489 490 case IPPROTO_IPV6: 491 /* 492 * IPPROTO_IPV6 options are only supported for sockets 493 * that are using IPv6 on the wire. 494 */ 495 if (connp->conn_ipversion != IPV6_VERSION) { 496 return (-1); 497 } 498 switch (name) { 499 case IPV6_PATHMTU: 500 if (tcp->tcp_state < TCPS_ESTABLISHED) 501 return (-1); 502 break; 503 } 504 break; 505 } 506 mutex_enter(&connp->conn_lock); 507 retval = conn_opt_get(&coas, level, name, ptr); 508 mutex_exit(&connp->conn_lock); 509 return (retval); 510 } 511 512 /* 513 * We declare as 'int' rather than 'void' to satisfy pfi_t arg requirements. 514 * Parameters are assumed to be verified by the caller. 515 */ 516 /* ARGSUSED */ 517 int 518 tcp_opt_set(conn_t *connp, uint_t optset_context, int level, int name, 519 uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 520 void *thisdg_attrs, cred_t *cr) 521 { 522 tcp_t *tcp = connp->conn_tcp; 523 int *i1 = (int *)invalp; 524 boolean_t onoff = (*i1 == 0) ? 0 : 1; 525 boolean_t checkonly; 526 int reterr; 527 tcp_stack_t *tcps = tcp->tcp_tcps; 528 conn_opt_arg_t coas; 529 uint32_t val = *((uint32_t *)invalp); 530 531 coas.coa_connp = connp; 532 coas.coa_ixa = connp->conn_ixa; 533 coas.coa_ipp = &connp->conn_xmit_ipp; 534 coas.coa_ancillary = B_FALSE; 535 coas.coa_changed = 0; 536 537 switch (optset_context) { 538 case SETFN_OPTCOM_CHECKONLY: 539 checkonly = B_TRUE; 540 /* 541 * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 542 * inlen != 0 implies value supplied and 543 * we have to "pretend" to set it. 544 * inlen == 0 implies that there is no 545 * value part in T_CHECK request and just validation 546 * done elsewhere should be enough, we just return here. 547 */ 548 if (inlen == 0) { 549 *outlenp = 0; 550 return (0); 551 } 552 break; 553 case SETFN_OPTCOM_NEGOTIATE: 554 checkonly = B_FALSE; 555 break; 556 case SETFN_UD_NEGOTIATE: /* error on conn-oriented transports ? */ 557 case SETFN_CONN_NEGOTIATE: 558 checkonly = B_FALSE; 559 /* 560 * Negotiating local and "association-related" options 561 * from other (T_CONN_REQ, T_CONN_RES,T_UNITDATA_REQ) 562 * primitives is allowed by XTI, but we choose 563 * to not implement this style negotiation for Internet 564 * protocols (We interpret it is a must for OSI world but 565 * optional for Internet protocols) for all options. 566 * [ Will do only for the few options that enable test 567 * suites that our XTI implementation of this feature 568 * works for transports that do allow it ] 569 */ 570 if (!tcp_allow_connopt_set(level, name)) { 571 *outlenp = 0; 572 return (EINVAL); 573 } 574 break; 575 default: 576 /* 577 * We should never get here 578 */ 579 *outlenp = 0; 580 return (EINVAL); 581 } 582 583 ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 584 (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 585 586 /* 587 * For TCP, we should have no ancillary data sent down 588 * (sendmsg isn't supported for SOCK_STREAM), so thisdg_attrs 589 * has to be zero. 590 */ 591 ASSERT(thisdg_attrs == NULL); 592 593 /* 594 * For fixed length options, no sanity check 595 * of passed in length is done. It is assumed *_optcom_req() 596 * routines do the right thing. 597 */ 598 switch (level) { 599 case SOL_SOCKET: 600 switch (name) { 601 case SO_KEEPALIVE: 602 if (checkonly) { 603 /* check only case */ 604 break; 605 } 606 607 if (!onoff) { 608 if (connp->conn_keepalive) { 609 if (tcp->tcp_ka_tid != 0) { 610 (void) TCP_TIMER_CANCEL(tcp, 611 tcp->tcp_ka_tid); 612 tcp->tcp_ka_tid = 0; 613 } 614 connp->conn_keepalive = 0; 615 } 616 break; 617 } 618 if (!connp->conn_keepalive) { 619 /* Crank up the keepalive timer */ 620 tcp->tcp_ka_last_intrvl = 0; 621 tcp->tcp_ka_tid = TCP_TIMER(tcp, 622 tcp_keepalive_timer, tcp->tcp_ka_interval); 623 connp->conn_keepalive = 1; 624 } 625 break; 626 case SO_SNDBUF: { 627 if (*i1 > tcps->tcps_max_buf) { 628 *outlenp = 0; 629 return (ENOBUFS); 630 } 631 if (checkonly) 632 break; 633 634 connp->conn_sndbuf = *i1; 635 if (tcps->tcps_snd_lowat_fraction != 0) { 636 connp->conn_sndlowat = connp->conn_sndbuf / 637 tcps->tcps_snd_lowat_fraction; 638 } 639 (void) tcp_maxpsz_set(tcp, B_TRUE); 640 /* 641 * If we are flow-controlled, recheck the condition. 642 * There are apps that increase SO_SNDBUF size when 643 * flow-controlled (EWOULDBLOCK), and expect the flow 644 * control condition to be lifted right away. 645 */ 646 mutex_enter(&tcp->tcp_non_sq_lock); 647 if (tcp->tcp_flow_stopped && 648 TCP_UNSENT_BYTES(tcp) < connp->conn_sndbuf) { 649 tcp_clrqfull(tcp); 650 } 651 mutex_exit(&tcp->tcp_non_sq_lock); 652 *outlenp = inlen; 653 return (0); 654 } 655 case SO_RCVBUF: 656 if (*i1 > tcps->tcps_max_buf) { 657 *outlenp = 0; 658 return (ENOBUFS); 659 } 660 /* Silently ignore zero */ 661 if (!checkonly && *i1 != 0) { 662 *i1 = MSS_ROUNDUP(*i1, tcp->tcp_mss); 663 (void) tcp_rwnd_set(tcp, *i1); 664 } 665 /* 666 * XXX should we return the rwnd here 667 * and tcp_opt_get ? 668 */ 669 *outlenp = inlen; 670 return (0); 671 case SO_SND_COPYAVOID: 672 if (!checkonly) { 673 if (tcp->tcp_loopback || 674 (onoff != 1) || !tcp_zcopy_check(tcp)) { 675 *outlenp = 0; 676 return (EOPNOTSUPP); 677 } 678 tcp->tcp_snd_zcopy_aware = 1; 679 } 680 *outlenp = inlen; 681 return (0); 682 } 683 break; 684 case IPPROTO_TCP: 685 switch (name) { 686 case TCP_NODELAY: 687 if (!checkonly) 688 tcp->tcp_naglim = *i1 ? 1 : tcp->tcp_mss; 689 break; 690 case TCP_NOTIFY_THRESHOLD: 691 if (!checkonly) 692 tcp->tcp_first_timer_threshold = *i1; 693 break; 694 case TCP_ABORT_THRESHOLD: 695 if (!checkonly) 696 tcp->tcp_second_timer_threshold = *i1; 697 break; 698 case TCP_CONN_NOTIFY_THRESHOLD: 699 if (!checkonly) 700 tcp->tcp_first_ctimer_threshold = *i1; 701 break; 702 case TCP_CONN_ABORT_THRESHOLD: 703 if (!checkonly) 704 tcp->tcp_second_ctimer_threshold = *i1; 705 break; 706 case TCP_RECVDSTADDR: 707 if (tcp->tcp_state > TCPS_LISTEN) { 708 *outlenp = 0; 709 return (EOPNOTSUPP); 710 } 711 /* Setting done in conn_opt_set */ 712 break; 713 case TCP_INIT_CWND: 714 if (checkonly) 715 break; 716 717 /* 718 * Only allow socket with network configuration 719 * privilege to set the initial cwnd to be larger 720 * than allowed by RFC 3390. 721 */ 722 if (val > MIN(4, MAX(2, 4380 / tcp->tcp_mss))) { 723 if ((reterr = secpolicy_ip_config(cr, B_TRUE)) 724 != 0) { 725 *outlenp = 0; 726 return (reterr); 727 } 728 if (val > tcp_max_init_cwnd) { 729 *outlenp = 0; 730 return (EINVAL); 731 } 732 } 733 734 tcp->tcp_init_cwnd = val; 735 736 /* 737 * If the socket is connected, AND no outbound data 738 * has been sent, reset the actual cwnd values. 739 */ 740 if (tcp->tcp_state == TCPS_ESTABLISHED && 741 tcp->tcp_iss == tcp->tcp_snxt - 1) { 742 tcp->tcp_cwnd = 743 MIN(tcp->tcp_rwnd, val * tcp->tcp_mss); 744 } 745 break; 746 747 /* 748 * TCP_KEEPIDLE is in seconds but TCP_KEEPALIVE_THRESHOLD 749 * is in milliseconds. TCP_KEEPIDLE is introduced for 750 * compatibility with other Unix flavors. 751 * We can fall through TCP_KEEPALIVE_THRESHOLD logic after 752 * converting the input to milliseconds. 753 */ 754 case TCP_KEEPIDLE: 755 *i1 *= 1000; 756 /* FALLTHRU */ 757 758 case TCP_KEEPALIVE_THRESHOLD: 759 if (checkonly) 760 break; 761 762 if (*i1 < tcps->tcps_keepalive_interval_low || 763 *i1 > tcps->tcps_keepalive_interval_high) { 764 *outlenp = 0; 765 return (EINVAL); 766 } 767 if (*i1 != tcp->tcp_ka_interval) { 768 tcp->tcp_ka_interval = *i1; 769 /* 770 * Check if we need to restart the 771 * keepalive timer. 772 */ 773 if (tcp->tcp_ka_tid != 0) { 774 ASSERT(connp->conn_keepalive); 775 (void) TCP_TIMER_CANCEL(tcp, 776 tcp->tcp_ka_tid); 777 tcp->tcp_ka_last_intrvl = 0; 778 tcp->tcp_ka_tid = TCP_TIMER(tcp, 779 tcp_keepalive_timer, 780 tcp->tcp_ka_interval); 781 } 782 } 783 break; 784 785 /* 786 * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt. 787 * So setting TCP_KEEPCNT or TCP_KEEPINTVL can affect all the 788 * three members - tcp_ka_abort_thres, tcp_ka_rinterval and 789 * tcp_ka_cnt. 790 */ 791 case TCP_KEEPCNT: 792 if (checkonly) 793 break; 794 795 if (*i1 == 0) { 796 return (EINVAL); 797 } else if (tcp->tcp_ka_rinterval == 0) { 798 /* 799 * When TCP_KEEPCNT is specified without first 800 * specifying a TCP_KEEPINTVL, we infer an 801 * interval based on a tunable specific to our 802 * stack: the tcp_keepalive_abort_interval. 803 * (Or the TCP_KEEPALIVE_ABORT_THRESHOLD, in 804 * the unlikely event that that has been set.) 805 * Given the abort interval's default value of 806 * 480 seconds, low TCP_KEEPCNT values can 807 * result in intervals that exceed the default 808 * maximum RTO of 60 seconds. Rather than 809 * fail in these cases, we (implicitly) clamp 810 * the interval at the maximum RTO; if the 811 * TCP_KEEPCNT is shortly followed by a 812 * TCP_KEEPINTVL (as we expect), the abort 813 * threshold will be recalculated correctly -- 814 * and if a TCP_KEEPINTVL is not forthcoming, 815 * keep-alive will at least operate reasonably 816 * given the underconfigured state. 817 */ 818 uint32_t interval; 819 820 interval = tcp->tcp_ka_abort_thres / *i1; 821 822 if (interval < tcp->tcp_rto_min) 823 interval = tcp->tcp_rto_min; 824 825 if (interval > tcp->tcp_rto_max) 826 interval = tcp->tcp_rto_max; 827 828 tcp->tcp_ka_rinterval = interval; 829 } else { 830 if ((*i1 * tcp->tcp_ka_rinterval) < 831 tcps->tcps_keepalive_abort_interval_low || 832 (*i1 * tcp->tcp_ka_rinterval) > 833 tcps->tcps_keepalive_abort_interval_high) 834 return (EINVAL); 835 tcp->tcp_ka_abort_thres = 836 (*i1 * tcp->tcp_ka_rinterval); 837 } 838 tcp->tcp_ka_cnt = *i1; 839 break; 840 case TCP_KEEPINTVL: 841 /* 842 * TCP_KEEPINTVL is specified in seconds, but 843 * tcp_ka_rinterval is in milliseconds. 844 */ 845 846 if (checkonly) 847 break; 848 849 if ((*i1 * 1000) < tcp->tcp_rto_min || 850 (*i1 * 1000) > tcp->tcp_rto_max) 851 return (EINVAL); 852 853 if (tcp->tcp_ka_cnt == 0) { 854 tcp->tcp_ka_cnt = 855 tcp->tcp_ka_abort_thres / (*i1 * 1000); 856 } else { 857 if ((*i1 * tcp->tcp_ka_cnt * 1000) < 858 tcps->tcps_keepalive_abort_interval_low || 859 (*i1 * tcp->tcp_ka_cnt * 1000) > 860 tcps->tcps_keepalive_abort_interval_high) 861 return (EINVAL); 862 tcp->tcp_ka_abort_thres = 863 (*i1 * tcp->tcp_ka_cnt * 1000); 864 } 865 tcp->tcp_ka_rinterval = *i1 * 1000; 866 break; 867 case TCP_KEEPALIVE_ABORT_THRESHOLD: 868 if (!checkonly) { 869 if (*i1 < 870 tcps->tcps_keepalive_abort_interval_low || 871 *i1 > 872 tcps->tcps_keepalive_abort_interval_high) { 873 *outlenp = 0; 874 return (EINVAL); 875 } 876 tcp->tcp_ka_abort_thres = *i1; 877 tcp->tcp_ka_cnt = 0; 878 tcp->tcp_ka_rinterval = 0; 879 } 880 break; 881 case TCP_CONGESTION: { 882 struct cc_algo *algo; 883 884 if (checkonly) { 885 break; 886 } 887 888 /* 889 * Make sure the string is NUL-terminated. Some 890 * consumers pass only the number of characters 891 * in the string, and don't include the NUL 892 * terminator, so we set it for them. 893 */ 894 if (inlen < CC_ALGO_NAME_MAX) { 895 invalp[inlen] = '\0'; 896 } 897 invalp[CC_ALGO_NAME_MAX - 1] = '\0'; 898 899 if ((algo = cc_load_algo((char *)invalp)) == NULL) { 900 return (ENOENT); 901 } 902 903 if (CC_ALGO(tcp)->cb_destroy != NULL) { 904 CC_ALGO(tcp)->cb_destroy(&tcp->tcp_ccv); 905 } 906 907 CC_DATA(tcp) = NULL; 908 CC_ALGO(tcp) = algo; 909 910 if (CC_ALGO(tcp)->cb_init != NULL) { 911 VERIFY0(CC_ALGO(tcp)->cb_init(&tcp->tcp_ccv)); 912 } 913 914 break; 915 } 916 case TCP_CORK: 917 if (!checkonly) { 918 /* 919 * if tcp->tcp_cork was set and is now 920 * being unset, we have to make sure that 921 * the remaining data gets sent out. Also 922 * unset tcp->tcp_cork so that tcp_wput_data() 923 * can send data even if it is less than mss 924 */ 925 if (tcp->tcp_cork && onoff == 0 && 926 tcp->tcp_unsent > 0) { 927 tcp->tcp_cork = B_FALSE; 928 tcp_wput_data(tcp, NULL, B_FALSE); 929 } 930 tcp->tcp_cork = onoff; 931 } 932 break; 933 case TCP_QUICKACK: 934 if (!checkonly) { 935 tcp->tcp_quickack = onoff; 936 } 937 break; 938 case TCP_RTO_INITIAL: 939 if (checkonly || val == 0) 940 break; 941 942 /* 943 * Sanity checks 944 * 945 * The initial RTO should be bounded by the minimum 946 * and maximum RTO. And it should also be smaller 947 * than the connect attempt abort timeout. Otherwise, 948 * the connection won't be aborted in a period 949 * reasonably close to that timeout. 950 */ 951 if (val < tcp->tcp_rto_min || val > tcp->tcp_rto_max || 952 val > tcp->tcp_second_ctimer_threshold || 953 val < tcps->tcps_rexmit_interval_initial_low || 954 val > tcps->tcps_rexmit_interval_initial_high) { 955 *outlenp = 0; 956 return (EINVAL); 957 } 958 tcp->tcp_rto_initial = val; 959 960 /* 961 * If TCP has not sent anything, need to re-calculate 962 * tcp_rto. Otherwise, this option change does not 963 * really affect anything. 964 */ 965 if (tcp->tcp_state >= TCPS_SYN_SENT) 966 break; 967 968 tcp->tcp_rtt_sa = MSEC2NSEC(tcp->tcp_rto_initial) << 2; 969 tcp->tcp_rtt_sd = MSEC2NSEC(tcp->tcp_rto_initial) >> 1; 970 tcp->tcp_rto = tcp_calculate_rto(tcp, tcps, 971 tcps->tcps_conn_grace_period); 972 break; 973 case TCP_RTO_MIN: 974 if (checkonly || val == 0) 975 break; 976 977 if (val < tcps->tcps_rexmit_interval_min_low || 978 val > tcps->tcps_rexmit_interval_min_high || 979 val > tcp->tcp_rto_max) { 980 *outlenp = 0; 981 return (EINVAL); 982 } 983 tcp->tcp_rto_min = val; 984 if (tcp->tcp_rto < val) 985 tcp->tcp_rto = val; 986 break; 987 case TCP_RTO_MAX: 988 if (checkonly || val == 0) 989 break; 990 991 /* 992 * Sanity checks 993 * 994 * The maximum RTO should not be larger than the 995 * connection abort timeout. Otherwise, the 996 * connection won't be aborted in a period reasonably 997 * close to that timeout. 998 */ 999 if (val < tcps->tcps_rexmit_interval_max_low || 1000 val > tcps->tcps_rexmit_interval_max_high || 1001 val < tcp->tcp_rto_min || 1002 val > tcp->tcp_second_timer_threshold) { 1003 *outlenp = 0; 1004 return (EINVAL); 1005 } 1006 tcp->tcp_rto_max = val; 1007 if (tcp->tcp_rto > val) 1008 tcp->tcp_rto = val; 1009 break; 1010 case TCP_LINGER2: 1011 if (checkonly || *i1 == 0) 1012 break; 1013 1014 /* 1015 * Note that the option value's unit is second. And 1016 * the value should be bigger than the private 1017 * parameter tcp_fin_wait_2_flush_interval's lower 1018 * bound and smaller than the current value of that 1019 * parameter. It should be smaller than the current 1020 * value to avoid an app setting TCP_LINGER2 to a big 1021 * value, causing resource to be held up too long in 1022 * FIN-WAIT-2 state. 1023 */ 1024 if (*i1 < 0 || 1025 tcps->tcps_fin_wait_2_flush_interval_low/SECONDS > 1026 *i1 || 1027 tcps->tcps_fin_wait_2_flush_interval/SECONDS < 1028 *i1) { 1029 *outlenp = 0; 1030 return (EINVAL); 1031 } 1032 tcp->tcp_fin_wait_2_flush_interval = *i1 * SECONDS; 1033 break; 1034 default: 1035 break; 1036 } 1037 break; 1038 case IPPROTO_IP: 1039 if (connp->conn_family != AF_INET) { 1040 *outlenp = 0; 1041 return (EINVAL); 1042 } 1043 switch (name) { 1044 case IP_SEC_OPT: 1045 /* 1046 * We should not allow policy setting after 1047 * we start listening for connections. 1048 */ 1049 if (tcp->tcp_state == TCPS_LISTEN) { 1050 return (EINVAL); 1051 } 1052 break; 1053 case IP_RECVTOS: 1054 if (!checkonly) { 1055 /* 1056 * Force it to be sent up with the next msg 1057 * by setting it to a value which cannot 1058 * appear in a packet (TOS is only 8-bits) 1059 */ 1060 tcp->tcp_recvtos = 0xffffffffU; 1061 } 1062 break; 1063 } 1064 break; 1065 case IPPROTO_IPV6: 1066 /* 1067 * IPPROTO_IPV6 options are only supported for sockets 1068 * that are using IPv6 on the wire. 1069 */ 1070 if (connp->conn_ipversion != IPV6_VERSION) { 1071 *outlenp = 0; 1072 return (EINVAL); 1073 } 1074 1075 switch (name) { 1076 case IPV6_RECVPKTINFO: 1077 if (!checkonly) { 1078 /* Force it to be sent up with the next msg */ 1079 tcp->tcp_recvifindex = 0; 1080 } 1081 break; 1082 case IPV6_RECVTCLASS: 1083 if (!checkonly) { 1084 /* Force it to be sent up with the next msg */ 1085 tcp->tcp_recvtclass = 0xffffffffU; 1086 } 1087 break; 1088 case IPV6_RECVHOPLIMIT: 1089 if (!checkonly) { 1090 /* Force it to be sent up with the next msg */ 1091 tcp->tcp_recvhops = 0xffffffffU; 1092 } 1093 break; 1094 case IPV6_PKTINFO: 1095 /* This is an extra check for TCP */ 1096 if (inlen == sizeof (struct in6_pktinfo)) { 1097 struct in6_pktinfo *pkti; 1098 1099 pkti = (struct in6_pktinfo *)invalp; 1100 /* 1101 * RFC 3542 states that ipi6_addr must be 1102 * the unspecified address when setting the 1103 * IPV6_PKTINFO sticky socket option on a 1104 * TCP socket. 1105 */ 1106 if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr)) 1107 return (EINVAL); 1108 } 1109 break; 1110 case IPV6_SEC_OPT: 1111 /* 1112 * We should not allow policy setting after 1113 * we start listening for connections. 1114 */ 1115 if (tcp->tcp_state == TCPS_LISTEN) { 1116 return (EINVAL); 1117 } 1118 break; 1119 } 1120 break; 1121 } 1122 reterr = conn_opt_set(&coas, level, name, inlen, invalp, 1123 checkonly, cr); 1124 if (reterr != 0) { 1125 *outlenp = 0; 1126 return (reterr); 1127 } 1128 1129 /* 1130 * Common case of OK return with outval same as inval 1131 */ 1132 if (invalp != outvalp) { 1133 /* don't trust bcopy for identical src/dst */ 1134 (void) bcopy(invalp, outvalp, inlen); 1135 } 1136 *outlenp = inlen; 1137 1138 if (coas.coa_changed & COA_HEADER_CHANGED) { 1139 /* If we are connected we rebuilt the headers */ 1140 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) && 1141 !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) { 1142 reterr = tcp_build_hdrs(tcp); 1143 if (reterr != 0) 1144 return (reterr); 1145 } 1146 } 1147 if (coas.coa_changed & COA_ROUTE_CHANGED) { 1148 in6_addr_t nexthop; 1149 1150 /* 1151 * If we are connected we re-cache the information. 1152 * We ignore errors to preserve BSD behavior. 1153 * Note that we don't redo IPsec policy lookup here 1154 * since the final destination (or source) didn't change. 1155 */ 1156 ip_attr_nexthop(&connp->conn_xmit_ipp, connp->conn_ixa, 1157 &connp->conn_faddr_v6, &nexthop); 1158 1159 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) && 1160 !IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_faddr_v6)) { 1161 (void) ip_attr_connect(connp, connp->conn_ixa, 1162 &connp->conn_laddr_v6, &connp->conn_faddr_v6, 1163 &nexthop, connp->conn_fport, NULL, NULL, 1164 IPDF_VERIFY_DST); 1165 } 1166 } 1167 if ((coas.coa_changed & COA_SNDBUF_CHANGED) && !IPCL_IS_NONSTR(connp)) { 1168 connp->conn_wq->q_hiwat = connp->conn_sndbuf; 1169 } 1170 if (coas.coa_changed & COA_WROFF_CHANGED) { 1171 connp->conn_wroff = connp->conn_ht_iphc_allocated + 1172 tcps->tcps_wroff_xtra; 1173 (void) proto_set_tx_wroff(connp->conn_rq, connp, 1174 connp->conn_wroff); 1175 } 1176 if (coas.coa_changed & COA_OOBINLINE_CHANGED) { 1177 if (IPCL_IS_NONSTR(connp)) 1178 proto_set_rx_oob_opt(connp, onoff); 1179 } 1180 return (0); 1181 } 1182