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