Print this page
13175 Add support for IP_RECVTOS
13182 CMSG_ macros should have man pages
Change-ID: I784aa36cfd3c17e3cccbf1fd329fa7e69b663ef9
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/inet/ip/conn_opt.c
+++ new/usr/src/uts/common/inet/ip/conn_opt.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
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
24 25 */
25 26 /* Copyright (c) 1990 Mentat Inc. */
26 27
27 28 #include <sys/types.h>
28 29 #include <sys/stream.h>
29 30 #include <sys/strsun.h>
30 31 #define _SUN_TPI_VERSION 2
31 32 #include <sys/tihdr.h>
32 33 #include <sys/xti_inet.h>
33 34 #include <sys/ucred.h>
34 35 #include <sys/zone.h>
35 36 #include <sys/ddi.h>
36 37 #include <sys/sunddi.h>
37 38 #include <sys/cmn_err.h>
38 39 #include <sys/debug.h>
39 40 #include <sys/atomic.h>
40 41 #include <sys/policy.h>
41 42
42 43 #include <sys/systm.h>
43 44 #include <sys/param.h>
44 45 #include <sys/kmem.h>
45 46 #include <sys/sdt.h>
46 47 #include <sys/socket.h>
47 48 #include <sys/ethernet.h>
48 49 #include <sys/mac.h>
49 50 #include <net/if.h>
50 51 #include <net/if_types.h>
51 52 #include <net/if_arp.h>
52 53 #include <net/route.h>
53 54 #include <sys/sockio.h>
54 55 #include <netinet/in.h>
55 56 #include <net/if_dl.h>
56 57
57 58 #include <inet/common.h>
58 59 #include <inet/mi.h>
59 60 #include <inet/mib2.h>
60 61 #include <inet/nd.h>
61 62 #include <inet/arp.h>
62 63 #include <inet/snmpcom.h>
63 64 #include <inet/kstatcom.h>
64 65
65 66 #include <netinet/igmp_var.h>
66 67 #include <netinet/ip6.h>
67 68 #include <netinet/icmp6.h>
68 69 #include <netinet/sctp.h>
69 70
70 71 #include <inet/ip.h>
71 72 #include <inet/ip_impl.h>
72 73 #include <inet/ip6.h>
73 74 #include <inet/ip6_asp.h>
74 75 #include <inet/tcp.h>
75 76 #include <inet/ip_multi.h>
76 77 #include <inet/ip_if.h>
77 78 #include <inet/ip_ire.h>
78 79 #include <inet/ip_ftable.h>
79 80 #include <inet/ip_rts.h>
80 81 #include <inet/optcom.h>
81 82 #include <inet/ip_ndp.h>
82 83 #include <inet/ip_listutils.h>
83 84 #include <netinet/igmp.h>
84 85 #include <netinet/ip_mroute.h>
85 86 #include <netinet/udp.h>
86 87 #include <inet/ipp_common.h>
87 88
88 89 #include <net/pfkeyv2.h>
89 90 #include <inet/sadb.h>
90 91 #include <inet/ipsec_impl.h>
91 92 #include <inet/ipdrop.h>
92 93 #include <inet/ip_netinfo.h>
93 94
94 95 #include <inet/ipclassifier.h>
95 96 #include <inet/sctp_ip.h>
96 97 #include <inet/sctp/sctp_impl.h>
97 98 #include <inet/udp_impl.h>
98 99 #include <sys/sunddi.h>
99 100
100 101 #include <sys/tsol/label.h>
101 102 #include <sys/tsol/tnet.h>
102 103
103 104 /*
104 105 * Return how much size is needed for the different ancillary data items
105 106 */
106 107 uint_t
107 108 conn_recvancillary_size(conn_t *connp, crb_t recv_ancillary,
108 109 ip_recv_attr_t *ira, mblk_t *mp, ip_pkt_t *ipp)
109 110 {
110 111 uint_t ancil_size;
111 112 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
112 113
113 114 /*
114 115 * If IP_RECVDSTADDR is set we include the destination IP
115 116 * address as an option. With IP_RECVOPTS we include all
116 117 * the IP options.
117 118 */
118 119 ancil_size = 0;
119 120 if (recv_ancillary.crb_recvdstaddr &&
120 121 (ira->ira_flags & IRAF_IS_IPV4)) {
121 122 ancil_size += sizeof (struct T_opthdr) +
122 123 sizeof (struct in_addr);
123 124 IP_STAT(ipst, conn_in_recvdstaddr);
124 125 }
125 126
126 127 /*
127 128 * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
128 129 * are different
129 130 */
130 131 if (recv_ancillary.crb_ip_recvpktinfo &&
131 132 connp->conn_family == AF_INET) {
132 133 ancil_size += sizeof (struct T_opthdr) +
133 134 sizeof (struct in_pktinfo);
134 135 IP_STAT(ipst, conn_in_recvpktinfo);
135 136 }
136 137
137 138 if ((recv_ancillary.crb_recvopts) &&
138 139 (ipp->ipp_fields & IPPF_IPV4_OPTIONS)) {
139 140 ancil_size += sizeof (struct T_opthdr) +
140 141 ipp->ipp_ipv4_options_len;
141 142 IP_STAT(ipst, conn_in_recvopts);
142 143 }
143 144
144 145 if (recv_ancillary.crb_recvslla) {
145 146 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
146 147 ill_t *ill;
147 148
148 149 /* Make sure ira_l2src is setup if not already */
149 150 if (!(ira->ira_flags & IRAF_L2SRC_SET)) {
150 151 ill = ill_lookup_on_ifindex(ira->ira_rifindex, B_FALSE,
151 152 ipst);
152 153 if (ill != NULL) {
153 154 ip_setl2src(mp, ira, ill);
154 155 ill_refrele(ill);
155 156 }
156 157 }
157 158 ancil_size += sizeof (struct T_opthdr) +
158 159 sizeof (struct sockaddr_dl);
159 160 IP_STAT(ipst, conn_in_recvslla);
160 161 }
161 162
162 163 if (recv_ancillary.crb_recvif) {
163 164 ancil_size += sizeof (struct T_opthdr) + sizeof (uint_t);
164 165 IP_STAT(ipst, conn_in_recvif);
165 166 }
166 167
167 168 /*
168 169 * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
169 170 * are different
170 171 */
171 172 if (recv_ancillary.crb_ip_recvpktinfo &&
172 173 connp->conn_family == AF_INET6) {
173 174 ancil_size += sizeof (struct T_opthdr) +
174 175 sizeof (struct in6_pktinfo);
175 176 IP_STAT(ipst, conn_in_recvpktinfo);
176 177 }
177 178
178 179 if (recv_ancillary.crb_ipv6_recvhoplimit) {
179 180 ancil_size += sizeof (struct T_opthdr) + sizeof (int);
180 181 IP_STAT(ipst, conn_in_recvhoplimit);
181 182 }
182 183
183 184 if (recv_ancillary.crb_ipv6_recvtclass) {
184 185 ancil_size += sizeof (struct T_opthdr) + sizeof (int);
185 186 IP_STAT(ipst, conn_in_recvtclass);
186 187 }
187 188
188 189 if (recv_ancillary.crb_ipv6_recvhopopts &&
189 190 (ipp->ipp_fields & IPPF_HOPOPTS)) {
190 191 ancil_size += sizeof (struct T_opthdr) + ipp->ipp_hopoptslen;
191 192 IP_STAT(ipst, conn_in_recvhopopts);
192 193 }
193 194 /*
194 195 * To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
195 196 * and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
196 197 * options that appear before a routing header.
197 198 * We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
198 199 */
199 200 if (ipp->ipp_fields & IPPF_RTHDRDSTOPTS) {
200 201 if (recv_ancillary.crb_ipv6_recvrthdrdstopts ||
201 202 (recv_ancillary.crb_ipv6_recvdstopts &&
202 203 recv_ancillary.crb_ipv6_recvrthdr)) {
203 204 ancil_size += sizeof (struct T_opthdr) +
204 205 ipp->ipp_rthdrdstoptslen;
205 206 IP_STAT(ipst, conn_in_recvrthdrdstopts);
206 207 }
207 208 }
208 209 if ((recv_ancillary.crb_ipv6_recvrthdr) &&
209 210 (ipp->ipp_fields & IPPF_RTHDR)) {
210 211 ancil_size += sizeof (struct T_opthdr) + ipp->ipp_rthdrlen;
211 212 IP_STAT(ipst, conn_in_recvrthdr);
212 213 }
213 214 if ((recv_ancillary.crb_ipv6_recvdstopts ||
214 215 recv_ancillary.crb_old_ipv6_recvdstopts) &&
215 216 (ipp->ipp_fields & IPPF_DSTOPTS)) {
216 217 ancil_size += sizeof (struct T_opthdr) + ipp->ipp_dstoptslen;
217 218 IP_STAT(ipst, conn_in_recvdstopts);
218 219 }
219 220 if (recv_ancillary.crb_recvucred && ira->ira_cred != NULL) {
220 221 ancil_size += sizeof (struct T_opthdr) +
221 222 ucredminsize(ira->ira_cred);
222 223 IP_STAT(ipst, conn_in_recvucred);
223 224 }
224 225
225 226 /*
226 227 * If SO_TIMESTAMP is set allocate the appropriate sized
227 228 * buffer. Since gethrestime() expects a pointer aligned
↓ open down ↓ |
194 lines elided |
↑ open up ↑ |
228 229 * argument, we allocate space necessary for extra
229 230 * alignment (even though it might not be used).
230 231 */
231 232 if (recv_ancillary.crb_timestamp) {
232 233 ancil_size += sizeof (struct T_opthdr) +
233 234 sizeof (timestruc_t) + _POINTER_ALIGNMENT;
234 235 IP_STAT(ipst, conn_in_timestamp);
235 236 }
236 237
237 238 /*
239 + * If IP_RECVTOS is set allocate the appropriately sized buffer
240 + */
241 + if (recv_ancillary.crb_recvtos &&
242 + (ira->ira_flags & IRAF_IS_IPV4)) {
243 + ancil_size += sizeof (struct T_opthdr) +
244 + P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
245 + IP_STAT(ipst, conn_in_recvtos);
246 + }
247 +
248 + /*
238 249 * If IP_RECVTTL is set allocate the appropriate sized buffer
239 250 */
240 251 if (recv_ancillary.crb_recvttl &&
241 252 (ira->ira_flags & IRAF_IS_IPV4)) {
242 - ancil_size += sizeof (struct T_opthdr) + sizeof (uint8_t);
253 + ancil_size += sizeof (struct T_opthdr) +
254 + P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
243 255 IP_STAT(ipst, conn_in_recvttl);
244 256 }
245 257
246 258 return (ancil_size);
247 259 }
248 260
249 261 /*
250 262 * Lay down the ancillary data items at "ancil_buf".
251 263 * Assumes caller has used conn_recvancillary_size to allocate a sufficiently
252 264 * large buffer - ancil_size.
253 265 */
254 266 void
255 267 conn_recvancillary_add(conn_t *connp, crb_t recv_ancillary,
256 268 ip_recv_attr_t *ira, ip_pkt_t *ipp, uchar_t *ancil_buf, uint_t ancil_size)
257 269 {
258 270 /*
259 271 * Copy in destination address before options to avoid
260 272 * any padding issues.
261 273 */
262 274 if (recv_ancillary.crb_recvdstaddr &&
263 275 (ira->ira_flags & IRAF_IS_IPV4)) {
264 276 struct T_opthdr *toh;
265 277 ipaddr_t *dstptr;
266 278
267 279 toh = (struct T_opthdr *)ancil_buf;
268 280 toh->level = IPPROTO_IP;
269 281 toh->name = IP_RECVDSTADDR;
270 282 toh->len = sizeof (struct T_opthdr) + sizeof (ipaddr_t);
271 283 toh->status = 0;
272 284 ancil_buf += sizeof (struct T_opthdr);
273 285 dstptr = (ipaddr_t *)ancil_buf;
274 286 *dstptr = ipp->ipp_addr_v4;
275 287 ancil_buf += sizeof (ipaddr_t);
276 288 ancil_size -= toh->len;
277 289 }
278 290
279 291 /*
280 292 * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
281 293 * are different
282 294 */
283 295 if (recv_ancillary.crb_ip_recvpktinfo &&
284 296 connp->conn_family == AF_INET) {
285 297 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
286 298 struct T_opthdr *toh;
287 299 struct in_pktinfo *pktinfop;
288 300 ill_t *ill;
289 301 ipif_t *ipif;
290 302
291 303 toh = (struct T_opthdr *)ancil_buf;
292 304 toh->level = IPPROTO_IP;
293 305 toh->name = IP_PKTINFO;
294 306 toh->len = sizeof (struct T_opthdr) + sizeof (*pktinfop);
295 307 toh->status = 0;
296 308 ancil_buf += sizeof (struct T_opthdr);
297 309 pktinfop = (struct in_pktinfo *)ancil_buf;
298 310
299 311 pktinfop->ipi_ifindex = ira->ira_ruifindex;
300 312 pktinfop->ipi_spec_dst.s_addr = INADDR_ANY;
301 313
302 314 /* Find a good address to report */
303 315 ill = ill_lookup_on_ifindex(ira->ira_ruifindex, B_FALSE, ipst);
304 316 if (ill != NULL) {
305 317 ipif = ipif_good_addr(ill, IPCL_ZONEID(connp));
306 318 if (ipif != NULL) {
307 319 pktinfop->ipi_spec_dst.s_addr =
308 320 ipif->ipif_lcl_addr;
309 321 ipif_refrele(ipif);
310 322 }
311 323 ill_refrele(ill);
312 324 }
313 325 pktinfop->ipi_addr.s_addr = ipp->ipp_addr_v4;
314 326 ancil_buf += sizeof (struct in_pktinfo);
315 327 ancil_size -= toh->len;
316 328 }
317 329
318 330 if ((recv_ancillary.crb_recvopts) &&
319 331 (ipp->ipp_fields & IPPF_IPV4_OPTIONS)) {
320 332 struct T_opthdr *toh;
321 333
322 334 toh = (struct T_opthdr *)ancil_buf;
323 335 toh->level = IPPROTO_IP;
324 336 toh->name = IP_RECVOPTS;
325 337 toh->len = sizeof (struct T_opthdr) + ipp->ipp_ipv4_options_len;
326 338 toh->status = 0;
327 339 ancil_buf += sizeof (struct T_opthdr);
328 340 bcopy(ipp->ipp_ipv4_options, ancil_buf,
329 341 ipp->ipp_ipv4_options_len);
330 342 ancil_buf += ipp->ipp_ipv4_options_len;
331 343 ancil_size -= toh->len;
332 344 }
333 345
334 346 if (recv_ancillary.crb_recvslla) {
335 347 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
336 348 struct T_opthdr *toh;
337 349 struct sockaddr_dl *dstptr;
338 350 ill_t *ill;
339 351 int alen = 0;
340 352
341 353 ill = ill_lookup_on_ifindex(ira->ira_rifindex, B_FALSE, ipst);
342 354 if (ill != NULL)
343 355 alen = ill->ill_phys_addr_length;
344 356
345 357 /*
346 358 * For loopback multicast and broadcast the packet arrives
347 359 * with ira_ruifdex being the physical interface, but
348 360 * ira_l2src is all zero since ip_postfrag_loopback doesn't
349 361 * know our l2src. We don't report the address in that case.
350 362 */
351 363 if (ira->ira_flags & IRAF_LOOPBACK)
352 364 alen = 0;
353 365
354 366 toh = (struct T_opthdr *)ancil_buf;
355 367 toh->level = IPPROTO_IP;
356 368 toh->name = IP_RECVSLLA;
357 369 toh->len = sizeof (struct T_opthdr) +
358 370 sizeof (struct sockaddr_dl);
359 371 toh->status = 0;
360 372 ancil_buf += sizeof (struct T_opthdr);
361 373 dstptr = (struct sockaddr_dl *)ancil_buf;
362 374 dstptr->sdl_family = AF_LINK;
363 375 dstptr->sdl_index = ira->ira_ruifindex;
364 376 if (ill != NULL)
365 377 dstptr->sdl_type = ill->ill_type;
366 378 else
367 379 dstptr->sdl_type = 0;
368 380 dstptr->sdl_nlen = 0;
369 381 dstptr->sdl_alen = alen;
370 382 dstptr->sdl_slen = 0;
371 383 bcopy(ira->ira_l2src, dstptr->sdl_data, alen);
372 384 ancil_buf += sizeof (struct sockaddr_dl);
373 385 ancil_size -= toh->len;
374 386 if (ill != NULL)
375 387 ill_refrele(ill);
376 388 }
377 389
378 390 if (recv_ancillary.crb_recvif) {
379 391 struct T_opthdr *toh;
380 392 uint_t *dstptr;
381 393
382 394 toh = (struct T_opthdr *)ancil_buf;
383 395 toh->level = IPPROTO_IP;
384 396 toh->name = IP_RECVIF;
385 397 toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
386 398 toh->status = 0;
387 399 ancil_buf += sizeof (struct T_opthdr);
388 400 dstptr = (uint_t *)ancil_buf;
389 401 *dstptr = ira->ira_ruifindex;
390 402 ancil_buf += sizeof (uint_t);
391 403 ancil_size -= toh->len;
392 404 }
393 405
394 406 /*
395 407 * ip_recvpktinfo is used for both AF_INET and AF_INET6 but
396 408 * are different
397 409 */
398 410 if (recv_ancillary.crb_ip_recvpktinfo &&
399 411 connp->conn_family == AF_INET6) {
400 412 struct T_opthdr *toh;
401 413 struct in6_pktinfo *pkti;
402 414
403 415 toh = (struct T_opthdr *)ancil_buf;
404 416 toh->level = IPPROTO_IPV6;
405 417 toh->name = IPV6_PKTINFO;
406 418 toh->len = sizeof (struct T_opthdr) + sizeof (*pkti);
407 419 toh->status = 0;
408 420 ancil_buf += sizeof (struct T_opthdr);
409 421 pkti = (struct in6_pktinfo *)ancil_buf;
410 422 if (ira->ira_flags & IRAF_IS_IPV4) {
411 423 IN6_IPADDR_TO_V4MAPPED(ipp->ipp_addr_v4,
412 424 &pkti->ipi6_addr);
413 425 } else {
414 426 pkti->ipi6_addr = ipp->ipp_addr;
415 427 }
416 428 pkti->ipi6_ifindex = ira->ira_ruifindex;
417 429
418 430 ancil_buf += sizeof (*pkti);
419 431 ancil_size -= toh->len;
420 432 }
421 433 if (recv_ancillary.crb_ipv6_recvhoplimit) {
422 434 struct T_opthdr *toh;
423 435
424 436 toh = (struct T_opthdr *)ancil_buf;
425 437 toh->level = IPPROTO_IPV6;
426 438 toh->name = IPV6_HOPLIMIT;
427 439 toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
428 440 toh->status = 0;
429 441 ancil_buf += sizeof (struct T_opthdr);
430 442 *(uint_t *)ancil_buf = ipp->ipp_hoplimit;
431 443 ancil_buf += sizeof (uint_t);
432 444 ancil_size -= toh->len;
433 445 }
434 446 if (recv_ancillary.crb_ipv6_recvtclass) {
435 447 struct T_opthdr *toh;
436 448
437 449 toh = (struct T_opthdr *)ancil_buf;
438 450 toh->level = IPPROTO_IPV6;
439 451 toh->name = IPV6_TCLASS;
440 452 toh->len = sizeof (struct T_opthdr) + sizeof (uint_t);
441 453 toh->status = 0;
442 454 ancil_buf += sizeof (struct T_opthdr);
443 455
444 456 if (ira->ira_flags & IRAF_IS_IPV4)
445 457 *(uint_t *)ancil_buf = ipp->ipp_type_of_service;
446 458 else
447 459 *(uint_t *)ancil_buf = ipp->ipp_tclass;
448 460 ancil_buf += sizeof (uint_t);
449 461 ancil_size -= toh->len;
450 462 }
451 463 if (recv_ancillary.crb_ipv6_recvhopopts &&
452 464 (ipp->ipp_fields & IPPF_HOPOPTS)) {
453 465 struct T_opthdr *toh;
454 466
455 467 toh = (struct T_opthdr *)ancil_buf;
456 468 toh->level = IPPROTO_IPV6;
457 469 toh->name = IPV6_HOPOPTS;
458 470 toh->len = sizeof (struct T_opthdr) + ipp->ipp_hopoptslen;
459 471 toh->status = 0;
460 472 ancil_buf += sizeof (struct T_opthdr);
461 473 bcopy(ipp->ipp_hopopts, ancil_buf, ipp->ipp_hopoptslen);
462 474 ancil_buf += ipp->ipp_hopoptslen;
463 475 ancil_size -= toh->len;
464 476 }
465 477 /*
466 478 * To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
467 479 * and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
468 480 * options that appear before a routing header.
469 481 * We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
470 482 */
471 483 if (ipp->ipp_fields & IPPF_RTHDRDSTOPTS) {
472 484 if (recv_ancillary.crb_ipv6_recvrthdrdstopts ||
473 485 (recv_ancillary.crb_ipv6_recvdstopts &&
474 486 recv_ancillary.crb_ipv6_recvrthdr)) {
475 487 struct T_opthdr *toh;
476 488
477 489 toh = (struct T_opthdr *)ancil_buf;
478 490 toh->level = IPPROTO_IPV6;
479 491 toh->name = IPV6_DSTOPTS;
480 492 toh->len = sizeof (struct T_opthdr) +
481 493 ipp->ipp_rthdrdstoptslen;
482 494 toh->status = 0;
483 495 ancil_buf += sizeof (struct T_opthdr);
484 496 bcopy(ipp->ipp_rthdrdstopts, ancil_buf,
485 497 ipp->ipp_rthdrdstoptslen);
486 498 ancil_buf += ipp->ipp_rthdrdstoptslen;
487 499 ancil_size -= toh->len;
488 500 }
489 501 }
490 502 if (recv_ancillary.crb_ipv6_recvrthdr &&
491 503 (ipp->ipp_fields & IPPF_RTHDR)) {
492 504 struct T_opthdr *toh;
493 505
494 506 toh = (struct T_opthdr *)ancil_buf;
495 507 toh->level = IPPROTO_IPV6;
496 508 toh->name = IPV6_RTHDR;
497 509 toh->len = sizeof (struct T_opthdr) + ipp->ipp_rthdrlen;
498 510 toh->status = 0;
499 511 ancil_buf += sizeof (struct T_opthdr);
500 512 bcopy(ipp->ipp_rthdr, ancil_buf, ipp->ipp_rthdrlen);
501 513 ancil_buf += ipp->ipp_rthdrlen;
502 514 ancil_size -= toh->len;
503 515 }
504 516 if ((recv_ancillary.crb_ipv6_recvdstopts ||
505 517 recv_ancillary.crb_old_ipv6_recvdstopts) &&
506 518 (ipp->ipp_fields & IPPF_DSTOPTS)) {
507 519 struct T_opthdr *toh;
508 520
509 521 toh = (struct T_opthdr *)ancil_buf;
510 522 toh->level = IPPROTO_IPV6;
511 523 toh->name = IPV6_DSTOPTS;
512 524 toh->len = sizeof (struct T_opthdr) + ipp->ipp_dstoptslen;
513 525 toh->status = 0;
514 526 ancil_buf += sizeof (struct T_opthdr);
515 527 bcopy(ipp->ipp_dstopts, ancil_buf, ipp->ipp_dstoptslen);
516 528 ancil_buf += ipp->ipp_dstoptslen;
517 529 ancil_size -= toh->len;
518 530 }
519 531
520 532 if (recv_ancillary.crb_recvucred && ira->ira_cred != NULL) {
521 533 struct T_opthdr *toh;
522 534 cred_t *rcr = connp->conn_cred;
523 535
524 536 toh = (struct T_opthdr *)ancil_buf;
525 537 toh->level = SOL_SOCKET;
526 538 toh->name = SCM_UCRED;
527 539 toh->len = sizeof (struct T_opthdr) +
528 540 ucredminsize(ira->ira_cred);
529 541 toh->status = 0;
530 542 (void) cred2ucred(ira->ira_cred, ira->ira_cpid, &toh[1], rcr);
531 543 ancil_buf += toh->len;
532 544 ancil_size -= toh->len;
533 545 }
534 546 if (recv_ancillary.crb_timestamp) {
535 547 struct T_opthdr *toh;
536 548
537 549 toh = (struct T_opthdr *)ancil_buf;
538 550 toh->level = SOL_SOCKET;
539 551 toh->name = SCM_TIMESTAMP;
540 552 toh->len = sizeof (struct T_opthdr) +
541 553 sizeof (timestruc_t) + _POINTER_ALIGNMENT;
↓ open down ↓ |
289 lines elided |
↑ open up ↑ |
542 554 toh->status = 0;
543 555 ancil_buf += sizeof (struct T_opthdr);
544 556 /* Align for gethrestime() */
545 557 ancil_buf = (uchar_t *)P2ROUNDUP((intptr_t)ancil_buf,
546 558 sizeof (intptr_t));
547 559 gethrestime((timestruc_t *)ancil_buf);
548 560 ancil_buf = (uchar_t *)toh + toh->len;
549 561 ancil_size -= toh->len;
550 562 }
551 563
552 - /*
553 - * CAUTION:
554 - * Due to aligment issues
555 - * Processing of IP_RECVTTL option
556 - * should always be the last. Adding
557 - * any option processing after this will
558 - * cause alignment panic.
559 - */
564 + if (recv_ancillary.crb_recvtos &&
565 + (ira->ira_flags & IRAF_IS_IPV4)) {
566 + struct T_opthdr *toh;
567 + uint8_t *dstptr;
568 +
569 + toh = (struct T_opthdr *)ancil_buf;
570 + toh->level = IPPROTO_IP;
571 + toh->name = IP_RECVTOS;
572 + toh->len = sizeof (struct T_opthdr) +
573 + P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
574 + toh->status = 0;
575 + ancil_buf += sizeof (struct T_opthdr);
576 + dstptr = (uint8_t *)ancil_buf;
577 + *dstptr = ipp->ipp_type_of_service;
578 + ancil_buf = (uchar_t *)toh + toh->len;
579 + ancil_size -= toh->len;
580 + ASSERT(__TPI_TOPT_ISALIGNED(toh));
581 + }
582 +
560 583 if (recv_ancillary.crb_recvttl &&
561 584 (ira->ira_flags & IRAF_IS_IPV4)) {
562 585 struct T_opthdr *toh;
563 586 uint8_t *dstptr;
564 587
565 588 toh = (struct T_opthdr *)ancil_buf;
566 589 toh->level = IPPROTO_IP;
567 590 toh->name = IP_RECVTTL;
568 - toh->len = sizeof (struct T_opthdr) + sizeof (uint8_t);
591 + toh->len = sizeof (struct T_opthdr) +
592 + P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
569 593 toh->status = 0;
570 594 ancil_buf += sizeof (struct T_opthdr);
571 595 dstptr = (uint8_t *)ancil_buf;
572 596 *dstptr = ipp->ipp_hoplimit;
573 - ancil_buf += sizeof (uint8_t);
597 + ancil_buf = (uchar_t *)toh + toh->len;
574 598 ancil_size -= toh->len;
599 + ASSERT(__TPI_TOPT_ISALIGNED(toh));
575 600 }
576 601
577 602 /* Consumed all of allocated space */
578 603 ASSERT(ancil_size == 0);
579 604
580 605 }
581 606
582 607 /*
583 608 * This routine retrieves the current status of socket options.
584 609 * It returns the size of the option retrieved, or -1.
585 610 */
586 611 int
587 612 conn_opt_get(conn_opt_arg_t *coa, t_scalar_t level, t_scalar_t name,
588 613 uchar_t *ptr)
589 614 {
590 615 int *i1 = (int *)ptr;
591 616 conn_t *connp = coa->coa_connp;
592 617 ip_xmit_attr_t *ixa = coa->coa_ixa;
593 618 ip_pkt_t *ipp = coa->coa_ipp;
594 619 ip_stack_t *ipst = ixa->ixa_ipst;
595 620 uint_t len;
596 621
597 622 ASSERT(MUTEX_HELD(&coa->coa_connp->conn_lock));
598 623
599 624 switch (level) {
600 625 case SOL_SOCKET:
601 626 switch (name) {
602 627 case SO_DEBUG:
603 628 *i1 = connp->conn_debug ? SO_DEBUG : 0;
604 629 break; /* goto sizeof (int) option return */
605 630 case SO_KEEPALIVE:
606 631 *i1 = connp->conn_keepalive ? SO_KEEPALIVE : 0;
607 632 break;
608 633 case SO_LINGER: {
609 634 struct linger *lgr = (struct linger *)ptr;
610 635
611 636 lgr->l_onoff = connp->conn_linger ? SO_LINGER : 0;
612 637 lgr->l_linger = connp->conn_lingertime;
613 638 }
614 639 return (sizeof (struct linger));
615 640
616 641 case SO_OOBINLINE:
617 642 *i1 = connp->conn_oobinline ? SO_OOBINLINE : 0;
618 643 break;
619 644 case SO_REUSEADDR:
620 645 *i1 = connp->conn_reuseaddr ? SO_REUSEADDR : 0;
621 646 break; /* goto sizeof (int) option return */
622 647 case SO_TYPE:
623 648 *i1 = connp->conn_so_type;
624 649 break; /* goto sizeof (int) option return */
625 650 case SO_DONTROUTE:
626 651 *i1 = (ixa->ixa_flags & IXAF_DONTROUTE) ?
627 652 SO_DONTROUTE : 0;
628 653 break; /* goto sizeof (int) option return */
629 654 case SO_USELOOPBACK:
630 655 *i1 = connp->conn_useloopback ? SO_USELOOPBACK : 0;
631 656 break; /* goto sizeof (int) option return */
632 657 case SO_BROADCAST:
633 658 *i1 = connp->conn_broadcast ? SO_BROADCAST : 0;
634 659 break; /* goto sizeof (int) option return */
635 660
636 661 case SO_SNDBUF:
637 662 *i1 = connp->conn_sndbuf;
638 663 break; /* goto sizeof (int) option return */
639 664 case SO_RCVBUF:
640 665 *i1 = connp->conn_rcvbuf;
641 666 break; /* goto sizeof (int) option return */
642 667 case SO_RCVTIMEO:
643 668 case SO_SNDTIMEO:
644 669 /*
645 670 * Pass these two options in order for third part
646 671 * protocol usage. Here just return directly.
647 672 */
648 673 *i1 = 0;
649 674 break;
650 675 case SO_DGRAM_ERRIND:
651 676 *i1 = connp->conn_dgram_errind ? SO_DGRAM_ERRIND : 0;
652 677 break; /* goto sizeof (int) option return */
653 678 case SO_RECVUCRED:
654 679 *i1 = connp->conn_recv_ancillary.crb_recvucred;
655 680 break; /* goto sizeof (int) option return */
656 681 case SO_TIMESTAMP:
657 682 *i1 = connp->conn_recv_ancillary.crb_timestamp;
658 683 break; /* goto sizeof (int) option return */
659 684 case SO_VRRP:
660 685 *i1 = connp->conn_isvrrp;
661 686 break; /* goto sizeof (int) option return */
662 687 case SO_ANON_MLP:
663 688 *i1 = connp->conn_anon_mlp;
664 689 break; /* goto sizeof (int) option return */
665 690 case SO_MAC_EXEMPT:
666 691 *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
667 692 break; /* goto sizeof (int) option return */
668 693 case SO_MAC_IMPLICIT:
669 694 *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
670 695 break; /* goto sizeof (int) option return */
671 696 case SO_ALLZONES:
672 697 *i1 = connp->conn_allzones;
673 698 break; /* goto sizeof (int) option return */
674 699 case SO_EXCLBIND:
675 700 *i1 = connp->conn_exclbind ? SO_EXCLBIND : 0;
676 701 break;
677 702 case SO_PROTOTYPE:
678 703 *i1 = connp->conn_proto;
679 704 break;
680 705
681 706 case SO_DOMAIN:
682 707 *i1 = connp->conn_family;
683 708 break;
684 709 default:
685 710 return (-1);
686 711 }
687 712 break;
688 713 case IPPROTO_IP:
689 714 if (connp->conn_family != AF_INET)
690 715 return (-1);
691 716 switch (name) {
692 717 case IP_OPTIONS:
693 718 case T_IP_OPTIONS:
694 719 if (!(ipp->ipp_fields & IPPF_IPV4_OPTIONS))
695 720 return (0);
696 721
697 722 len = ipp->ipp_ipv4_options_len;
698 723 if (len > 0) {
699 724 bcopy(ipp->ipp_ipv4_options, ptr, len);
700 725 }
701 726 return (len);
702 727
703 728 case IP_PKTINFO: {
704 729 /*
705 730 * This also handles IP_RECVPKTINFO.
706 731 * IP_PKTINFO and IP_RECVPKTINFO have same value.
707 732 * Differentiation is based on the size of the
708 733 * argument passed in.
709 734 */
710 735 struct in_pktinfo *pktinfo;
711 736
712 737 #ifdef notdef
713 738 /* optcom doesn't provide a length with "get" */
714 739 if (inlen == sizeof (int)) {
715 740 /* This is IP_RECVPKTINFO option. */
716 741 *i1 = connp->conn_recv_ancillary.
717 742 crb_ip_recvpktinfo;
718 743 return (sizeof (int));
719 744 }
720 745 #endif
721 746 /* XXX assumes that caller has room for max size! */
722 747
723 748 pktinfo = (struct in_pktinfo *)ptr;
724 749 pktinfo->ipi_ifindex = ixa->ixa_ifindex;
725 750 if (ipp->ipp_fields & IPPF_ADDR)
726 751 pktinfo->ipi_spec_dst.s_addr = ipp->ipp_addr_v4;
727 752 else
728 753 pktinfo->ipi_spec_dst.s_addr = INADDR_ANY;
729 754 return (sizeof (struct in_pktinfo));
730 755 }
731 756 case IP_DONTFRAG:
732 757 *i1 = (ixa->ixa_flags & IXAF_DONTFRAG) != 0;
733 758 return (sizeof (int));
734 759 case IP_TOS:
735 760 case T_IP_TOS:
736 761 *i1 = (int)ipp->ipp_type_of_service;
737 762 break; /* goto sizeof (int) option return */
738 763 case IP_TTL:
739 764 *i1 = (int)ipp->ipp_unicast_hops;
740 765 break; /* goto sizeof (int) option return */
741 766 case IP_DHCPINIT_IF:
742 767 return (-1);
743 768 case IP_NEXTHOP:
744 769 if (ixa->ixa_flags & IXAF_NEXTHOP_SET) {
745 770 *(ipaddr_t *)ptr = ixa->ixa_nexthop_v4;
746 771 return (sizeof (ipaddr_t));
747 772 } else {
748 773 return (0);
749 774 }
750 775
751 776 case IP_MULTICAST_IF:
752 777 /* 0 address if not set */
753 778 *(ipaddr_t *)ptr = ixa->ixa_multicast_ifaddr;
754 779 return (sizeof (ipaddr_t));
755 780 case IP_MULTICAST_TTL:
756 781 *(uchar_t *)ptr = ixa->ixa_multicast_ttl;
757 782 return (sizeof (uchar_t));
758 783 case IP_MULTICAST_LOOP:
759 784 *ptr = (ixa->ixa_flags & IXAF_MULTICAST_LOOP) ? 1 : 0;
760 785 return (sizeof (uint8_t));
761 786 case IP_RECVOPTS:
762 787 *i1 = connp->conn_recv_ancillary.crb_recvopts;
763 788 break; /* goto sizeof (int) option return */
764 789 case IP_RECVDSTADDR:
765 790 *i1 = connp->conn_recv_ancillary.crb_recvdstaddr;
↓ open down ↓ |
181 lines elided |
↑ open up ↑ |
766 791 break; /* goto sizeof (int) option return */
767 792 case IP_RECVIF:
768 793 *i1 = connp->conn_recv_ancillary.crb_recvif;
769 794 break; /* goto sizeof (int) option return */
770 795 case IP_RECVSLLA:
771 796 *i1 = connp->conn_recv_ancillary.crb_recvslla;
772 797 break; /* goto sizeof (int) option return */
773 798 case IP_RECVTTL:
774 799 *i1 = connp->conn_recv_ancillary.crb_recvttl;
775 800 break; /* goto sizeof (int) option return */
801 + case IP_RECVTOS:
802 + *i1 = connp->conn_recv_ancillary.crb_recvtos;
803 + break; /* goto sizeof (int) option return */
776 804 case IP_ADD_MEMBERSHIP:
777 805 case IP_DROP_MEMBERSHIP:
778 806 case MCAST_JOIN_GROUP:
779 807 case MCAST_LEAVE_GROUP:
780 808 case IP_BLOCK_SOURCE:
781 809 case IP_UNBLOCK_SOURCE:
782 810 case IP_ADD_SOURCE_MEMBERSHIP:
783 811 case IP_DROP_SOURCE_MEMBERSHIP:
784 812 case MCAST_BLOCK_SOURCE:
785 813 case MCAST_UNBLOCK_SOURCE:
786 814 case MCAST_JOIN_SOURCE_GROUP:
787 815 case MCAST_LEAVE_SOURCE_GROUP:
788 816 case MRT_INIT:
789 817 case MRT_DONE:
790 818 case MRT_ADD_VIF:
791 819 case MRT_DEL_VIF:
792 820 case MRT_ADD_MFC:
793 821 case MRT_DEL_MFC:
794 822 /* cannot "get" the value for these */
795 823 return (-1);
796 824 case MRT_VERSION:
797 825 case MRT_ASSERT:
798 826 (void) ip_mrouter_get(name, connp, ptr);
799 827 return (sizeof (int));
800 828 case IP_SEC_OPT:
801 829 return (ipsec_req_from_conn(connp, (ipsec_req_t *)ptr,
802 830 IPSEC_AF_V4));
803 831 case IP_BOUND_IF:
804 832 /* Zero if not set */
805 833 *i1 = connp->conn_bound_if;
806 834 break; /* goto sizeof (int) option return */
807 835 case IP_UNSPEC_SRC:
808 836 *i1 = connp->conn_unspec_src;
809 837 break; /* goto sizeof (int) option return */
810 838 case IP_BROADCAST_TTL:
811 839 if (ixa->ixa_flags & IXAF_BROADCAST_TTL_SET)
812 840 *(uchar_t *)ptr = ixa->ixa_broadcast_ttl;
813 841 else
814 842 *(uchar_t *)ptr = ipst->ips_ip_broadcast_ttl;
815 843 return (sizeof (uchar_t));
816 844 default:
817 845 return (-1);
818 846 }
819 847 break;
820 848 case IPPROTO_IPV6:
821 849 if (connp->conn_family != AF_INET6)
822 850 return (-1);
823 851 switch (name) {
824 852 case IPV6_UNICAST_HOPS:
825 853 *i1 = (int)ipp->ipp_unicast_hops;
826 854 break; /* goto sizeof (int) option return */
827 855 case IPV6_MULTICAST_IF:
828 856 /* 0 index if not set */
829 857 *i1 = ixa->ixa_multicast_ifindex;
830 858 break; /* goto sizeof (int) option return */
831 859 case IPV6_MULTICAST_HOPS:
832 860 *i1 = ixa->ixa_multicast_ttl;
833 861 break; /* goto sizeof (int) option return */
834 862 case IPV6_MULTICAST_LOOP:
835 863 *i1 = (ixa->ixa_flags & IXAF_MULTICAST_LOOP) ? 1 : 0;
836 864 break; /* goto sizeof (int) option return */
837 865 case IPV6_JOIN_GROUP:
838 866 case IPV6_LEAVE_GROUP:
839 867 case MCAST_JOIN_GROUP:
840 868 case MCAST_LEAVE_GROUP:
841 869 case MCAST_BLOCK_SOURCE:
842 870 case MCAST_UNBLOCK_SOURCE:
843 871 case MCAST_JOIN_SOURCE_GROUP:
844 872 case MCAST_LEAVE_SOURCE_GROUP:
845 873 /* cannot "get" the value for these */
846 874 return (-1);
847 875 case IPV6_BOUND_IF:
848 876 /* Zero if not set */
849 877 *i1 = connp->conn_bound_if;
850 878 break; /* goto sizeof (int) option return */
851 879 case IPV6_UNSPEC_SRC:
852 880 *i1 = connp->conn_unspec_src;
853 881 break; /* goto sizeof (int) option return */
854 882 case IPV6_RECVPKTINFO:
855 883 *i1 = connp->conn_recv_ancillary.crb_ip_recvpktinfo;
856 884 break; /* goto sizeof (int) option return */
857 885 case IPV6_RECVTCLASS:
858 886 *i1 = connp->conn_recv_ancillary.crb_ipv6_recvtclass;
859 887 break; /* goto sizeof (int) option return */
860 888 case IPV6_RECVPATHMTU:
861 889 *i1 = connp->conn_ipv6_recvpathmtu;
862 890 break; /* goto sizeof (int) option return */
863 891 case IPV6_RECVHOPLIMIT:
864 892 *i1 = connp->conn_recv_ancillary.crb_ipv6_recvhoplimit;
865 893 break; /* goto sizeof (int) option return */
866 894 case IPV6_RECVHOPOPTS:
867 895 *i1 = connp->conn_recv_ancillary.crb_ipv6_recvhopopts;
868 896 break; /* goto sizeof (int) option return */
869 897 case IPV6_RECVDSTOPTS:
870 898 *i1 = connp->conn_recv_ancillary.crb_ipv6_recvdstopts;
871 899 break; /* goto sizeof (int) option return */
872 900 case _OLD_IPV6_RECVDSTOPTS:
873 901 *i1 =
874 902 connp->conn_recv_ancillary.crb_old_ipv6_recvdstopts;
875 903 break; /* goto sizeof (int) option return */
876 904 case IPV6_RECVRTHDRDSTOPTS:
877 905 *i1 = connp->conn_recv_ancillary.
878 906 crb_ipv6_recvrthdrdstopts;
879 907 break; /* goto sizeof (int) option return */
880 908 case IPV6_RECVRTHDR:
881 909 *i1 = connp->conn_recv_ancillary.crb_ipv6_recvrthdr;
882 910 break; /* goto sizeof (int) option return */
883 911 case IPV6_PKTINFO: {
884 912 /* XXX assumes that caller has room for max size! */
885 913 struct in6_pktinfo *pkti;
886 914
887 915 pkti = (struct in6_pktinfo *)ptr;
888 916 pkti->ipi6_ifindex = ixa->ixa_ifindex;
889 917 if (ipp->ipp_fields & IPPF_ADDR)
890 918 pkti->ipi6_addr = ipp->ipp_addr;
891 919 else
892 920 pkti->ipi6_addr = ipv6_all_zeros;
893 921 return (sizeof (struct in6_pktinfo));
894 922 }
895 923 case IPV6_TCLASS:
896 924 *i1 = ipp->ipp_tclass;
897 925 break; /* goto sizeof (int) option return */
898 926 case IPV6_NEXTHOP: {
899 927 sin6_t *sin6 = (sin6_t *)ptr;
900 928
901 929 if (ixa->ixa_flags & IXAF_NEXTHOP_SET)
902 930 return (0);
903 931
904 932 *sin6 = sin6_null;
905 933 sin6->sin6_family = AF_INET6;
906 934 sin6->sin6_addr = ixa->ixa_nexthop_v6;
907 935
908 936 return (sizeof (sin6_t));
909 937 }
910 938 case IPV6_HOPOPTS:
911 939 if (!(ipp->ipp_fields & IPPF_HOPOPTS))
912 940 return (0);
913 941 bcopy(ipp->ipp_hopopts, ptr,
914 942 ipp->ipp_hopoptslen);
915 943 return (ipp->ipp_hopoptslen);
916 944 case IPV6_RTHDRDSTOPTS:
917 945 if (!(ipp->ipp_fields & IPPF_RTHDRDSTOPTS))
918 946 return (0);
919 947 bcopy(ipp->ipp_rthdrdstopts, ptr,
920 948 ipp->ipp_rthdrdstoptslen);
921 949 return (ipp->ipp_rthdrdstoptslen);
922 950 case IPV6_RTHDR:
923 951 if (!(ipp->ipp_fields & IPPF_RTHDR))
924 952 return (0);
925 953 bcopy(ipp->ipp_rthdr, ptr, ipp->ipp_rthdrlen);
926 954 return (ipp->ipp_rthdrlen);
927 955 case IPV6_DSTOPTS:
928 956 if (!(ipp->ipp_fields & IPPF_DSTOPTS))
929 957 return (0);
930 958 bcopy(ipp->ipp_dstopts, ptr, ipp->ipp_dstoptslen);
931 959 return (ipp->ipp_dstoptslen);
932 960 case IPV6_PATHMTU:
933 961 return (ip_fill_mtuinfo(connp, ixa,
934 962 (struct ip6_mtuinfo *)ptr));
935 963 case IPV6_SEC_OPT:
936 964 return (ipsec_req_from_conn(connp, (ipsec_req_t *)ptr,
937 965 IPSEC_AF_V6));
938 966 case IPV6_SRC_PREFERENCES:
939 967 return (ip6_get_src_preferences(ixa, (uint32_t *)ptr));
940 968 case IPV6_DONTFRAG:
941 969 *i1 = (ixa->ixa_flags & IXAF_DONTFRAG) != 0;
942 970 return (sizeof (int));
943 971 case IPV6_USE_MIN_MTU:
944 972 if (ixa->ixa_flags & IXAF_USE_MIN_MTU)
945 973 *i1 = ixa->ixa_use_min_mtu;
946 974 else
947 975 *i1 = IPV6_USE_MIN_MTU_MULTICAST;
948 976 break;
949 977 case IPV6_V6ONLY:
950 978 *i1 = connp->conn_ipv6_v6only;
951 979 return (sizeof (int));
952 980 default:
953 981 return (-1);
954 982 }
955 983 break;
956 984 case IPPROTO_UDP:
957 985 switch (name) {
958 986 case UDP_ANONPRIVBIND:
959 987 *i1 = connp->conn_anon_priv_bind;
960 988 break;
961 989 case UDP_EXCLBIND:
962 990 *i1 = connp->conn_exclbind ? UDP_EXCLBIND : 0;
963 991 break;
964 992 default:
965 993 return (-1);
966 994 }
967 995 break;
968 996 case IPPROTO_TCP:
969 997 switch (name) {
970 998 case TCP_RECVDSTADDR:
971 999 *i1 = connp->conn_recv_ancillary.crb_recvdstaddr;
972 1000 break;
973 1001 case TCP_ANONPRIVBIND:
974 1002 *i1 = connp->conn_anon_priv_bind;
975 1003 break;
976 1004 case TCP_EXCLBIND:
977 1005 *i1 = connp->conn_exclbind ? TCP_EXCLBIND : 0;
978 1006 break;
979 1007 default:
980 1008 return (-1);
981 1009 }
982 1010 break;
983 1011 default:
984 1012 return (-1);
985 1013 }
986 1014 return (sizeof (int));
987 1015 }
988 1016
989 1017 static int conn_opt_set_socket(conn_opt_arg_t *coa, t_scalar_t name,
990 1018 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
991 1019 static int conn_opt_set_ip(conn_opt_arg_t *coa, t_scalar_t name,
992 1020 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
993 1021 static int conn_opt_set_ipv6(conn_opt_arg_t *coa, t_scalar_t name,
994 1022 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
995 1023 static int conn_opt_set_udp(conn_opt_arg_t *coa, t_scalar_t name,
996 1024 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
997 1025 static int conn_opt_set_tcp(conn_opt_arg_t *coa, t_scalar_t name,
998 1026 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr);
999 1027
1000 1028 /*
1001 1029 * This routine sets the most common socket options including some
1002 1030 * that are transport/ULP specific.
1003 1031 * It returns errno or zero.
1004 1032 *
1005 1033 * For fixed length options, there is no sanity check
1006 1034 * of passed in length is done. It is assumed *_optcom_req()
1007 1035 * routines do the right thing.
1008 1036 */
1009 1037 int
1010 1038 conn_opt_set(conn_opt_arg_t *coa, t_scalar_t level, t_scalar_t name,
1011 1039 uint_t inlen, uchar_t *invalp, boolean_t checkonly, cred_t *cr)
1012 1040 {
1013 1041 ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
1014 1042
1015 1043 /* We have different functions for different levels */
1016 1044 switch (level) {
1017 1045 case SOL_SOCKET:
1018 1046 return (conn_opt_set_socket(coa, name, inlen, invalp,
1019 1047 checkonly, cr));
1020 1048 case IPPROTO_IP:
1021 1049 return (conn_opt_set_ip(coa, name, inlen, invalp,
1022 1050 checkonly, cr));
1023 1051 case IPPROTO_IPV6:
1024 1052 return (conn_opt_set_ipv6(coa, name, inlen, invalp,
1025 1053 checkonly, cr));
1026 1054 case IPPROTO_UDP:
1027 1055 return (conn_opt_set_udp(coa, name, inlen, invalp,
1028 1056 checkonly, cr));
1029 1057 case IPPROTO_TCP:
1030 1058 return (conn_opt_set_tcp(coa, name, inlen, invalp,
1031 1059 checkonly, cr));
1032 1060 default:
1033 1061 return (0);
1034 1062 }
1035 1063 }
1036 1064
1037 1065 /*
1038 1066 * Handle SOL_SOCKET
1039 1067 * Note that we do not handle SO_PROTOTYPE here. The ULPs that support
1040 1068 * it implement their own checks and setting of conn_proto.
1041 1069 */
1042 1070 /* ARGSUSED1 */
1043 1071 static int
1044 1072 conn_opt_set_socket(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
1045 1073 uchar_t *invalp, boolean_t checkonly, cred_t *cr)
1046 1074 {
1047 1075 conn_t *connp = coa->coa_connp;
1048 1076 ip_xmit_attr_t *ixa = coa->coa_ixa;
1049 1077 int *i1 = (int *)invalp;
1050 1078 boolean_t onoff = (*i1 == 0) ? 0 : 1;
1051 1079
1052 1080 switch (name) {
1053 1081 case SO_ALLZONES:
1054 1082 if (IPCL_IS_BOUND(connp))
1055 1083 return (EINVAL);
1056 1084 break;
1057 1085 case SO_VRRP:
1058 1086 if (secpolicy_ip_config(cr, checkonly) != 0)
1059 1087 return (EACCES);
1060 1088 break;
1061 1089 case SO_MAC_EXEMPT:
1062 1090 if (secpolicy_net_mac_aware(cr) != 0)
1063 1091 return (EACCES);
1064 1092 if (IPCL_IS_BOUND(connp))
1065 1093 return (EINVAL);
1066 1094 break;
1067 1095 case SO_MAC_IMPLICIT:
1068 1096 if (secpolicy_net_mac_implicit(cr) != 0)
1069 1097 return (EACCES);
1070 1098 break;
1071 1099 }
1072 1100 if (checkonly)
1073 1101 return (0);
1074 1102
1075 1103 mutex_enter(&connp->conn_lock);
1076 1104 /* Here we set the actual option value */
1077 1105 switch (name) {
1078 1106 case SO_DEBUG:
1079 1107 connp->conn_debug = onoff;
1080 1108 break;
1081 1109 case SO_KEEPALIVE:
1082 1110 connp->conn_keepalive = onoff;
1083 1111 break;
1084 1112 case SO_LINGER: {
1085 1113 struct linger *lgr = (struct linger *)invalp;
1086 1114
1087 1115 if (lgr->l_onoff) {
1088 1116 connp->conn_linger = 1;
1089 1117 connp->conn_lingertime = lgr->l_linger;
1090 1118 } else {
1091 1119 connp->conn_linger = 0;
1092 1120 connp->conn_lingertime = 0;
1093 1121 }
1094 1122 break;
1095 1123 }
1096 1124 case SO_OOBINLINE:
1097 1125 connp->conn_oobinline = onoff;
1098 1126 coa->coa_changed |= COA_OOBINLINE_CHANGED;
1099 1127 break;
1100 1128 case SO_REUSEADDR:
1101 1129 connp->conn_reuseaddr = onoff;
1102 1130 break;
1103 1131 case SO_DONTROUTE:
1104 1132 if (onoff)
1105 1133 ixa->ixa_flags |= IXAF_DONTROUTE;
1106 1134 else
1107 1135 ixa->ixa_flags &= ~IXAF_DONTROUTE;
1108 1136 coa->coa_changed |= COA_ROUTE_CHANGED;
1109 1137 break;
1110 1138 case SO_USELOOPBACK:
1111 1139 connp->conn_useloopback = onoff;
1112 1140 break;
1113 1141 case SO_BROADCAST:
1114 1142 connp->conn_broadcast = onoff;
1115 1143 break;
1116 1144 case SO_SNDBUF:
1117 1145 /* ULP has range checked the value */
1118 1146 connp->conn_sndbuf = *i1;
1119 1147 coa->coa_changed |= COA_SNDBUF_CHANGED;
1120 1148 break;
1121 1149 case SO_RCVBUF:
1122 1150 /* ULP has range checked the value */
1123 1151 connp->conn_rcvbuf = *i1;
1124 1152 coa->coa_changed |= COA_RCVBUF_CHANGED;
1125 1153 break;
1126 1154 case SO_RCVTIMEO:
1127 1155 case SO_SNDTIMEO:
1128 1156 /*
1129 1157 * Pass these two options in order for third part
1130 1158 * protocol usage.
1131 1159 */
1132 1160 break;
1133 1161 case SO_DGRAM_ERRIND:
1134 1162 connp->conn_dgram_errind = onoff;
1135 1163 break;
1136 1164 case SO_RECVUCRED:
1137 1165 connp->conn_recv_ancillary.crb_recvucred = onoff;
1138 1166 break;
1139 1167 case SO_ALLZONES:
1140 1168 connp->conn_allzones = onoff;
1141 1169 coa->coa_changed |= COA_ROUTE_CHANGED;
1142 1170 if (onoff)
1143 1171 ixa->ixa_zoneid = ALL_ZONES;
1144 1172 else
1145 1173 ixa->ixa_zoneid = connp->conn_zoneid;
1146 1174 break;
1147 1175 case SO_TIMESTAMP:
1148 1176 connp->conn_recv_ancillary.crb_timestamp = onoff;
1149 1177 break;
1150 1178 case SO_VRRP:
1151 1179 connp->conn_isvrrp = onoff;
1152 1180 break;
1153 1181 case SO_ANON_MLP:
1154 1182 connp->conn_anon_mlp = onoff;
1155 1183 break;
1156 1184 case SO_MAC_EXEMPT:
1157 1185 connp->conn_mac_mode = onoff ?
1158 1186 CONN_MAC_AWARE : CONN_MAC_DEFAULT;
1159 1187 break;
1160 1188 case SO_MAC_IMPLICIT:
1161 1189 connp->conn_mac_mode = onoff ?
1162 1190 CONN_MAC_IMPLICIT : CONN_MAC_DEFAULT;
1163 1191 break;
1164 1192 case SO_EXCLBIND:
1165 1193 connp->conn_exclbind = onoff;
1166 1194 break;
1167 1195 }
1168 1196 mutex_exit(&connp->conn_lock);
1169 1197 return (0);
1170 1198 }
1171 1199
1172 1200 /* Handle IPPROTO_IP */
1173 1201 static int
1174 1202 conn_opt_set_ip(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
1175 1203 uchar_t *invalp, boolean_t checkonly, cred_t *cr)
1176 1204 {
1177 1205 conn_t *connp = coa->coa_connp;
1178 1206 ip_xmit_attr_t *ixa = coa->coa_ixa;
1179 1207 ip_pkt_t *ipp = coa->coa_ipp;
1180 1208 int *i1 = (int *)invalp;
1181 1209 boolean_t onoff = (*i1 == 0) ? 0 : 1;
1182 1210 ipaddr_t addr = (ipaddr_t)*i1;
1183 1211 uint_t ifindex;
1184 1212 zoneid_t zoneid = IPCL_ZONEID(connp);
1185 1213 ipif_t *ipif;
1186 1214 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
1187 1215 int error;
1188 1216
1189 1217 if (connp->conn_family != AF_INET)
1190 1218 return (EINVAL);
1191 1219
1192 1220 ifindex = UINT_MAX;
1193 1221 switch (name) {
1194 1222 case IP_TTL:
1195 1223 /* Don't allow zero */
1196 1224 if (*i1 < 1 || *i1 > 255)
1197 1225 return (EINVAL);
1198 1226 break;
1199 1227 case IP_MULTICAST_IF:
1200 1228 if (addr == INADDR_ANY) {
1201 1229 /* Clear */
1202 1230 ifindex = 0;
1203 1231 break;
1204 1232 }
1205 1233 ipif = ipif_lookup_addr(addr, NULL, zoneid, ipst);
1206 1234 if (ipif == NULL)
1207 1235 return (EHOSTUNREACH);
1208 1236 /* not supported by the virtual network iface */
1209 1237 if (IS_VNI(ipif->ipif_ill)) {
1210 1238 ipif_refrele(ipif);
1211 1239 return (EINVAL);
1212 1240 }
1213 1241 ifindex = ipif->ipif_ill->ill_phyint->phyint_ifindex;
1214 1242 ipif_refrele(ipif);
1215 1243 break;
1216 1244 case IP_NEXTHOP: {
1217 1245 ire_t *ire;
1218 1246
1219 1247 if (addr == INADDR_ANY) {
1220 1248 /* Clear */
1221 1249 break;
1222 1250 }
1223 1251 /* Verify that the next-hop is on-link */
1224 1252 ire = ire_ftable_lookup_v4(addr, 0, 0, IRE_ONLINK, NULL, zoneid,
1225 1253 NULL, MATCH_IRE_TYPE, 0, ipst, NULL);
1226 1254 if (ire == NULL)
1227 1255 return (EHOSTUNREACH);
1228 1256 ire_refrele(ire);
1229 1257 break;
1230 1258 }
1231 1259 case IP_OPTIONS:
1232 1260 case T_IP_OPTIONS: {
1233 1261 uint_t newlen;
1234 1262
1235 1263 if (ipp->ipp_fields & IPPF_LABEL_V4)
1236 1264 newlen = inlen + (ipp->ipp_label_len_v4 + 3) & ~3;
1237 1265 else
1238 1266 newlen = inlen;
1239 1267 if ((inlen & 0x3) || newlen > IP_MAX_OPT_LENGTH) {
1240 1268 return (EINVAL);
1241 1269 }
1242 1270 break;
1243 1271 }
1244 1272 case IP_PKTINFO: {
1245 1273 struct in_pktinfo *pktinfo;
1246 1274
1247 1275 /* Two different valid lengths */
1248 1276 if (inlen != sizeof (int) &&
1249 1277 inlen != sizeof (struct in_pktinfo))
1250 1278 return (EINVAL);
1251 1279 if (inlen == sizeof (int))
1252 1280 break;
1253 1281
1254 1282 pktinfo = (struct in_pktinfo *)invalp;
1255 1283 if (pktinfo->ipi_spec_dst.s_addr != INADDR_ANY) {
1256 1284 switch (ip_laddr_verify_v4(pktinfo->ipi_spec_dst.s_addr,
1257 1285 zoneid, ipst, B_FALSE)) {
1258 1286 case IPVL_UNICAST_UP:
1259 1287 case IPVL_UNICAST_DOWN:
1260 1288 break;
1261 1289 default:
1262 1290 return (EADDRNOTAVAIL);
1263 1291 }
1264 1292 }
1265 1293 if (!ip_xmit_ifindex_valid(pktinfo->ipi_ifindex, zoneid,
1266 1294 B_FALSE, ipst))
1267 1295 return (ENXIO);
1268 1296 break;
1269 1297 }
1270 1298 case IP_BOUND_IF:
1271 1299 ifindex = *(uint_t *)i1;
1272 1300
1273 1301 /* Just check it is ok. */
1274 1302 if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_FALSE, ipst))
1275 1303 return (ENXIO);
1276 1304 break;
1277 1305 }
1278 1306 if (checkonly)
1279 1307 return (0);
1280 1308
1281 1309 /* Here we set the actual option value */
1282 1310 /*
1283 1311 * conn_lock protects the bitfields, and is used to
1284 1312 * set the fields atomically. Not needed for ixa settings since
1285 1313 * the caller has an exclusive copy of the ixa.
1286 1314 * We can not hold conn_lock across the multicast options though.
1287 1315 */
1288 1316 switch (name) {
1289 1317 case IP_OPTIONS:
1290 1318 case T_IP_OPTIONS:
1291 1319 /* Save options for use by IP. */
1292 1320 mutex_enter(&connp->conn_lock);
1293 1321 error = optcom_pkt_set(invalp, inlen,
1294 1322 (uchar_t **)&ipp->ipp_ipv4_options,
1295 1323 &ipp->ipp_ipv4_options_len);
1296 1324 if (error != 0) {
1297 1325 mutex_exit(&connp->conn_lock);
1298 1326 return (error);
1299 1327 }
1300 1328 if (ipp->ipp_ipv4_options_len == 0) {
1301 1329 ipp->ipp_fields &= ~IPPF_IPV4_OPTIONS;
1302 1330 } else {
1303 1331 ipp->ipp_fields |= IPPF_IPV4_OPTIONS;
1304 1332 }
1305 1333 mutex_exit(&connp->conn_lock);
1306 1334 coa->coa_changed |= COA_HEADER_CHANGED;
1307 1335 coa->coa_changed |= COA_WROFF_CHANGED;
1308 1336 break;
1309 1337
1310 1338 case IP_TTL:
1311 1339 mutex_enter(&connp->conn_lock);
1312 1340 ipp->ipp_unicast_hops = *i1;
1313 1341 mutex_exit(&connp->conn_lock);
1314 1342 coa->coa_changed |= COA_HEADER_CHANGED;
1315 1343 break;
1316 1344 case IP_TOS:
1317 1345 case T_IP_TOS:
1318 1346 mutex_enter(&connp->conn_lock);
1319 1347 if (*i1 == -1) {
1320 1348 ipp->ipp_type_of_service = 0;
1321 1349 } else {
1322 1350 ipp->ipp_type_of_service = *i1;
1323 1351 }
1324 1352 mutex_exit(&connp->conn_lock);
1325 1353 coa->coa_changed |= COA_HEADER_CHANGED;
1326 1354 break;
1327 1355 case IP_MULTICAST_IF:
1328 1356 ixa->ixa_multicast_ifindex = ifindex;
1329 1357 ixa->ixa_multicast_ifaddr = addr;
1330 1358 coa->coa_changed |= COA_ROUTE_CHANGED;
1331 1359 break;
1332 1360 case IP_MULTICAST_TTL:
1333 1361 ixa->ixa_multicast_ttl = *invalp;
1334 1362 /* Handled automatically by ip_output */
1335 1363 break;
1336 1364 case IP_MULTICAST_LOOP:
1337 1365 if (*invalp != 0)
1338 1366 ixa->ixa_flags |= IXAF_MULTICAST_LOOP;
1339 1367 else
1340 1368 ixa->ixa_flags &= ~IXAF_MULTICAST_LOOP;
1341 1369 /* Handled automatically by ip_output */
1342 1370 break;
1343 1371 case IP_RECVOPTS:
1344 1372 mutex_enter(&connp->conn_lock);
1345 1373 connp->conn_recv_ancillary.crb_recvopts = onoff;
1346 1374 mutex_exit(&connp->conn_lock);
1347 1375 break;
1348 1376 case IP_RECVDSTADDR:
1349 1377 mutex_enter(&connp->conn_lock);
1350 1378 connp->conn_recv_ancillary.crb_recvdstaddr = onoff;
1351 1379 mutex_exit(&connp->conn_lock);
1352 1380 break;
1353 1381 case IP_RECVIF:
1354 1382 mutex_enter(&connp->conn_lock);
1355 1383 connp->conn_recv_ancillary.crb_recvif = onoff;
1356 1384 mutex_exit(&connp->conn_lock);
1357 1385 break;
↓ open down ↓ |
572 lines elided |
↑ open up ↑ |
1358 1386 case IP_RECVSLLA:
1359 1387 mutex_enter(&connp->conn_lock);
1360 1388 connp->conn_recv_ancillary.crb_recvslla = onoff;
1361 1389 mutex_exit(&connp->conn_lock);
1362 1390 break;
1363 1391 case IP_RECVTTL:
1364 1392 mutex_enter(&connp->conn_lock);
1365 1393 connp->conn_recv_ancillary.crb_recvttl = onoff;
1366 1394 mutex_exit(&connp->conn_lock);
1367 1395 break;
1396 + case IP_RECVTOS:
1397 + mutex_enter(&connp->conn_lock);
1398 + connp->conn_recv_ancillary.crb_recvtos = onoff;
1399 + mutex_exit(&connp->conn_lock);
1400 + break;
1368 1401 case IP_PKTINFO: {
1369 1402 /*
1370 1403 * This also handles IP_RECVPKTINFO.
1371 1404 * IP_PKTINFO and IP_RECVPKTINFO have same value.
1372 1405 * Differentiation is based on the size of the
1373 1406 * argument passed in.
1374 1407 */
1375 1408 struct in_pktinfo *pktinfo;
1376 1409
1377 1410 if (inlen == sizeof (int)) {
1378 1411 /* This is IP_RECVPKTINFO option. */
1379 1412 mutex_enter(&connp->conn_lock);
1380 1413 connp->conn_recv_ancillary.crb_ip_recvpktinfo =
1381 1414 onoff;
1382 1415 mutex_exit(&connp->conn_lock);
1383 1416 break;
1384 1417 }
1385 1418
1386 1419 /* This is IP_PKTINFO option. */
1387 1420 mutex_enter(&connp->conn_lock);
1388 1421 pktinfo = (struct in_pktinfo *)invalp;
1389 1422 if (pktinfo->ipi_spec_dst.s_addr != INADDR_ANY) {
1390 1423 ipp->ipp_fields |= IPPF_ADDR;
1391 1424 IN6_INADDR_TO_V4MAPPED(&pktinfo->ipi_spec_dst,
1392 1425 &ipp->ipp_addr);
1393 1426 } else {
1394 1427 ipp->ipp_fields &= ~IPPF_ADDR;
1395 1428 ipp->ipp_addr = ipv6_all_zeros;
1396 1429 }
1397 1430 mutex_exit(&connp->conn_lock);
1398 1431 ixa->ixa_ifindex = pktinfo->ipi_ifindex;
1399 1432 coa->coa_changed |= COA_ROUTE_CHANGED;
1400 1433 coa->coa_changed |= COA_HEADER_CHANGED;
1401 1434 break;
1402 1435 }
1403 1436 case IP_DONTFRAG:
1404 1437 if (onoff) {
1405 1438 ixa->ixa_flags |= (IXAF_DONTFRAG | IXAF_PMTU_IPV4_DF);
1406 1439 ixa->ixa_flags &= ~IXAF_PMTU_DISCOVERY;
1407 1440 } else {
1408 1441 ixa->ixa_flags &= ~(IXAF_DONTFRAG | IXAF_PMTU_IPV4_DF);
1409 1442 ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;
1410 1443 }
1411 1444 /* Need to redo ip_attr_connect */
1412 1445 coa->coa_changed |= COA_ROUTE_CHANGED;
1413 1446 break;
1414 1447 case IP_ADD_MEMBERSHIP:
1415 1448 case IP_DROP_MEMBERSHIP:
1416 1449 case MCAST_JOIN_GROUP:
1417 1450 case MCAST_LEAVE_GROUP:
1418 1451 return (ip_opt_set_multicast_group(connp, name,
1419 1452 invalp, B_FALSE, checkonly));
1420 1453
1421 1454 case IP_BLOCK_SOURCE:
1422 1455 case IP_UNBLOCK_SOURCE:
1423 1456 case IP_ADD_SOURCE_MEMBERSHIP:
1424 1457 case IP_DROP_SOURCE_MEMBERSHIP:
1425 1458 case MCAST_BLOCK_SOURCE:
1426 1459 case MCAST_UNBLOCK_SOURCE:
1427 1460 case MCAST_JOIN_SOURCE_GROUP:
1428 1461 case MCAST_LEAVE_SOURCE_GROUP:
1429 1462 return (ip_opt_set_multicast_sources(connp, name,
1430 1463 invalp, B_FALSE, checkonly));
1431 1464
1432 1465 case IP_SEC_OPT:
1433 1466 mutex_enter(&connp->conn_lock);
1434 1467 error = ipsec_set_req(cr, connp, (ipsec_req_t *)invalp);
1435 1468 mutex_exit(&connp->conn_lock);
1436 1469 if (error != 0) {
1437 1470 return (error);
1438 1471 }
1439 1472 /* This is an IPsec policy change - redo ip_attr_connect */
1440 1473 coa->coa_changed |= COA_ROUTE_CHANGED;
1441 1474 break;
1442 1475 case IP_NEXTHOP:
1443 1476 ixa->ixa_nexthop_v4 = addr;
1444 1477 if (addr != INADDR_ANY)
1445 1478 ixa->ixa_flags |= IXAF_NEXTHOP_SET;
1446 1479 else
1447 1480 ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
1448 1481 coa->coa_changed |= COA_ROUTE_CHANGED;
1449 1482 break;
1450 1483
1451 1484 case IP_BOUND_IF:
1452 1485 ixa->ixa_ifindex = ifindex; /* Send */
1453 1486 mutex_enter(&connp->conn_lock);
1454 1487 connp->conn_incoming_ifindex = ifindex; /* Receive */
1455 1488 connp->conn_bound_if = ifindex; /* getsockopt */
1456 1489 mutex_exit(&connp->conn_lock);
1457 1490 coa->coa_changed |= COA_ROUTE_CHANGED;
1458 1491 break;
1459 1492 case IP_UNSPEC_SRC:
1460 1493 mutex_enter(&connp->conn_lock);
1461 1494 connp->conn_unspec_src = onoff;
1462 1495 if (onoff)
1463 1496 ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
1464 1497 else
1465 1498 ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
1466 1499
1467 1500 mutex_exit(&connp->conn_lock);
1468 1501 break;
1469 1502 case IP_BROADCAST_TTL:
1470 1503 ixa->ixa_broadcast_ttl = *invalp;
1471 1504 ixa->ixa_flags |= IXAF_BROADCAST_TTL_SET;
1472 1505 /* Handled automatically by ip_output */
1473 1506 break;
1474 1507 case MRT_INIT:
1475 1508 case MRT_DONE:
1476 1509 case MRT_ADD_VIF:
1477 1510 case MRT_DEL_VIF:
1478 1511 case MRT_ADD_MFC:
1479 1512 case MRT_DEL_MFC:
1480 1513 case MRT_ASSERT:
1481 1514 if ((error = secpolicy_ip_config(cr, B_FALSE)) != 0) {
1482 1515 return (error);
1483 1516 }
1484 1517 error = ip_mrouter_set((int)name, connp, checkonly,
1485 1518 (uchar_t *)invalp, inlen);
1486 1519 if (error) {
1487 1520 return (error);
1488 1521 }
1489 1522 return (0);
1490 1523
1491 1524 }
1492 1525 return (0);
1493 1526 }
1494 1527
1495 1528 /* Handle IPPROTO_IPV6 */
1496 1529 static int
1497 1530 conn_opt_set_ipv6(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
1498 1531 uchar_t *invalp, boolean_t checkonly, cred_t *cr)
1499 1532 {
1500 1533 conn_t *connp = coa->coa_connp;
1501 1534 ip_xmit_attr_t *ixa = coa->coa_ixa;
1502 1535 ip_pkt_t *ipp = coa->coa_ipp;
1503 1536 int *i1 = (int *)invalp;
1504 1537 boolean_t onoff = (*i1 == 0) ? 0 : 1;
1505 1538 uint_t ifindex;
1506 1539 zoneid_t zoneid = IPCL_ZONEID(connp);
1507 1540 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
1508 1541 int error;
1509 1542
1510 1543 if (connp->conn_family != AF_INET6)
1511 1544 return (EINVAL);
1512 1545
1513 1546 ifindex = UINT_MAX;
1514 1547 switch (name) {
1515 1548 case IPV6_MULTICAST_IF:
1516 1549 /*
1517 1550 * The only possible error is EINVAL.
1518 1551 * We call this option on both V4 and V6
1519 1552 * If both fail, then this call returns
1520 1553 * EINVAL. If at least one of them succeeds we
1521 1554 * return success.
1522 1555 */
1523 1556 ifindex = *(uint_t *)i1;
1524 1557
1525 1558 if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_TRUE, ipst) &&
1526 1559 !ip_xmit_ifindex_valid(ifindex, zoneid, B_FALSE, ipst))
1527 1560 return (EINVAL);
1528 1561 break;
1529 1562 case IPV6_UNICAST_HOPS:
1530 1563 /* Don't allow zero. -1 means to use default */
1531 1564 if (*i1 < -1 || *i1 == 0 || *i1 > IPV6_MAX_HOPS)
1532 1565 return (EINVAL);
1533 1566 break;
1534 1567 case IPV6_MULTICAST_HOPS:
1535 1568 /* -1 means use default */
1536 1569 if (*i1 < -1 || *i1 > IPV6_MAX_HOPS)
1537 1570 return (EINVAL);
1538 1571 break;
1539 1572 case IPV6_MULTICAST_LOOP:
1540 1573 if (*i1 != 0 && *i1 != 1)
1541 1574 return (EINVAL);
1542 1575 break;
1543 1576 case IPV6_BOUND_IF:
1544 1577 ifindex = *(uint_t *)i1;
1545 1578
1546 1579 if (!ip_xmit_ifindex_valid(ifindex, zoneid, B_TRUE, ipst))
1547 1580 return (ENXIO);
1548 1581 break;
1549 1582 case IPV6_PKTINFO: {
1550 1583 struct in6_pktinfo *pkti;
1551 1584 boolean_t isv6;
1552 1585
1553 1586 if (inlen != 0 && inlen != sizeof (struct in6_pktinfo))
1554 1587 return (EINVAL);
1555 1588 if (inlen == 0)
1556 1589 break; /* Clear values below */
1557 1590
1558 1591 /*
1559 1592 * Verify the source address and ifindex. Privileged users
1560 1593 * can use any source address.
1561 1594 */
1562 1595 pkti = (struct in6_pktinfo *)invalp;
1563 1596
1564 1597 /*
1565 1598 * For link-local addresses we use the ipi6_ifindex when
1566 1599 * we verify the local address.
1567 1600 * If net_rawaccess then any source address can be used.
1568 1601 */
1569 1602 if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr) &&
1570 1603 secpolicy_net_rawaccess(cr) != 0) {
1571 1604 uint_t scopeid = 0;
1572 1605 in6_addr_t *v6src = &pkti->ipi6_addr;
1573 1606 ipaddr_t v4src;
1574 1607 ip_laddr_t laddr_type = IPVL_UNICAST_UP;
1575 1608
1576 1609 if (IN6_IS_ADDR_V4MAPPED(v6src)) {
1577 1610 IN6_V4MAPPED_TO_IPADDR(v6src, v4src);
1578 1611 if (v4src != INADDR_ANY) {
1579 1612 laddr_type = ip_laddr_verify_v4(v4src,
1580 1613 zoneid, ipst, B_FALSE);
1581 1614 }
1582 1615 } else {
1583 1616 if (IN6_IS_ADDR_LINKSCOPE(v6src))
1584 1617 scopeid = pkti->ipi6_ifindex;
1585 1618
1586 1619 laddr_type = ip_laddr_verify_v6(v6src, zoneid,
1587 1620 ipst, B_FALSE, scopeid);
1588 1621 }
1589 1622 switch (laddr_type) {
1590 1623 case IPVL_UNICAST_UP:
1591 1624 case IPVL_UNICAST_DOWN:
1592 1625 break;
1593 1626 default:
1594 1627 return (EADDRNOTAVAIL);
1595 1628 }
1596 1629 ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
1597 1630 } else if (!IN6_IS_ADDR_UNSPECIFIED(&pkti->ipi6_addr)) {
1598 1631 /* Allow any source */
1599 1632 ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
1600 1633 }
1601 1634 isv6 = !(IN6_IS_ADDR_V4MAPPED(&pkti->ipi6_addr));
1602 1635 if (!ip_xmit_ifindex_valid(pkti->ipi6_ifindex, zoneid, isv6,
1603 1636 ipst))
1604 1637 return (ENXIO);
1605 1638 break;
1606 1639 }
1607 1640 case IPV6_HOPLIMIT:
1608 1641 /* It is only allowed as ancilary data */
1609 1642 if (!coa->coa_ancillary)
1610 1643 return (EINVAL);
1611 1644
1612 1645 if (inlen != 0 && inlen != sizeof (int))
1613 1646 return (EINVAL);
1614 1647 if (inlen == sizeof (int)) {
1615 1648 if (*i1 > 255 || *i1 < -1 || *i1 == 0)
1616 1649 return (EINVAL);
1617 1650 }
1618 1651 break;
1619 1652 case IPV6_TCLASS:
1620 1653 if (inlen != 0 && inlen != sizeof (int))
1621 1654 return (EINVAL);
1622 1655 if (inlen == sizeof (int)) {
1623 1656 if (*i1 > 255 || *i1 < -1)
1624 1657 return (EINVAL);
1625 1658 }
1626 1659 break;
1627 1660 case IPV6_NEXTHOP:
1628 1661 if (inlen != 0 && inlen != sizeof (sin6_t))
1629 1662 return (EINVAL);
1630 1663 if (inlen == sizeof (sin6_t)) {
1631 1664 sin6_t *sin6 = (sin6_t *)invalp;
1632 1665 ire_t *ire;
1633 1666
1634 1667 if (sin6->sin6_family != AF_INET6)
1635 1668 return (EAFNOSUPPORT);
1636 1669 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1637 1670 return (EADDRNOTAVAIL);
1638 1671
1639 1672 /* Verify that the next-hop is on-link */
1640 1673 ire = ire_ftable_lookup_v6(&sin6->sin6_addr,
1641 1674 0, 0, IRE_ONLINK, NULL, zoneid,
1642 1675 NULL, MATCH_IRE_TYPE, 0, ipst, NULL);
1643 1676 if (ire == NULL)
1644 1677 return (EHOSTUNREACH);
1645 1678 ire_refrele(ire);
1646 1679 break;
1647 1680 }
1648 1681 break;
1649 1682 case IPV6_RTHDR:
1650 1683 case IPV6_DSTOPTS:
1651 1684 case IPV6_RTHDRDSTOPTS:
1652 1685 case IPV6_HOPOPTS: {
1653 1686 /* All have the length field in the same place */
1654 1687 ip6_hbh_t *hopts = (ip6_hbh_t *)invalp;
1655 1688 /*
1656 1689 * Sanity checks - minimum size, size a multiple of
1657 1690 * eight bytes, and matching size passed in.
1658 1691 */
1659 1692 if (inlen != 0 &&
1660 1693 inlen != (8 * (hopts->ip6h_len + 1)))
1661 1694 return (EINVAL);
1662 1695 break;
1663 1696 }
1664 1697 case IPV6_PATHMTU:
1665 1698 /* Can't be set */
1666 1699 return (EINVAL);
1667 1700
1668 1701 case IPV6_USE_MIN_MTU:
1669 1702 if (inlen != sizeof (int))
1670 1703 return (EINVAL);
1671 1704 if (*i1 < -1 || *i1 > 1)
1672 1705 return (EINVAL);
1673 1706 break;
1674 1707 case IPV6_SRC_PREFERENCES:
1675 1708 if (inlen != sizeof (uint32_t))
1676 1709 return (EINVAL);
1677 1710 break;
1678 1711 case IPV6_V6ONLY:
1679 1712 if (*i1 < 0 || *i1 > 1) {
1680 1713 return (EINVAL);
1681 1714 }
1682 1715 break;
1683 1716 }
1684 1717 if (checkonly)
1685 1718 return (0);
1686 1719
1687 1720 /* Here we set the actual option value */
1688 1721 /*
1689 1722 * conn_lock protects the bitfields, and is used to
1690 1723 * set the fields atomically. Not needed for ixa settings since
1691 1724 * the caller has an exclusive copy of the ixa.
1692 1725 * We can not hold conn_lock across the multicast options though.
1693 1726 */
1694 1727 ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
1695 1728 switch (name) {
1696 1729 case IPV6_MULTICAST_IF:
1697 1730 ixa->ixa_multicast_ifindex = ifindex;
1698 1731 /* Need to redo ip_attr_connect */
1699 1732 coa->coa_changed |= COA_ROUTE_CHANGED;
1700 1733 break;
1701 1734 case IPV6_UNICAST_HOPS:
1702 1735 /* -1 means use default */
1703 1736 mutex_enter(&connp->conn_lock);
1704 1737 if (*i1 == -1) {
1705 1738 ipp->ipp_unicast_hops = connp->conn_default_ttl;
1706 1739 } else {
1707 1740 ipp->ipp_unicast_hops = (uint8_t)*i1;
1708 1741 }
1709 1742 mutex_exit(&connp->conn_lock);
1710 1743 coa->coa_changed |= COA_HEADER_CHANGED;
1711 1744 break;
1712 1745 case IPV6_MULTICAST_HOPS:
1713 1746 /* -1 means use default */
1714 1747 if (*i1 == -1) {
1715 1748 ixa->ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1716 1749 } else {
1717 1750 ixa->ixa_multicast_ttl = (uint8_t)*i1;
1718 1751 }
1719 1752 /* Handled automatically by ip_output */
1720 1753 break;
1721 1754 case IPV6_MULTICAST_LOOP:
1722 1755 if (*i1 != 0)
1723 1756 ixa->ixa_flags |= IXAF_MULTICAST_LOOP;
1724 1757 else
1725 1758 ixa->ixa_flags &= ~IXAF_MULTICAST_LOOP;
1726 1759 /* Handled automatically by ip_output */
1727 1760 break;
1728 1761 case IPV6_JOIN_GROUP:
1729 1762 case IPV6_LEAVE_GROUP:
1730 1763 case MCAST_JOIN_GROUP:
1731 1764 case MCAST_LEAVE_GROUP:
1732 1765 return (ip_opt_set_multicast_group(connp, name,
1733 1766 invalp, B_TRUE, checkonly));
1734 1767
1735 1768 case MCAST_BLOCK_SOURCE:
1736 1769 case MCAST_UNBLOCK_SOURCE:
1737 1770 case MCAST_JOIN_SOURCE_GROUP:
1738 1771 case MCAST_LEAVE_SOURCE_GROUP:
1739 1772 return (ip_opt_set_multicast_sources(connp, name,
1740 1773 invalp, B_TRUE, checkonly));
1741 1774
1742 1775 case IPV6_BOUND_IF:
1743 1776 ixa->ixa_ifindex = ifindex; /* Send */
1744 1777 mutex_enter(&connp->conn_lock);
1745 1778 connp->conn_incoming_ifindex = ifindex; /* Receive */
1746 1779 connp->conn_bound_if = ifindex; /* getsockopt */
1747 1780 mutex_exit(&connp->conn_lock);
1748 1781 coa->coa_changed |= COA_ROUTE_CHANGED;
1749 1782 break;
1750 1783 case IPV6_UNSPEC_SRC:
1751 1784 mutex_enter(&connp->conn_lock);
1752 1785 connp->conn_unspec_src = onoff;
1753 1786 if (onoff)
1754 1787 ixa->ixa_flags &= ~IXAF_VERIFY_SOURCE;
1755 1788 else
1756 1789 ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
1757 1790 mutex_exit(&connp->conn_lock);
1758 1791 break;
1759 1792 case IPV6_RECVPKTINFO:
1760 1793 mutex_enter(&connp->conn_lock);
1761 1794 connp->conn_recv_ancillary.crb_ip_recvpktinfo = onoff;
1762 1795 mutex_exit(&connp->conn_lock);
1763 1796 break;
1764 1797 case IPV6_RECVTCLASS:
1765 1798 mutex_enter(&connp->conn_lock);
1766 1799 connp->conn_recv_ancillary.crb_ipv6_recvtclass = onoff;
1767 1800 mutex_exit(&connp->conn_lock);
1768 1801 break;
1769 1802 case IPV6_RECVPATHMTU:
1770 1803 mutex_enter(&connp->conn_lock);
1771 1804 connp->conn_ipv6_recvpathmtu = onoff;
1772 1805 mutex_exit(&connp->conn_lock);
1773 1806 break;
1774 1807 case IPV6_RECVHOPLIMIT:
1775 1808 mutex_enter(&connp->conn_lock);
1776 1809 connp->conn_recv_ancillary.crb_ipv6_recvhoplimit =
1777 1810 onoff;
1778 1811 mutex_exit(&connp->conn_lock);
1779 1812 break;
1780 1813 case IPV6_RECVHOPOPTS:
1781 1814 mutex_enter(&connp->conn_lock);
1782 1815 connp->conn_recv_ancillary.crb_ipv6_recvhopopts = onoff;
1783 1816 mutex_exit(&connp->conn_lock);
1784 1817 break;
1785 1818 case IPV6_RECVDSTOPTS:
1786 1819 mutex_enter(&connp->conn_lock);
1787 1820 connp->conn_recv_ancillary.crb_ipv6_recvdstopts = onoff;
1788 1821 mutex_exit(&connp->conn_lock);
1789 1822 break;
1790 1823 case _OLD_IPV6_RECVDSTOPTS:
1791 1824 mutex_enter(&connp->conn_lock);
1792 1825 connp->conn_recv_ancillary.crb_old_ipv6_recvdstopts =
1793 1826 onoff;
1794 1827 mutex_exit(&connp->conn_lock);
1795 1828 break;
1796 1829 case IPV6_RECVRTHDRDSTOPTS:
1797 1830 mutex_enter(&connp->conn_lock);
1798 1831 connp->conn_recv_ancillary.crb_ipv6_recvrthdrdstopts =
1799 1832 onoff;
1800 1833 mutex_exit(&connp->conn_lock);
1801 1834 break;
1802 1835 case IPV6_RECVRTHDR:
1803 1836 mutex_enter(&connp->conn_lock);
1804 1837 connp->conn_recv_ancillary.crb_ipv6_recvrthdr = onoff;
1805 1838 mutex_exit(&connp->conn_lock);
1806 1839 break;
1807 1840 case IPV6_PKTINFO:
1808 1841 mutex_enter(&connp->conn_lock);
1809 1842 if (inlen == 0) {
1810 1843 ipp->ipp_fields &= ~IPPF_ADDR;
1811 1844 ipp->ipp_addr = ipv6_all_zeros;
1812 1845 ixa->ixa_ifindex = 0;
1813 1846 } else {
1814 1847 struct in6_pktinfo *pkti;
1815 1848
1816 1849 pkti = (struct in6_pktinfo *)invalp;
1817 1850 ipp->ipp_addr = pkti->ipi6_addr;
1818 1851 if (!IN6_IS_ADDR_UNSPECIFIED(&ipp->ipp_addr))
1819 1852 ipp->ipp_fields |= IPPF_ADDR;
1820 1853 else
1821 1854 ipp->ipp_fields &= ~IPPF_ADDR;
1822 1855 ixa->ixa_ifindex = pkti->ipi6_ifindex;
1823 1856 }
1824 1857 mutex_exit(&connp->conn_lock);
1825 1858 /* Source and ifindex might have changed */
1826 1859 coa->coa_changed |= COA_HEADER_CHANGED;
1827 1860 coa->coa_changed |= COA_ROUTE_CHANGED;
1828 1861 break;
1829 1862 case IPV6_HOPLIMIT:
1830 1863 mutex_enter(&connp->conn_lock);
1831 1864 if (inlen == 0 || *i1 == -1) {
1832 1865 /* Revert to default */
1833 1866 ipp->ipp_fields &= ~IPPF_HOPLIMIT;
1834 1867 ixa->ixa_flags &= ~IXAF_NO_TTL_CHANGE;
1835 1868 } else {
1836 1869 ipp->ipp_hoplimit = *i1;
1837 1870 ipp->ipp_fields |= IPPF_HOPLIMIT;
1838 1871 /* Ensure that it sticks for multicast packets */
1839 1872 ixa->ixa_flags |= IXAF_NO_TTL_CHANGE;
1840 1873 }
1841 1874 mutex_exit(&connp->conn_lock);
1842 1875 coa->coa_changed |= COA_HEADER_CHANGED;
1843 1876 break;
1844 1877 case IPV6_TCLASS:
1845 1878 /*
1846 1879 * IPV6_TCLASS accepts -1 as use kernel default
1847 1880 * and [0, 255] as the actualy traffic class.
1848 1881 */
1849 1882 mutex_enter(&connp->conn_lock);
1850 1883 if (inlen == 0 || *i1 == -1) {
1851 1884 ipp->ipp_tclass = 0;
1852 1885 ipp->ipp_fields &= ~IPPF_TCLASS;
1853 1886 } else {
1854 1887 ipp->ipp_tclass = *i1;
1855 1888 ipp->ipp_fields |= IPPF_TCLASS;
1856 1889 }
1857 1890 mutex_exit(&connp->conn_lock);
1858 1891 coa->coa_changed |= COA_HEADER_CHANGED;
1859 1892 break;
1860 1893 case IPV6_NEXTHOP:
1861 1894 if (inlen == 0) {
1862 1895 ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
1863 1896 } else {
1864 1897 sin6_t *sin6 = (sin6_t *)invalp;
1865 1898
1866 1899 ixa->ixa_nexthop_v6 = sin6->sin6_addr;
1867 1900 if (!IN6_IS_ADDR_UNSPECIFIED(&ixa->ixa_nexthop_v6))
1868 1901 ixa->ixa_flags |= IXAF_NEXTHOP_SET;
1869 1902 else
1870 1903 ixa->ixa_flags &= ~IXAF_NEXTHOP_SET;
1871 1904 }
1872 1905 coa->coa_changed |= COA_ROUTE_CHANGED;
1873 1906 break;
1874 1907 case IPV6_HOPOPTS:
1875 1908 mutex_enter(&connp->conn_lock);
1876 1909 error = optcom_pkt_set(invalp, inlen,
1877 1910 (uchar_t **)&ipp->ipp_hopopts, &ipp->ipp_hopoptslen);
1878 1911 if (error != 0) {
1879 1912 mutex_exit(&connp->conn_lock);
1880 1913 return (error);
1881 1914 }
1882 1915 if (ipp->ipp_hopoptslen == 0) {
1883 1916 ipp->ipp_fields &= ~IPPF_HOPOPTS;
1884 1917 } else {
1885 1918 ipp->ipp_fields |= IPPF_HOPOPTS;
1886 1919 }
1887 1920 mutex_exit(&connp->conn_lock);
1888 1921 coa->coa_changed |= COA_HEADER_CHANGED;
1889 1922 coa->coa_changed |= COA_WROFF_CHANGED;
1890 1923 break;
1891 1924 case IPV6_RTHDRDSTOPTS:
1892 1925 mutex_enter(&connp->conn_lock);
1893 1926 error = optcom_pkt_set(invalp, inlen,
1894 1927 (uchar_t **)&ipp->ipp_rthdrdstopts,
1895 1928 &ipp->ipp_rthdrdstoptslen);
1896 1929 if (error != 0) {
1897 1930 mutex_exit(&connp->conn_lock);
1898 1931 return (error);
1899 1932 }
1900 1933 if (ipp->ipp_rthdrdstoptslen == 0) {
1901 1934 ipp->ipp_fields &= ~IPPF_RTHDRDSTOPTS;
1902 1935 } else {
1903 1936 ipp->ipp_fields |= IPPF_RTHDRDSTOPTS;
1904 1937 }
1905 1938 mutex_exit(&connp->conn_lock);
1906 1939 coa->coa_changed |= COA_HEADER_CHANGED;
1907 1940 coa->coa_changed |= COA_WROFF_CHANGED;
1908 1941 break;
1909 1942 case IPV6_DSTOPTS:
1910 1943 mutex_enter(&connp->conn_lock);
1911 1944 error = optcom_pkt_set(invalp, inlen,
1912 1945 (uchar_t **)&ipp->ipp_dstopts, &ipp->ipp_dstoptslen);
1913 1946 if (error != 0) {
1914 1947 mutex_exit(&connp->conn_lock);
1915 1948 return (error);
1916 1949 }
1917 1950 if (ipp->ipp_dstoptslen == 0) {
1918 1951 ipp->ipp_fields &= ~IPPF_DSTOPTS;
1919 1952 } else {
1920 1953 ipp->ipp_fields |= IPPF_DSTOPTS;
1921 1954 }
1922 1955 mutex_exit(&connp->conn_lock);
1923 1956 coa->coa_changed |= COA_HEADER_CHANGED;
1924 1957 coa->coa_changed |= COA_WROFF_CHANGED;
1925 1958 break;
1926 1959 case IPV6_RTHDR:
1927 1960 mutex_enter(&connp->conn_lock);
1928 1961 error = optcom_pkt_set(invalp, inlen,
1929 1962 (uchar_t **)&ipp->ipp_rthdr, &ipp->ipp_rthdrlen);
1930 1963 if (error != 0) {
1931 1964 mutex_exit(&connp->conn_lock);
1932 1965 return (error);
1933 1966 }
1934 1967 if (ipp->ipp_rthdrlen == 0) {
1935 1968 ipp->ipp_fields &= ~IPPF_RTHDR;
1936 1969 } else {
1937 1970 ipp->ipp_fields |= IPPF_RTHDR;
1938 1971 }
1939 1972 mutex_exit(&connp->conn_lock);
1940 1973 coa->coa_changed |= COA_HEADER_CHANGED;
1941 1974 coa->coa_changed |= COA_WROFF_CHANGED;
1942 1975 break;
1943 1976
1944 1977 case IPV6_DONTFRAG:
1945 1978 if (onoff) {
1946 1979 ixa->ixa_flags |= IXAF_DONTFRAG;
1947 1980 ixa->ixa_flags &= ~IXAF_PMTU_DISCOVERY;
1948 1981 } else {
1949 1982 ixa->ixa_flags &= ~IXAF_DONTFRAG;
1950 1983 ixa->ixa_flags |= IXAF_PMTU_DISCOVERY;
1951 1984 }
1952 1985 /* Need to redo ip_attr_connect */
1953 1986 coa->coa_changed |= COA_ROUTE_CHANGED;
1954 1987 break;
1955 1988
1956 1989 case IPV6_USE_MIN_MTU:
1957 1990 ixa->ixa_flags |= IXAF_USE_MIN_MTU;
1958 1991 ixa->ixa_use_min_mtu = *i1;
1959 1992 /* Need to redo ip_attr_connect */
1960 1993 coa->coa_changed |= COA_ROUTE_CHANGED;
1961 1994 break;
1962 1995
1963 1996 case IPV6_SEC_OPT:
1964 1997 mutex_enter(&connp->conn_lock);
1965 1998 error = ipsec_set_req(cr, connp, (ipsec_req_t *)invalp);
1966 1999 mutex_exit(&connp->conn_lock);
1967 2000 if (error != 0) {
1968 2001 return (error);
1969 2002 }
1970 2003 /* This is an IPsec policy change - redo ip_attr_connect */
1971 2004 coa->coa_changed |= COA_ROUTE_CHANGED;
1972 2005 break;
1973 2006 case IPV6_SRC_PREFERENCES:
1974 2007 /*
1975 2008 * This socket option only affects connected
1976 2009 * sockets that haven't already bound to a specific
1977 2010 * IPv6 address. In other words, sockets that
1978 2011 * don't call bind() with an address other than the
1979 2012 * unspecified address and that call connect().
1980 2013 * ip_set_destination_v6() passes these preferences
1981 2014 * to the ipif_select_source_v6() function.
1982 2015 */
1983 2016 mutex_enter(&connp->conn_lock);
1984 2017 error = ip6_set_src_preferences(ixa, *(uint32_t *)invalp);
1985 2018 mutex_exit(&connp->conn_lock);
1986 2019 if (error != 0) {
1987 2020 return (error);
1988 2021 }
1989 2022 break;
1990 2023 case IPV6_V6ONLY:
1991 2024 mutex_enter(&connp->conn_lock);
1992 2025 connp->conn_ipv6_v6only = onoff;
1993 2026 mutex_exit(&connp->conn_lock);
1994 2027 break;
1995 2028 }
1996 2029 return (0);
1997 2030 }
1998 2031
1999 2032 /* Handle IPPROTO_UDP */
2000 2033 /* ARGSUSED1 */
2001 2034 static int
2002 2035 conn_opt_set_udp(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
2003 2036 uchar_t *invalp, boolean_t checkonly, cred_t *cr)
2004 2037 {
2005 2038 conn_t *connp = coa->coa_connp;
2006 2039 int *i1 = (int *)invalp;
2007 2040 boolean_t onoff = (*i1 == 0) ? 0 : 1;
2008 2041 int error;
2009 2042
2010 2043 switch (name) {
2011 2044 case UDP_ANONPRIVBIND:
2012 2045 if ((error = secpolicy_net_privaddr(cr, 0, IPPROTO_UDP)) != 0) {
2013 2046 return (error);
2014 2047 }
2015 2048 break;
2016 2049 }
2017 2050 if (checkonly)
2018 2051 return (0);
2019 2052
2020 2053 /* Here we set the actual option value */
2021 2054 mutex_enter(&connp->conn_lock);
2022 2055 switch (name) {
2023 2056 case UDP_ANONPRIVBIND:
2024 2057 connp->conn_anon_priv_bind = onoff;
2025 2058 break;
2026 2059 case UDP_EXCLBIND:
2027 2060 connp->conn_exclbind = onoff;
2028 2061 break;
2029 2062 }
2030 2063 mutex_exit(&connp->conn_lock);
2031 2064 return (0);
2032 2065 }
2033 2066
2034 2067 /* Handle IPPROTO_TCP */
2035 2068 /* ARGSUSED1 */
2036 2069 static int
2037 2070 conn_opt_set_tcp(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
2038 2071 uchar_t *invalp, boolean_t checkonly, cred_t *cr)
2039 2072 {
2040 2073 conn_t *connp = coa->coa_connp;
2041 2074 int *i1 = (int *)invalp;
2042 2075 boolean_t onoff = (*i1 == 0) ? 0 : 1;
2043 2076 int error;
2044 2077
2045 2078 switch (name) {
2046 2079 case TCP_ANONPRIVBIND:
2047 2080 if ((error = secpolicy_net_privaddr(cr, 0, IPPROTO_TCP)) != 0) {
2048 2081 return (error);
2049 2082 }
2050 2083 break;
2051 2084 }
2052 2085 if (checkonly)
2053 2086 return (0);
2054 2087
2055 2088 /* Here we set the actual option value */
2056 2089 mutex_enter(&connp->conn_lock);
2057 2090 switch (name) {
2058 2091 case TCP_ANONPRIVBIND:
2059 2092 connp->conn_anon_priv_bind = onoff;
2060 2093 break;
2061 2094 case TCP_EXCLBIND:
2062 2095 connp->conn_exclbind = onoff;
2063 2096 break;
2064 2097 case TCP_RECVDSTADDR:
2065 2098 connp->conn_recv_ancillary.crb_recvdstaddr = onoff;
2066 2099 break;
2067 2100 }
2068 2101 mutex_exit(&connp->conn_lock);
2069 2102 return (0);
2070 2103 }
2071 2104
2072 2105 int
2073 2106 conn_getsockname(conn_t *connp, struct sockaddr *sa, uint_t *salenp)
2074 2107 {
2075 2108 sin_t *sin;
2076 2109 sin6_t *sin6;
2077 2110
2078 2111 if (connp->conn_family == AF_INET) {
2079 2112 if (*salenp < sizeof (sin_t))
2080 2113 return (EINVAL);
2081 2114
2082 2115 *salenp = sizeof (sin_t);
2083 2116 /* Fill zeroes and then initialize non-zero fields */
2084 2117 sin = (sin_t *)sa;
2085 2118 *sin = sin_null;
2086 2119 sin->sin_family = AF_INET;
2087 2120 if (!IN6_IS_ADDR_V4MAPPED_ANY(&connp->conn_saddr_v6) &&
2088 2121 !IN6_IS_ADDR_UNSPECIFIED(&connp->conn_saddr_v6)) {
2089 2122 sin->sin_addr.s_addr = connp->conn_saddr_v4;
2090 2123 } else {
2091 2124 /*
2092 2125 * INADDR_ANY
2093 2126 * conn_saddr is not set, we might be bound to
2094 2127 * broadcast/multicast. Use conn_bound_addr as
2095 2128 * local address instead (that could
2096 2129 * also still be INADDR_ANY)
2097 2130 */
2098 2131 sin->sin_addr.s_addr = connp->conn_bound_addr_v4;
2099 2132 }
2100 2133 sin->sin_port = connp->conn_lport;
2101 2134 } else {
2102 2135 if (*salenp < sizeof (sin6_t))
2103 2136 return (EINVAL);
2104 2137
2105 2138 *salenp = sizeof (sin6_t);
2106 2139 /* Fill zeroes and then initialize non-zero fields */
2107 2140 sin6 = (sin6_t *)sa;
2108 2141 *sin6 = sin6_null;
2109 2142 sin6->sin6_family = AF_INET6;
2110 2143 if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_saddr_v6)) {
2111 2144 sin6->sin6_addr = connp->conn_saddr_v6;
2112 2145 } else {
2113 2146 /*
2114 2147 * conn_saddr is not set, we might be bound to
2115 2148 * broadcast/multicast. Use conn_bound_addr as
2116 2149 * local address instead (which could
2117 2150 * also still be unspecified)
2118 2151 */
2119 2152 sin6->sin6_addr = connp->conn_bound_addr_v6;
2120 2153 }
2121 2154 sin6->sin6_port = connp->conn_lport;
2122 2155 if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
2123 2156 (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET))
2124 2157 sin6->sin6_scope_id = connp->conn_ixa->ixa_scopeid;
2125 2158 }
2126 2159 return (0);
2127 2160 }
2128 2161
2129 2162 int
2130 2163 conn_getpeername(conn_t *connp, struct sockaddr *sa, uint_t *salenp)
2131 2164 {
2132 2165 struct sockaddr_in *sin;
2133 2166 struct sockaddr_in6 *sin6;
2134 2167
2135 2168 if (connp->conn_family == AF_INET) {
2136 2169 if (*salenp < sizeof (sin_t))
2137 2170 return (EINVAL);
2138 2171
2139 2172 *salenp = sizeof (sin_t);
2140 2173 /* initialize */
2141 2174 sin = (sin_t *)sa;
2142 2175 *sin = sin_null;
2143 2176 sin->sin_family = AF_INET;
2144 2177 sin->sin_addr.s_addr = connp->conn_faddr_v4;
2145 2178 sin->sin_port = connp->conn_fport;
2146 2179 } else {
2147 2180 if (*salenp < sizeof (sin6_t))
2148 2181 return (EINVAL);
2149 2182
2150 2183 *salenp = sizeof (sin6_t);
2151 2184 /* initialize */
2152 2185 sin6 = (sin6_t *)sa;
2153 2186 *sin6 = sin6_null;
2154 2187 sin6->sin6_family = AF_INET6;
2155 2188 sin6->sin6_addr = connp->conn_faddr_v6;
2156 2189 sin6->sin6_port = connp->conn_fport;
2157 2190 sin6->sin6_flowinfo = connp->conn_flowinfo;
2158 2191 if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
2159 2192 (connp->conn_ixa->ixa_flags & IXAF_SCOPEID_SET))
2160 2193 sin6->sin6_scope_id = connp->conn_ixa->ixa_scopeid;
2161 2194 }
2162 2195 return (0);
2163 2196 }
2164 2197
2165 2198 static uint32_t cksum_massage_options_v4(ipha_t *, netstack_t *);
2166 2199 static uint32_t cksum_massage_options_v6(ip6_t *, uint_t, netstack_t *);
2167 2200
2168 2201 /*
2169 2202 * Allocate and fill in conn_ht_iphc based on the current information
2170 2203 * in the conn.
2171 2204 * Normally used when we bind() and connect().
2172 2205 * Returns failure if can't allocate memory, or if there is a problem
2173 2206 * with a routing header/option.
2174 2207 *
2175 2208 * We allocate space for the transport header (ulp_hdr_len + extra) and
2176 2209 * indicate the offset of the ulp header by setting ixa_ip_hdr_length.
2177 2210 * The extra is there for transports that want some spare room for future
2178 2211 * options. conn_ht_iphc_allocated is what was allocated; conn_ht_iphc_len
2179 2212 * excludes the extra part.
2180 2213 *
2181 2214 * We massage an routing option/header and store the ckecksum difference
2182 2215 * in conn_sum.
2183 2216 *
2184 2217 * Caller needs to update conn_wroff if desired.
2185 2218 */
2186 2219 int
2187 2220 conn_build_hdr_template(conn_t *connp, uint_t ulp_hdr_length, uint_t extra,
2188 2221 const in6_addr_t *v6src, const in6_addr_t *v6dst, uint32_t flowinfo)
2189 2222 {
2190 2223 ip_xmit_attr_t *ixa = connp->conn_ixa;
2191 2224 ip_pkt_t *ipp = &connp->conn_xmit_ipp;
2192 2225 uint_t ip_hdr_length;
2193 2226 uchar_t *hdrs;
2194 2227 uint_t hdrs_len;
2195 2228
2196 2229 ASSERT(MUTEX_HELD(&connp->conn_lock));
2197 2230
2198 2231 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2199 2232 ip_hdr_length = ip_total_hdrs_len_v4(ipp);
2200 2233 /* In case of TX label and IP options it can be too much */
2201 2234 if (ip_hdr_length > IP_MAX_HDR_LENGTH) {
2202 2235 /* Preserves existing TX errno for this */
2203 2236 return (EHOSTUNREACH);
2204 2237 }
2205 2238 } else {
2206 2239 ip_hdr_length = ip_total_hdrs_len_v6(ipp);
2207 2240 }
2208 2241 ixa->ixa_ip_hdr_length = ip_hdr_length;
2209 2242 hdrs_len = ip_hdr_length + ulp_hdr_length + extra;
2210 2243 ASSERT(hdrs_len != 0);
2211 2244
2212 2245 if (hdrs_len != connp->conn_ht_iphc_allocated) {
2213 2246 /* Allocate new before we free any old */
2214 2247 hdrs = kmem_alloc(hdrs_len, KM_NOSLEEP);
2215 2248 if (hdrs == NULL)
2216 2249 return (ENOMEM);
2217 2250
2218 2251 if (connp->conn_ht_iphc != NULL) {
2219 2252 kmem_free(connp->conn_ht_iphc,
2220 2253 connp->conn_ht_iphc_allocated);
2221 2254 }
2222 2255 connp->conn_ht_iphc = hdrs;
2223 2256 connp->conn_ht_iphc_allocated = hdrs_len;
2224 2257 } else {
2225 2258 hdrs = connp->conn_ht_iphc;
2226 2259 }
2227 2260 hdrs_len -= extra;
2228 2261 connp->conn_ht_iphc_len = hdrs_len;
2229 2262
2230 2263 connp->conn_ht_ulp = hdrs + ip_hdr_length;
2231 2264 connp->conn_ht_ulp_len = ulp_hdr_length;
2232 2265
2233 2266 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2234 2267 ipha_t *ipha = (ipha_t *)hdrs;
2235 2268
2236 2269 IN6_V4MAPPED_TO_IPADDR(v6src, ipha->ipha_src);
2237 2270 IN6_V4MAPPED_TO_IPADDR(v6dst, ipha->ipha_dst);
2238 2271 ip_build_hdrs_v4(hdrs, ip_hdr_length, ipp, connp->conn_proto);
2239 2272 ipha->ipha_length = htons(hdrs_len);
2240 2273 if (ixa->ixa_flags & IXAF_PMTU_IPV4_DF)
2241 2274 ipha->ipha_fragment_offset_and_flags |= IPH_DF_HTONS;
2242 2275 else
2243 2276 ipha->ipha_fragment_offset_and_flags &= ~IPH_DF_HTONS;
2244 2277
2245 2278 if (ipp->ipp_fields & IPPF_IPV4_OPTIONS) {
2246 2279 connp->conn_sum = cksum_massage_options_v4(ipha,
2247 2280 connp->conn_netstack);
2248 2281 } else {
2249 2282 connp->conn_sum = 0;
2250 2283 }
2251 2284 } else {
2252 2285 ip6_t *ip6h = (ip6_t *)hdrs;
2253 2286
2254 2287 ip6h->ip6_src = *v6src;
2255 2288 ip6h->ip6_dst = *v6dst;
2256 2289 ip_build_hdrs_v6(hdrs, ip_hdr_length, ipp, connp->conn_proto,
2257 2290 flowinfo);
2258 2291 ip6h->ip6_plen = htons(hdrs_len - IPV6_HDR_LEN);
2259 2292
2260 2293 if (ipp->ipp_fields & IPPF_RTHDR) {
2261 2294 connp->conn_sum = cksum_massage_options_v6(ip6h,
2262 2295 ip_hdr_length, connp->conn_netstack);
2263 2296
2264 2297 /*
2265 2298 * Verify that the first hop isn't a mapped address.
2266 2299 * Routers along the path need to do this verification
2267 2300 * for subsequent hops.
2268 2301 */
2269 2302 if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst))
2270 2303 return (EADDRNOTAVAIL);
2271 2304
2272 2305 } else {
2273 2306 connp->conn_sum = 0;
2274 2307 }
2275 2308 }
2276 2309 return (0);
2277 2310 }
2278 2311
2279 2312 /*
2280 2313 * Prepend a header template to data_mp based on the ip_pkt_t
2281 2314 * and the passed in source, destination and protocol.
2282 2315 *
2283 2316 * Returns failure if can't allocate memory, in which case data_mp is freed.
2284 2317 * We allocate space for the transport header (ulp_hdr_len) and
2285 2318 * indicate the offset of the ulp header by setting ixa_ip_hdr_length.
2286 2319 *
2287 2320 * We massage an routing option/header and return the ckecksum difference
2288 2321 * in *sump. This is in host byte order.
2289 2322 *
2290 2323 * Caller needs to update conn_wroff if desired.
2291 2324 */
2292 2325 mblk_t *
2293 2326 conn_prepend_hdr(ip_xmit_attr_t *ixa, const ip_pkt_t *ipp,
2294 2327 const in6_addr_t *v6src, const in6_addr_t *v6dst,
2295 2328 uint8_t protocol, uint32_t flowinfo, uint_t ulp_hdr_length, mblk_t *data_mp,
2296 2329 uint_t data_length, uint_t wroff_extra, uint32_t *sump, int *errorp)
2297 2330 {
2298 2331 uint_t ip_hdr_length;
2299 2332 uchar_t *hdrs;
2300 2333 uint_t hdrs_len;
2301 2334 mblk_t *mp;
2302 2335
2303 2336 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2304 2337 ip_hdr_length = ip_total_hdrs_len_v4(ipp);
2305 2338 ASSERT(ip_hdr_length <= IP_MAX_HDR_LENGTH);
2306 2339 } else {
2307 2340 ip_hdr_length = ip_total_hdrs_len_v6(ipp);
2308 2341 }
2309 2342 hdrs_len = ip_hdr_length + ulp_hdr_length;
2310 2343 ASSERT(hdrs_len != 0);
2311 2344
2312 2345 ixa->ixa_ip_hdr_length = ip_hdr_length;
2313 2346
2314 2347 /* Can we prepend to data_mp? */
2315 2348 if (data_mp != NULL &&
2316 2349 data_mp->b_rptr - data_mp->b_datap->db_base >= hdrs_len &&
2317 2350 data_mp->b_datap->db_ref == 1) {
2318 2351 hdrs = data_mp->b_rptr - hdrs_len;
2319 2352 data_mp->b_rptr = hdrs;
2320 2353 mp = data_mp;
2321 2354 } else {
2322 2355 mp = allocb(hdrs_len + wroff_extra, BPRI_MED);
2323 2356 if (mp == NULL) {
2324 2357 freemsg(data_mp);
2325 2358 *errorp = ENOMEM;
2326 2359 return (NULL);
2327 2360 }
2328 2361 mp->b_wptr = mp->b_datap->db_lim;
2329 2362 hdrs = mp->b_rptr = mp->b_wptr - hdrs_len;
2330 2363 mp->b_cont = data_mp;
2331 2364 }
2332 2365
2333 2366 /*
2334 2367 * Set the source in the header. ip_build_hdrs_v4/v6 will overwrite it
2335 2368 * if PKTINFO (aka IPPF_ADDR) was set.
2336 2369 */
2337 2370 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2338 2371 ipha_t *ipha = (ipha_t *)hdrs;
2339 2372
2340 2373 ASSERT(IN6_IS_ADDR_V4MAPPED(v6dst));
2341 2374 IN6_V4MAPPED_TO_IPADDR(v6src, ipha->ipha_src);
2342 2375 IN6_V4MAPPED_TO_IPADDR(v6dst, ipha->ipha_dst);
2343 2376 ip_build_hdrs_v4(hdrs, ip_hdr_length, ipp, protocol);
2344 2377 ipha->ipha_length = htons(hdrs_len + data_length);
2345 2378 if (ixa->ixa_flags & IXAF_PMTU_IPV4_DF)
2346 2379 ipha->ipha_fragment_offset_and_flags |= IPH_DF_HTONS;
2347 2380 else
2348 2381 ipha->ipha_fragment_offset_and_flags &= ~IPH_DF_HTONS;
2349 2382
2350 2383 if (ipp->ipp_fields & IPPF_IPV4_OPTIONS) {
2351 2384 *sump = cksum_massage_options_v4(ipha,
2352 2385 ixa->ixa_ipst->ips_netstack);
2353 2386 } else {
2354 2387 *sump = 0;
2355 2388 }
2356 2389 } else {
2357 2390 ip6_t *ip6h = (ip6_t *)hdrs;
2358 2391
2359 2392 ip6h->ip6_src = *v6src;
2360 2393 ip6h->ip6_dst = *v6dst;
2361 2394 ip_build_hdrs_v6(hdrs, ip_hdr_length, ipp, protocol, flowinfo);
2362 2395 ip6h->ip6_plen = htons(hdrs_len + data_length - IPV6_HDR_LEN);
2363 2396
2364 2397 if (ipp->ipp_fields & IPPF_RTHDR) {
2365 2398 *sump = cksum_massage_options_v6(ip6h,
2366 2399 ip_hdr_length, ixa->ixa_ipst->ips_netstack);
2367 2400
2368 2401 /*
2369 2402 * Verify that the first hop isn't a mapped address.
2370 2403 * Routers along the path need to do this verification
2371 2404 * for subsequent hops.
2372 2405 */
2373 2406 if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) {
2374 2407 *errorp = EADDRNOTAVAIL;
2375 2408 freemsg(mp);
2376 2409 return (NULL);
2377 2410 }
2378 2411 } else {
2379 2412 *sump = 0;
2380 2413 }
2381 2414 }
2382 2415 return (mp);
2383 2416 }
2384 2417
2385 2418 /*
2386 2419 * Massage a source route if any putting the first hop
2387 2420 * in ipha_dst. Compute a starting value for the checksum which
2388 2421 * takes into account that the original ipha_dst should be
2389 2422 * included in the checksum but that IP will include the
2390 2423 * first hop from the source route in the tcp checksum.
2391 2424 */
2392 2425 static uint32_t
2393 2426 cksum_massage_options_v4(ipha_t *ipha, netstack_t *ns)
2394 2427 {
2395 2428 in_addr_t dst;
2396 2429 uint32_t cksum;
2397 2430
2398 2431 /* Get last hop then diff against first hop */
2399 2432 cksum = ip_massage_options(ipha, ns);
2400 2433 cksum = (cksum & 0xFFFF) + (cksum >> 16);
2401 2434 dst = ipha->ipha_dst;
2402 2435 cksum -= ((dst >> 16) + (dst & 0xffff));
2403 2436 if ((int)cksum < 0)
2404 2437 cksum--;
2405 2438 cksum = (cksum & 0xFFFF) + (cksum >> 16);
2406 2439 cksum = (cksum & 0xFFFF) + (cksum >> 16);
2407 2440 ASSERT(cksum < 0x10000);
2408 2441 return (ntohs(cksum));
2409 2442 }
2410 2443
2411 2444 static uint32_t
2412 2445 cksum_massage_options_v6(ip6_t *ip6h, uint_t ip_hdr_len, netstack_t *ns)
2413 2446 {
2414 2447 uint8_t *end;
2415 2448 ip6_rthdr_t *rth;
2416 2449 uint32_t cksum;
2417 2450
2418 2451 end = (uint8_t *)ip6h + ip_hdr_len;
2419 2452 rth = ip_find_rthdr_v6(ip6h, end);
2420 2453 if (rth == NULL)
2421 2454 return (0);
2422 2455
2423 2456 cksum = ip_massage_options_v6(ip6h, rth, ns);
2424 2457 cksum = (cksum & 0xFFFF) + (cksum >> 16);
2425 2458 ASSERT(cksum < 0x10000);
2426 2459 return (ntohs(cksum));
2427 2460 }
2428 2461
2429 2462 /*
2430 2463 * ULPs that change the destination address need to call this for each
2431 2464 * change to discard any state about a previous destination that might
2432 2465 * have been multicast or multirt.
2433 2466 */
2434 2467 void
2435 2468 ip_attr_newdst(ip_xmit_attr_t *ixa)
2436 2469 {
2437 2470 ixa->ixa_flags &= ~(IXAF_LOOPBACK_COPY | IXAF_NO_HW_CKSUM |
2438 2471 IXAF_NO_TTL_CHANGE | IXAF_IPV6_ADD_FRAGHDR |
2439 2472 IXAF_NO_LOOP_ZONEID_SET);
2440 2473 }
2441 2474
2442 2475 /*
2443 2476 * Determine the nexthop which will be used.
2444 2477 * Normally this is just the destination, but if a IPv4 source route, or
2445 2478 * IPv6 routing header, is in the ip_pkt_t then we extract the nexthop from
2446 2479 * there.
2447 2480 */
2448 2481 void
2449 2482 ip_attr_nexthop(const ip_pkt_t *ipp, const ip_xmit_attr_t *ixa,
2450 2483 const in6_addr_t *dst, in6_addr_t *nexthop)
2451 2484 {
2452 2485 if (!(ipp->ipp_fields & (IPPF_IPV4_OPTIONS|IPPF_RTHDR))) {
2453 2486 *nexthop = *dst;
2454 2487 return;
2455 2488 }
2456 2489 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2457 2490 ipaddr_t v4dst;
2458 2491 ipaddr_t v4nexthop;
2459 2492
2460 2493 IN6_V4MAPPED_TO_IPADDR(dst, v4dst);
2461 2494 v4nexthop = ip_pkt_source_route_v4(ipp);
2462 2495 if (v4nexthop == INADDR_ANY)
2463 2496 v4nexthop = v4dst;
2464 2497
2465 2498 IN6_IPADDR_TO_V4MAPPED(v4nexthop, nexthop);
2466 2499 } else {
2467 2500 const in6_addr_t *v6nexthop;
2468 2501
2469 2502 v6nexthop = ip_pkt_source_route_v6(ipp);
2470 2503 if (v6nexthop == NULL)
2471 2504 v6nexthop = dst;
2472 2505
2473 2506 *nexthop = *v6nexthop;
2474 2507 }
2475 2508 }
2476 2509
2477 2510 /*
2478 2511 * Update the ip_xmit_attr_t based the addresses, conn_xmit_ipp and conn_ixa.
2479 2512 * If IPDF_IPSEC is set we cache the IPsec policy to handle the unconnected
2480 2513 * case (connected latching is done in conn_connect).
2481 2514 * Note that IPsec policy lookup requires conn_proto and conn_laddr to be
2482 2515 * set, but doesn't otherwise use the conn_t.
2483 2516 *
2484 2517 * Caller must set/clear IXAF_IS_IPV4 as appropriately.
2485 2518 * Caller must use ip_attr_nexthop() to determine the nexthop argument.
2486 2519 *
2487 2520 * The caller must NOT hold conn_lock (to avoid problems with ill_refrele
2488 2521 * causing the squeue to run doing ipcl_walk grabbing conn_lock.)
2489 2522 *
2490 2523 * Updates laddrp and uinfo if they are non-NULL.
2491 2524 *
2492 2525 * TSOL notes: The callers if ip_attr_connect must check if the destination
2493 2526 * is different than before and in that case redo conn_update_label.
2494 2527 * The callers of conn_connect do not need that since conn_connect
2495 2528 * performs the conn_update_label.
2496 2529 */
2497 2530 int
2498 2531 ip_attr_connect(const conn_t *connp, ip_xmit_attr_t *ixa,
2499 2532 const in6_addr_t *v6src, const in6_addr_t *v6dst,
2500 2533 const in6_addr_t *v6nexthop, in_port_t dstport, in6_addr_t *laddrp,
2501 2534 iulp_t *uinfo, uint32_t flags)
2502 2535 {
2503 2536 in6_addr_t laddr = *v6src;
2504 2537 int error;
2505 2538
2506 2539 ASSERT(MUTEX_NOT_HELD(&connp->conn_lock));
2507 2540
2508 2541 if (connp->conn_zone_is_global)
2509 2542 flags |= IPDF_ZONE_IS_GLOBAL;
2510 2543 else
2511 2544 flags &= ~IPDF_ZONE_IS_GLOBAL;
2512 2545
2513 2546 /*
2514 2547 * Lookup the route to determine a source address and the uinfo.
2515 2548 * If the ULP has a source route option then the caller will
2516 2549 * have set v6nexthop to be the first hop.
2517 2550 */
2518 2551 if (ixa->ixa_flags & IXAF_IS_IPV4) {
2519 2552 ipaddr_t v4dst;
2520 2553 ipaddr_t v4src, v4nexthop;
2521 2554
2522 2555 IN6_V4MAPPED_TO_IPADDR(v6dst, v4dst);
2523 2556 IN6_V4MAPPED_TO_IPADDR(v6nexthop, v4nexthop);
2524 2557 IN6_V4MAPPED_TO_IPADDR(v6src, v4src);
2525 2558
2526 2559 if (connp->conn_unspec_src || v4src != INADDR_ANY)
2527 2560 flags &= ~IPDF_SELECT_SRC;
2528 2561 else
2529 2562 flags |= IPDF_SELECT_SRC;
2530 2563
2531 2564 error = ip_set_destination_v4(&v4src, v4dst, v4nexthop, ixa,
2532 2565 uinfo, flags, connp->conn_mac_mode);
2533 2566 IN6_IPADDR_TO_V4MAPPED(v4src, &laddr);
2534 2567 } else {
2535 2568 if (connp->conn_unspec_src || !IN6_IS_ADDR_UNSPECIFIED(v6src))
2536 2569 flags &= ~IPDF_SELECT_SRC;
2537 2570 else
2538 2571 flags |= IPDF_SELECT_SRC;
2539 2572
2540 2573 error = ip_set_destination_v6(&laddr, v6dst, v6nexthop, ixa,
2541 2574 uinfo, flags, connp->conn_mac_mode);
2542 2575 }
2543 2576 /* Pass out some address even if we hit a RTF_REJECT etc */
2544 2577 if (laddrp != NULL)
2545 2578 *laddrp = laddr;
2546 2579
2547 2580 if (error != 0)
2548 2581 return (error);
2549 2582
2550 2583 if (flags & IPDF_IPSEC) {
2551 2584 /*
2552 2585 * Set any IPsec policy in ixa. Routine also looks at ULP
2553 2586 * ports.
2554 2587 */
2555 2588 ipsec_cache_outbound_policy(connp, v6src, v6dst, dstport, ixa);
2556 2589 }
2557 2590 return (0);
2558 2591 }
2559 2592
2560 2593 /*
2561 2594 * Connect the conn based on the addresses, conn_xmit_ipp and conn_ixa.
2562 2595 * Assumes that conn_faddr and conn_fport are already set. As such it is not
2563 2596 * usable for SCTP, since SCTP has multiple faddrs.
2564 2597 *
2565 2598 * Caller must hold conn_lock to provide atomic constency between the
2566 2599 * conn_t's addresses and the ixa.
2567 2600 * NOTE: this function drops and reaquires conn_lock since it can't be
2568 2601 * held across ip_attr_connect/ip_set_destination.
2569 2602 *
2570 2603 * The caller needs to handle inserting in the receive-side fanout when
2571 2604 * appropriate after conn_connect returns.
2572 2605 */
2573 2606 int
2574 2607 conn_connect(conn_t *connp, iulp_t *uinfo, uint32_t flags)
2575 2608 {
2576 2609 ip_xmit_attr_t *ixa = connp->conn_ixa;
2577 2610 in6_addr_t nexthop;
2578 2611 in6_addr_t saddr, faddr;
2579 2612 in_port_t fport;
2580 2613 int error;
2581 2614
2582 2615 ASSERT(MUTEX_HELD(&connp->conn_lock));
2583 2616
2584 2617 if (connp->conn_ipversion == IPV4_VERSION)
2585 2618 ixa->ixa_flags |= IXAF_IS_IPV4;
2586 2619 else
2587 2620 ixa->ixa_flags &= ~IXAF_IS_IPV4;
2588 2621
2589 2622 /* We do IPsec latching below - hence no caching in ip_attr_connect */
2590 2623 flags &= ~IPDF_IPSEC;
2591 2624
2592 2625 /* In case we had previously done an ip_attr_connect */
2593 2626 ip_attr_newdst(ixa);
2594 2627
2595 2628 /*
2596 2629 * Determine the nexthop and copy the addresses before dropping
2597 2630 * conn_lock.
2598 2631 */
2599 2632 ip_attr_nexthop(&connp->conn_xmit_ipp, connp->conn_ixa,
2600 2633 &connp->conn_faddr_v6, &nexthop);
2601 2634 saddr = connp->conn_saddr_v6;
2602 2635 faddr = connp->conn_faddr_v6;
2603 2636 fport = connp->conn_fport;
2604 2637
2605 2638 mutex_exit(&connp->conn_lock);
2606 2639 error = ip_attr_connect(connp, ixa, &saddr, &faddr, &nexthop, fport,
2607 2640 &saddr, uinfo, flags | IPDF_VERIFY_DST);
2608 2641 mutex_enter(&connp->conn_lock);
2609 2642
2610 2643 /* Could have changed even if an error */
2611 2644 connp->conn_saddr_v6 = saddr;
2612 2645 if (error != 0)
2613 2646 return (error);
2614 2647
2615 2648 /*
2616 2649 * Check whether Trusted Solaris policy allows communication with this
2617 2650 * host, and pretend that the destination is unreachable if not.
2618 2651 * Compute any needed label and place it in ipp_label_v4/v6.
2619 2652 *
2620 2653 * Later conn_build_hdr_template() takes ipp_label_v4/v6 to form
2621 2654 * the packet.
2622 2655 *
2623 2656 * TSOL Note: Any concurrent threads would pick a different ixa
2624 2657 * (and ipp if they are to change the ipp) so we
2625 2658 * don't have to worry about concurrent threads.
2626 2659 */
2627 2660 if (is_system_labeled()) {
2628 2661 if (connp->conn_mlp_type != mlptSingle)
2629 2662 return (ECONNREFUSED);
2630 2663
2631 2664 /*
2632 2665 * conn_update_label will set ipp_label* which will later
2633 2666 * be used by conn_build_hdr_template.
2634 2667 */
2635 2668 error = conn_update_label(connp, ixa,
2636 2669 &connp->conn_faddr_v6, &connp->conn_xmit_ipp);
2637 2670 if (error != 0)
2638 2671 return (error);
2639 2672 }
2640 2673
2641 2674 /*
2642 2675 * Ensure that we match on the selected local address.
2643 2676 * This overrides conn_laddr in the case we had earlier bound to a
2644 2677 * multicast or broadcast address.
2645 2678 */
2646 2679 connp->conn_laddr_v6 = connp->conn_saddr_v6;
2647 2680
2648 2681 /*
2649 2682 * Allow setting new policies.
2650 2683 * The addresses/ports are already set, thus the IPsec policy calls
2651 2684 * can handle their passed-in conn's.
2652 2685 */
2653 2686 connp->conn_policy_cached = B_FALSE;
2654 2687
2655 2688 /*
2656 2689 * Cache IPsec policy in this conn. If we have per-socket policy,
2657 2690 * we'll cache that. If we don't, we'll inherit global policy.
2658 2691 *
2659 2692 * This is done before the caller inserts in the receive-side fanout.
2660 2693 * Note that conn_policy_cached is set by ipsec_conn_cache_policy() even
2661 2694 * for connections where we don't have a policy. This is to prevent
2662 2695 * global policy lookups in the inbound path.
2663 2696 *
2664 2697 * If we insert before we set conn_policy_cached,
2665 2698 * CONN_INBOUND_POLICY_PRESENT() check can still evaluate true
2666 2699 * because global policy cound be non-empty. We normally call
2667 2700 * ipsec_check_policy() for conn_policy_cached connections only if
2668 2701 * conn_in_enforce_policy is set. But in this case,
2669 2702 * conn_policy_cached can get set anytime since we made the
2670 2703 * CONN_INBOUND_POLICY_PRESENT() check and ipsec_check_policy() is
2671 2704 * called, which will make the above assumption false. Thus, we
2672 2705 * need to insert after we set conn_policy_cached.
2673 2706 */
2674 2707 error = ipsec_conn_cache_policy(connp,
2675 2708 connp->conn_ipversion == IPV4_VERSION);
2676 2709 if (error != 0)
2677 2710 return (error);
2678 2711
2679 2712 /*
2680 2713 * We defer to do LSO check until here since now we have better idea
2681 2714 * whether IPsec is present. If the underlying ill is LSO capable,
2682 2715 * copy its capability in so the ULP can decide whether to enable LSO
2683 2716 * on this connection. So far, only TCP/IPv4 is implemented, so won't
2684 2717 * claim LSO for IPv6.
2685 2718 *
2686 2719 * Currently, won't enable LSO for IRE_LOOPBACK or IRE_LOCAL, because
2687 2720 * the receiver can not handle it. Also not to enable LSO for MULTIRT.
2688 2721 */
2689 2722 ixa->ixa_flags &= ~IXAF_LSO_CAPAB;
2690 2723
2691 2724 ASSERT(ixa->ixa_ire != NULL);
2692 2725 if (ixa->ixa_ipst->ips_ip_lso_outbound && (flags & IPDF_LSO) &&
2693 2726 !(ixa->ixa_flags & IXAF_IPSEC_SECURE) &&
2694 2727 !(ixa->ixa_ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK)) &&
2695 2728 !(ixa->ixa_ire->ire_flags & RTF_MULTIRT) &&
2696 2729 (ixa->ixa_nce != NULL) &&
2697 2730 ((ixa->ixa_flags & IXAF_IS_IPV4) ?
2698 2731 ILL_LSO_TCP_IPV4_USABLE(ixa->ixa_nce->nce_ill) :
2699 2732 ILL_LSO_TCP_IPV6_USABLE(ixa->ixa_nce->nce_ill))) {
2700 2733 ixa->ixa_lso_capab = *ixa->ixa_nce->nce_ill->ill_lso_capab;
2701 2734 ixa->ixa_flags |= IXAF_LSO_CAPAB;
2702 2735 }
2703 2736
2704 2737 /* Check whether ZEROCOPY capability is usable for this connection. */
2705 2738 ixa->ixa_flags &= ~IXAF_ZCOPY_CAPAB;
2706 2739
2707 2740 if ((flags & IPDF_ZCOPY) &&
2708 2741 !(ixa->ixa_flags & IXAF_IPSEC_SECURE) &&
2709 2742 !(ixa->ixa_ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK)) &&
2710 2743 !(ixa->ixa_ire->ire_flags & RTF_MULTIRT) &&
2711 2744 (ixa->ixa_nce != NULL) &&
2712 2745 ILL_ZCOPY_USABLE(ixa->ixa_nce->nce_ill)) {
2713 2746 ixa->ixa_flags |= IXAF_ZCOPY_CAPAB;
2714 2747 }
2715 2748 return (0);
2716 2749 }
2717 2750
2718 2751 /*
2719 2752 * Predicates to check if the addresses match conn_last*
2720 2753 */
2721 2754
2722 2755 /*
2723 2756 * Compare the conn against an address.
2724 2757 * If using mapped addresses on AF_INET6 sockets, use the _v6 function
2725 2758 */
2726 2759 boolean_t
2727 2760 conn_same_as_last_v4(conn_t *connp, sin_t *sin)
2728 2761 {
2729 2762 ASSERT(connp->conn_family == AF_INET);
2730 2763 return (sin->sin_addr.s_addr == connp->conn_v4lastdst &&
2731 2764 sin->sin_port == connp->conn_lastdstport);
2732 2765 }
2733 2766
2734 2767 /*
2735 2768 * Compare, including for mapped addresses
2736 2769 */
2737 2770 boolean_t
2738 2771 conn_same_as_last_v6(conn_t *connp, sin6_t *sin6)
2739 2772 {
2740 2773 return (IN6_ARE_ADDR_EQUAL(&connp->conn_v6lastdst, &sin6->sin6_addr) &&
2741 2774 sin6->sin6_port == connp->conn_lastdstport &&
2742 2775 sin6->sin6_flowinfo == connp->conn_lastflowinfo &&
2743 2776 sin6->sin6_scope_id == connp->conn_lastscopeid);
2744 2777 }
2745 2778
2746 2779 /*
2747 2780 * Compute a label and place it in the ip_packet_t.
2748 2781 * Handles IPv4 and IPv6.
2749 2782 * The caller should have a correct ixa_tsl and ixa_zoneid and have
2750 2783 * already called conn_connect or ip_attr_connect to ensure that tsol_check_dest
2751 2784 * has been called.
2752 2785 */
2753 2786 int
2754 2787 conn_update_label(const conn_t *connp, const ip_xmit_attr_t *ixa,
2755 2788 const in6_addr_t *v6dst, ip_pkt_t *ipp)
2756 2789 {
2757 2790 int err;
2758 2791 ipaddr_t v4dst;
2759 2792
2760 2793 if (IN6_IS_ADDR_V4MAPPED(v6dst)) {
2761 2794 uchar_t opt_storage[IP_MAX_OPT_LENGTH];
2762 2795
2763 2796 IN6_V4MAPPED_TO_IPADDR(v6dst, v4dst);
2764 2797
2765 2798 err = tsol_compute_label_v4(ixa->ixa_tsl, ixa->ixa_zoneid,
2766 2799 v4dst, opt_storage, ixa->ixa_ipst);
2767 2800 if (err == 0) {
2768 2801 /* Length contained in opt_storage[IPOPT_OLEN] */
2769 2802 err = optcom_pkt_set(opt_storage,
2770 2803 opt_storage[IPOPT_OLEN],
2771 2804 (uchar_t **)&ipp->ipp_label_v4,
2772 2805 &ipp->ipp_label_len_v4);
2773 2806 }
2774 2807 if (err != 0) {
2775 2808 DTRACE_PROBE4(tx__ip__log__info__updatelabel,
2776 2809 char *, "conn(1) failed to update options(2) "
2777 2810 "on ixa(3)",
2778 2811 conn_t *, connp, char *, opt_storage,
2779 2812 ip_xmit_attr_t *, ixa);
2780 2813 }
2781 2814 if (ipp->ipp_label_len_v4 != 0)
2782 2815 ipp->ipp_fields |= IPPF_LABEL_V4;
2783 2816 else
2784 2817 ipp->ipp_fields &= ~IPPF_LABEL_V4;
2785 2818 } else {
2786 2819 uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
2787 2820 uint_t optlen;
2788 2821
2789 2822 err = tsol_compute_label_v6(ixa->ixa_tsl, ixa->ixa_zoneid,
2790 2823 v6dst, opt_storage, ixa->ixa_ipst);
2791 2824 if (err == 0) {
2792 2825 /*
2793 2826 * Note that ipp_label_v6 is just the option - not
2794 2827 * the hopopts extension header.
2795 2828 *
2796 2829 * Length contained in opt_storage[IPOPT_OLEN], but
2797 2830 * that doesn't include the two byte options header.
2798 2831 */
2799 2832 optlen = opt_storage[IPOPT_OLEN];
2800 2833 if (optlen != 0)
2801 2834 optlen += 2;
2802 2835
2803 2836 err = optcom_pkt_set(opt_storage, optlen,
2804 2837 (uchar_t **)&ipp->ipp_label_v6,
2805 2838 &ipp->ipp_label_len_v6);
2806 2839 }
2807 2840 if (err != 0) {
2808 2841 DTRACE_PROBE4(tx__ip__log__info__updatelabel,
2809 2842 char *, "conn(1) failed to update options(2) "
2810 2843 "on ixa(3)",
2811 2844 conn_t *, connp, char *, opt_storage,
2812 2845 ip_xmit_attr_t *, ixa);
2813 2846 }
2814 2847 if (ipp->ipp_label_len_v6 != 0)
2815 2848 ipp->ipp_fields |= IPPF_LABEL_V6;
2816 2849 else
2817 2850 ipp->ipp_fields &= ~IPPF_LABEL_V6;
2818 2851 }
2819 2852 return (err);
2820 2853 }
2821 2854
2822 2855 /*
2823 2856 * Inherit all options settings from the parent/listener to the eager.
2824 2857 * Returns zero on success; ENOMEM if memory allocation failed.
2825 2858 *
2826 2859 * We assume that the eager has not had any work done i.e., the conn_ixa
2827 2860 * and conn_xmit_ipp are all zero.
2828 2861 * Furthermore we assume that no other thread can access the eager (because
2829 2862 * it isn't inserted in any fanout list).
2830 2863 */
2831 2864 int
2832 2865 conn_inherit_parent(conn_t *lconnp, conn_t *econnp)
2833 2866 {
2834 2867 cred_t *credp;
2835 2868 int err;
2836 2869 void *notify_cookie;
2837 2870 uint32_t xmit_hint;
2838 2871
2839 2872 econnp->conn_family = lconnp->conn_family;
2840 2873 econnp->conn_ipv6_v6only = lconnp->conn_ipv6_v6only;
2841 2874 econnp->conn_wq = lconnp->conn_wq;
2842 2875 econnp->conn_rq = lconnp->conn_rq;
2843 2876
2844 2877 /*
2845 2878 * Make a safe copy of the transmit attributes.
2846 2879 * conn_connect will later be used by the caller to setup the ire etc.
2847 2880 */
2848 2881 ASSERT(econnp->conn_ixa->ixa_refcnt == 1);
2849 2882 ASSERT(econnp->conn_ixa->ixa_ire == NULL);
2850 2883 ASSERT(econnp->conn_ixa->ixa_dce == NULL);
2851 2884 ASSERT(econnp->conn_ixa->ixa_nce == NULL);
2852 2885
2853 2886 /* Preserve ixa_notify_cookie and xmit_hint */
2854 2887 notify_cookie = econnp->conn_ixa->ixa_notify_cookie;
2855 2888 xmit_hint = econnp->conn_ixa->ixa_xmit_hint;
2856 2889 ixa_safe_copy(lconnp->conn_ixa, econnp->conn_ixa);
2857 2890 econnp->conn_ixa->ixa_notify_cookie = notify_cookie;
2858 2891 econnp->conn_ixa->ixa_xmit_hint = xmit_hint;
2859 2892
2860 2893 econnp->conn_bound_if = lconnp->conn_bound_if;
2861 2894 econnp->conn_incoming_ifindex = lconnp->conn_incoming_ifindex;
2862 2895
2863 2896 /* Inherit all RECV options */
2864 2897 econnp->conn_recv_ancillary = lconnp->conn_recv_ancillary;
2865 2898
2866 2899 err = ip_pkt_copy(&lconnp->conn_xmit_ipp, &econnp->conn_xmit_ipp,
2867 2900 KM_NOSLEEP);
2868 2901 if (err != 0)
2869 2902 return (err);
2870 2903
2871 2904 econnp->conn_zoneid = lconnp->conn_zoneid;
2872 2905 econnp->conn_allzones = lconnp->conn_allzones;
2873 2906
2874 2907 /* This is odd. Pick a flowlabel for each connection instead? */
2875 2908 econnp->conn_flowinfo = lconnp->conn_flowinfo;
2876 2909
2877 2910 econnp->conn_default_ttl = lconnp->conn_default_ttl;
2878 2911
2879 2912 /*
2880 2913 * TSOL: tsol_input_proc() needs the eager's cred before the
2881 2914 * eager is accepted
2882 2915 */
2883 2916 ASSERT(lconnp->conn_cred != NULL);
2884 2917 econnp->conn_cred = credp = lconnp->conn_cred;
2885 2918 crhold(credp);
2886 2919 econnp->conn_cpid = lconnp->conn_cpid;
2887 2920 econnp->conn_open_time = ddi_get_lbolt64();
2888 2921
2889 2922 /*
2890 2923 * Cache things in the ixa without any refhold.
2891 2924 * Listener might not have set up ixa_cred
2892 2925 */
2893 2926 ASSERT(!(econnp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
2894 2927 econnp->conn_ixa->ixa_cred = econnp->conn_cred;
2895 2928 econnp->conn_ixa->ixa_cpid = econnp->conn_cpid;
2896 2929 if (is_system_labeled())
2897 2930 econnp->conn_ixa->ixa_tsl = crgetlabel(econnp->conn_cred);
2898 2931
2899 2932 /*
2900 2933 * If the caller has the process-wide flag set, then default to MAC
2901 2934 * exempt mode. This allows read-down to unlabeled hosts.
2902 2935 */
2903 2936 if (getpflags(NET_MAC_AWARE, credp) != 0)
2904 2937 econnp->conn_mac_mode = CONN_MAC_AWARE;
2905 2938
2906 2939 econnp->conn_zone_is_global = lconnp->conn_zone_is_global;
2907 2940
2908 2941 /*
2909 2942 * We eliminate the need for sockfs to send down a T_SVR4_OPTMGMT_REQ
2910 2943 * via soaccept()->soinheritoptions() which essentially applies
2911 2944 * all the listener options to the new connection. The options that we
2912 2945 * need to take care of are:
2913 2946 * SO_DEBUG, SO_REUSEADDR, SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST,
2914 2947 * SO_USELOOPBACK, SO_OOBINLINE, SO_DGRAM_ERRIND, SO_LINGER,
2915 2948 * SO_SNDBUF, SO_RCVBUF.
2916 2949 *
2917 2950 * SO_RCVBUF: conn_rcvbuf is set.
2918 2951 * SO_SNDBUF: conn_sndbuf is set.
2919 2952 */
2920 2953
2921 2954 /* Could we define a struct and use a struct copy for this? */
2922 2955 econnp->conn_sndbuf = lconnp->conn_sndbuf;
2923 2956 econnp->conn_rcvbuf = lconnp->conn_rcvbuf;
2924 2957 econnp->conn_sndlowat = lconnp->conn_sndlowat;
2925 2958 econnp->conn_rcvlowat = lconnp->conn_rcvlowat;
2926 2959 econnp->conn_dgram_errind = lconnp->conn_dgram_errind;
2927 2960 econnp->conn_oobinline = lconnp->conn_oobinline;
2928 2961 econnp->conn_debug = lconnp->conn_debug;
2929 2962 econnp->conn_keepalive = lconnp->conn_keepalive;
2930 2963 econnp->conn_linger = lconnp->conn_linger;
2931 2964 econnp->conn_lingertime = lconnp->conn_lingertime;
2932 2965
2933 2966 /* Set the IP options */
2934 2967 econnp->conn_broadcast = lconnp->conn_broadcast;
2935 2968 econnp->conn_useloopback = lconnp->conn_useloopback;
2936 2969 econnp->conn_reuseaddr = lconnp->conn_reuseaddr;
2937 2970 return (0);
2938 2971 }
↓ open down ↓ |
1561 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX