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