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