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 /* 23a5407c02SAnil udupa * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved 24*af10b639SDan McDonald * 25*af10b639SDan McDonald * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26bd670b35SErik Nordmark */ 27bd670b35SErik Nordmark /* Copyright (c) 1990 Mentat Inc. */ 28bd670b35SErik Nordmark 29bd670b35SErik Nordmark #include <sys/types.h> 30bd670b35SErik Nordmark #include <sys/stream.h> 31bd670b35SErik Nordmark #include <sys/dlpi.h> 32bd670b35SErik Nordmark #include <sys/stropts.h> 33bd670b35SErik Nordmark #include <sys/sysmacros.h> 34bd670b35SErik Nordmark #include <sys/strsubr.h> 35bd670b35SErik Nordmark #include <sys/strlog.h> 36bd670b35SErik Nordmark #include <sys/strsun.h> 37bd670b35SErik Nordmark #include <sys/zone.h> 38bd670b35SErik Nordmark #define _SUN_TPI_VERSION 2 39bd670b35SErik Nordmark #include <sys/tihdr.h> 40bd670b35SErik Nordmark #include <sys/xti_inet.h> 41bd670b35SErik Nordmark #include <sys/ddi.h> 42bd670b35SErik Nordmark #include <sys/sunddi.h> 43bd670b35SErik Nordmark #include <sys/cmn_err.h> 44bd670b35SErik Nordmark #include <sys/debug.h> 45bd670b35SErik Nordmark #include <sys/kobj.h> 46bd670b35SErik Nordmark #include <sys/modctl.h> 47bd670b35SErik Nordmark #include <sys/atomic.h> 48bd670b35SErik Nordmark #include <sys/policy.h> 49bd670b35SErik Nordmark #include <sys/priv.h> 50bd670b35SErik Nordmark 51bd670b35SErik Nordmark #include <sys/systm.h> 52bd670b35SErik Nordmark #include <sys/param.h> 53bd670b35SErik Nordmark #include <sys/kmem.h> 54bd670b35SErik Nordmark #include <sys/sdt.h> 55bd670b35SErik Nordmark #include <sys/socket.h> 56bd670b35SErik Nordmark #include <sys/vtrace.h> 57bd670b35SErik Nordmark #include <sys/isa_defs.h> 58bd670b35SErik Nordmark #include <sys/mac.h> 59bd670b35SErik Nordmark #include <net/if.h> 60bd670b35SErik Nordmark #include <net/if_arp.h> 61bd670b35SErik Nordmark #include <net/route.h> 62bd670b35SErik Nordmark #include <sys/sockio.h> 63bd670b35SErik Nordmark #include <netinet/in.h> 64bd670b35SErik Nordmark #include <net/if_dl.h> 65bd670b35SErik Nordmark 66bd670b35SErik Nordmark #include <inet/common.h> 67bd670b35SErik Nordmark #include <inet/mi.h> 68bd670b35SErik Nordmark #include <inet/mib2.h> 69bd670b35SErik Nordmark #include <inet/nd.h> 70bd670b35SErik Nordmark #include <inet/arp.h> 71bd670b35SErik Nordmark #include <inet/snmpcom.h> 72bd670b35SErik Nordmark #include <inet/kstatcom.h> 73bd670b35SErik Nordmark 74bd670b35SErik Nordmark #include <netinet/igmp_var.h> 75bd670b35SErik Nordmark #include <netinet/ip6.h> 76bd670b35SErik Nordmark #include <netinet/icmp6.h> 77bd670b35SErik Nordmark #include <netinet/sctp.h> 78bd670b35SErik Nordmark 79bd670b35SErik Nordmark #include <inet/ip.h> 80bd670b35SErik Nordmark #include <inet/ip_impl.h> 81bd670b35SErik Nordmark #include <inet/ip6.h> 82bd670b35SErik Nordmark #include <inet/ip6_asp.h> 83bd670b35SErik Nordmark #include <inet/optcom.h> 84bd670b35SErik Nordmark #include <inet/tcp.h> 85bd670b35SErik Nordmark #include <inet/tcp_impl.h> 86bd670b35SErik Nordmark #include <inet/ip_multi.h> 87bd670b35SErik Nordmark #include <inet/ip_if.h> 88bd670b35SErik Nordmark #include <inet/ip_ire.h> 89bd670b35SErik Nordmark #include <inet/ip_ftable.h> 90bd670b35SErik Nordmark #include <inet/ip_rts.h> 91bd670b35SErik Nordmark #include <inet/ip_ndp.h> 92bd670b35SErik Nordmark #include <inet/ip_listutils.h> 93bd670b35SErik Nordmark #include <netinet/igmp.h> 94bd670b35SErik Nordmark #include <netinet/ip_mroute.h> 95bd670b35SErik Nordmark #include <inet/ipp_common.h> 96bd670b35SErik Nordmark 97bd670b35SErik Nordmark #include <net/pfkeyv2.h> 98bd670b35SErik Nordmark #include <inet/sadb.h> 99bd670b35SErik Nordmark #include <inet/ipsec_impl.h> 100bd670b35SErik Nordmark #include <inet/ipdrop.h> 101bd670b35SErik Nordmark #include <inet/ip_netinfo.h> 102bd670b35SErik Nordmark #include <inet/ilb_ip.h> 103bd670b35SErik Nordmark #include <sys/squeue_impl.h> 104bd670b35SErik Nordmark #include <sys/squeue.h> 105bd670b35SErik Nordmark 106bd670b35SErik Nordmark #include <sys/ethernet.h> 107bd670b35SErik Nordmark #include <net/if_types.h> 108bd670b35SErik Nordmark #include <sys/cpuvar.h> 109bd670b35SErik Nordmark 110bd670b35SErik Nordmark #include <ipp/ipp.h> 111bd670b35SErik Nordmark #include <ipp/ipp_impl.h> 112bd670b35SErik Nordmark #include <ipp/ipgpc/ipgpc.h> 113bd670b35SErik Nordmark 114bd670b35SErik Nordmark #include <sys/pattr.h> 115bd670b35SErik Nordmark #include <inet/ipclassifier.h> 116bd670b35SErik Nordmark #include <inet/sctp_ip.h> 117bd670b35SErik Nordmark #include <inet/sctp/sctp_impl.h> 118bd670b35SErik Nordmark #include <inet/udp_impl.h> 119bd670b35SErik Nordmark #include <sys/sunddi.h> 120bd670b35SErik Nordmark 121bd670b35SErik Nordmark #include <sys/tsol/label.h> 122bd670b35SErik Nordmark #include <sys/tsol/tnet.h> 123bd670b35SErik Nordmark 124b36a561eSErik Nordmark #include <sys/clock_impl.h> /* For LBOLT_FASTPATH{,64} */ 125bd670b35SErik Nordmark 126bd670b35SErik Nordmark #ifdef DEBUG 127bd670b35SErik Nordmark extern boolean_t skip_sctp_cksum; 128bd670b35SErik Nordmark #endif 129bd670b35SErik Nordmark 130bd670b35SErik Nordmark static void ip_input_local_v6(ire_t *, mblk_t *, ip6_t *, ip_recv_attr_t *); 131bd670b35SErik Nordmark 132bd670b35SErik Nordmark static void ip_input_multicast_v6(ire_t *, mblk_t *, ip6_t *, 133bd670b35SErik Nordmark ip_recv_attr_t *); 134bd670b35SErik Nordmark 135bd670b35SErik Nordmark #pragma inline(ip_input_common_v6, ip_input_local_v6, ip_forward_xmit_v6) 136bd670b35SErik Nordmark 137bd670b35SErik Nordmark /* 138bd670b35SErik Nordmark * Direct read side procedure capable of dealing with chains. GLDv3 based 139bd670b35SErik Nordmark * drivers call this function directly with mblk chains while STREAMS 140bd670b35SErik Nordmark * read side procedure ip_rput() calls this for single packet with ip_ring 141bd670b35SErik Nordmark * set to NULL to process one packet at a time. 142bd670b35SErik Nordmark * 143bd670b35SErik Nordmark * The ill will always be valid if this function is called directly from 144bd670b35SErik Nordmark * the driver. 145bd670b35SErik Nordmark * 146bd670b35SErik Nordmark * If ip_input_v6() is called from GLDv3: 147bd670b35SErik Nordmark * 148bd670b35SErik Nordmark * - This must be a non-VLAN IP stream. 149bd670b35SErik Nordmark * - 'mp' is either an untagged or a special priority-tagged packet. 150bd670b35SErik Nordmark * - Any VLAN tag that was in the MAC header has been stripped. 151bd670b35SErik Nordmark * 152bd670b35SErik Nordmark * If the IP header in packet is not 32-bit aligned, every message in the 153bd670b35SErik Nordmark * chain will be aligned before further operations. This is required on SPARC 154bd670b35SErik Nordmark * platform. 155bd670b35SErik Nordmark */ 156bd670b35SErik Nordmark void 157bd670b35SErik Nordmark ip_input_v6(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 158bd670b35SErik Nordmark struct mac_header_info_s *mhip) 159bd670b35SErik Nordmark { 160bd670b35SErik Nordmark (void) ip_input_common_v6(ill, ip_ring, mp_chain, mhip, NULL, NULL, 161bd670b35SErik Nordmark NULL); 162bd670b35SErik Nordmark } 163bd670b35SErik Nordmark 164bd670b35SErik Nordmark /* 165bd670b35SErik Nordmark * ip_accept_tcp_v6() - This function is called by the squeue when it retrieves 166bd670b35SErik Nordmark * a chain of packets in the poll mode. The packets have gone through the 167bd670b35SErik Nordmark * data link processing but not IP processing. For performance and latency 168bd670b35SErik Nordmark * reasons, the squeue wants to process the chain in line instead of feeding 169bd670b35SErik Nordmark * it back via ip_input path. 170bd670b35SErik Nordmark * 171bd670b35SErik Nordmark * We set up the ip_recv_attr_t with IRAF_TARGET_SQP to that ip_fanout_v6 172bd670b35SErik Nordmark * will pass back any TCP packets matching the target sqp to 173bd670b35SErik Nordmark * ip_input_common_v6 using ira_target_sqp_mp. Other packets are handled by 174bd670b35SErik Nordmark * ip_input_v6 and ip_fanout_v6 as normal. 175bd670b35SErik Nordmark * The TCP packets that match the target squeue are returned to the caller 176bd670b35SErik Nordmark * as a b_next chain after each packet has been prepend with an mblk 177bd670b35SErik Nordmark * from ip_recv_attr_to_mblk. 178bd670b35SErik Nordmark */ 179bd670b35SErik Nordmark mblk_t * 180bd670b35SErik Nordmark ip_accept_tcp_v6(ill_t *ill, ill_rx_ring_t *ip_ring, squeue_t *target_sqp, 181bd670b35SErik Nordmark mblk_t *mp_chain, mblk_t **last, uint_t *cnt) 182bd670b35SErik Nordmark { 183bd670b35SErik Nordmark return (ip_input_common_v6(ill, ip_ring, mp_chain, NULL, target_sqp, 184bd670b35SErik Nordmark last, cnt)); 185bd670b35SErik Nordmark } 186bd670b35SErik Nordmark 187bd670b35SErik Nordmark /* 188bd670b35SErik Nordmark * Used by ip_input_v6 and ip_accept_tcp_v6 189bd670b35SErik Nordmark * The last three arguments are only used by ip_accept_tcp_v6, and mhip is 190bd670b35SErik Nordmark * only used by ip_input_v6. 191bd670b35SErik Nordmark */ 192bd670b35SErik Nordmark mblk_t * 193bd670b35SErik Nordmark ip_input_common_v6(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 194bd670b35SErik Nordmark struct mac_header_info_s *mhip, squeue_t *target_sqp, 195bd670b35SErik Nordmark mblk_t **last, uint_t *cnt) 196bd670b35SErik Nordmark { 197bd670b35SErik Nordmark mblk_t *mp; 198bd670b35SErik Nordmark ip6_t *ip6h; 199bd670b35SErik Nordmark ip_recv_attr_t iras; /* Receive attributes */ 200bd670b35SErik Nordmark rtc_t rtc; 201bd670b35SErik Nordmark iaflags_t chain_flags = 0; /* Fixed for chain */ 202bd670b35SErik Nordmark mblk_t *ahead = NULL; /* Accepted head */ 203bd670b35SErik Nordmark mblk_t *atail = NULL; /* Accepted tail */ 204bd670b35SErik Nordmark uint_t acnt = 0; /* Accepted count */ 205bd670b35SErik Nordmark 206bd670b35SErik Nordmark ASSERT(mp_chain != NULL); 207bd670b35SErik Nordmark ASSERT(ill != NULL); 208bd670b35SErik Nordmark 209bd670b35SErik Nordmark /* These ones do not change as we loop over packets */ 210bd670b35SErik Nordmark iras.ira_ill = iras.ira_rill = ill; 211bd670b35SErik Nordmark iras.ira_ruifindex = ill->ill_phyint->phyint_ifindex; 212bd670b35SErik Nordmark iras.ira_rifindex = iras.ira_ruifindex; 213bd670b35SErik Nordmark iras.ira_sqp = NULL; 214bd670b35SErik Nordmark iras.ira_ring = ip_ring; 215bd670b35SErik Nordmark /* For ECMP and outbound transmit ring selection */ 216bd670b35SErik Nordmark iras.ira_xmit_hint = ILL_RING_TO_XMIT_HINT(ip_ring); 217bd670b35SErik Nordmark 218bd670b35SErik Nordmark iras.ira_target_sqp = target_sqp; 219bd670b35SErik Nordmark iras.ira_target_sqp_mp = NULL; 220bd670b35SErik Nordmark if (target_sqp != NULL) 221bd670b35SErik Nordmark chain_flags |= IRAF_TARGET_SQP; 222bd670b35SErik Nordmark 223bd670b35SErik Nordmark /* 224bd670b35SErik Nordmark * We try to have a mhip pointer when possible, but 225bd670b35SErik Nordmark * it might be NULL in some cases. In those cases we 226bd670b35SErik Nordmark * have to assume unicast. 227bd670b35SErik Nordmark */ 228bd670b35SErik Nordmark iras.ira_mhip = mhip; 229bd670b35SErik Nordmark iras.ira_flags = 0; 230bd670b35SErik Nordmark if (mhip != NULL) { 231bd670b35SErik Nordmark switch (mhip->mhi_dsttype) { 232bd670b35SErik Nordmark case MAC_ADDRTYPE_MULTICAST : 233bd670b35SErik Nordmark chain_flags |= IRAF_L2DST_MULTICAST; 234bd670b35SErik Nordmark break; 235bd670b35SErik Nordmark case MAC_ADDRTYPE_BROADCAST : 236bd670b35SErik Nordmark chain_flags |= IRAF_L2DST_BROADCAST; 237bd670b35SErik Nordmark break; 238bd670b35SErik Nordmark } 239bd670b35SErik Nordmark } 240bd670b35SErik Nordmark 241bd670b35SErik Nordmark /* 242bd670b35SErik Nordmark * Initialize the one-element route cache. 243bd670b35SErik Nordmark * 244bd670b35SErik Nordmark * We do ire caching from one iteration to 245bd670b35SErik Nordmark * another. In the event the packet chain contains 246bd670b35SErik Nordmark * all packets from the same dst, this caching saves 247bd670b35SErik Nordmark * an ire_route_recursive for each of the succeeding 248bd670b35SErik Nordmark * packets in a packet chain. 249bd670b35SErik Nordmark */ 250bd670b35SErik Nordmark rtc.rtc_ire = NULL; 251bd670b35SErik Nordmark rtc.rtc_ip6addr = ipv6_all_zeros; 252bd670b35SErik Nordmark 253bd670b35SErik Nordmark /* Loop over b_next */ 254bd670b35SErik Nordmark for (mp = mp_chain; mp != NULL; mp = mp_chain) { 255bd670b35SErik Nordmark mp_chain = mp->b_next; 256bd670b35SErik Nordmark mp->b_next = NULL; 257bd670b35SErik Nordmark 258bd670b35SErik Nordmark /* 259bd670b35SErik Nordmark * if db_ref > 1 then copymsg and free original. Packet 260bd670b35SErik Nordmark * may be changed and we do not want the other entity 261bd670b35SErik Nordmark * who has a reference to this message to trip over the 262bd670b35SErik Nordmark * changes. This is a blind change because trying to 263bd670b35SErik Nordmark * catch all places that might change the packet is too 264bd670b35SErik Nordmark * difficult. 265bd670b35SErik Nordmark * 266bd670b35SErik Nordmark * This corresponds to the fast path case, where we have 267bd670b35SErik Nordmark * a chain of M_DATA mblks. We check the db_ref count 268bd670b35SErik Nordmark * of only the 1st data block in the mblk chain. There 269bd670b35SErik Nordmark * doesn't seem to be a reason why a device driver would 270bd670b35SErik Nordmark * send up data with varying db_ref counts in the mblk 271bd670b35SErik Nordmark * chain. In any case the Fast path is a private 272bd670b35SErik Nordmark * interface, and our drivers don't do such a thing. 273bd670b35SErik Nordmark * Given the above assumption, there is no need to walk 274bd670b35SErik Nordmark * down the entire mblk chain (which could have a 275bd670b35SErik Nordmark * potential performance problem) 276bd670b35SErik Nordmark * 277bd670b35SErik Nordmark * The "(DB_REF(mp) > 1)" check was moved from ip_rput() 278bd670b35SErik Nordmark * to here because of exclusive ip stacks and vnics. 279bd670b35SErik Nordmark * Packets transmitted from exclusive stack over vnic 280bd670b35SErik Nordmark * can have db_ref > 1 and when it gets looped back to 281bd670b35SErik Nordmark * another vnic in a different zone, you have ip_input() 282bd670b35SErik Nordmark * getting dblks with db_ref > 1. So if someone 283bd670b35SErik Nordmark * complains of TCP performance under this scenario, 284bd670b35SErik Nordmark * take a serious look here on the impact of copymsg(). 285bd670b35SErik Nordmark */ 286bd670b35SErik Nordmark if (DB_REF(mp) > 1) { 287bd670b35SErik Nordmark if ((mp = ip_fix_dbref(mp, &iras)) == NULL) 288bd670b35SErik Nordmark continue; 289bd670b35SErik Nordmark } 290bd670b35SErik Nordmark 291bd670b35SErik Nordmark /* 292bd670b35SErik Nordmark * IP header ptr not aligned? 293bd670b35SErik Nordmark * OR IP header not complete in first mblk 294bd670b35SErik Nordmark */ 295bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 296bd670b35SErik Nordmark if (!OK_32PTR(ip6h) || MBLKL(mp) < IPV6_HDR_LEN) { 297bd670b35SErik Nordmark mp = ip_check_and_align_header(mp, IPV6_HDR_LEN, &iras); 298bd670b35SErik Nordmark if (mp == NULL) 299bd670b35SErik Nordmark continue; 300bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 301bd670b35SErik Nordmark } 302bd670b35SErik Nordmark 303bd670b35SErik Nordmark /* Protect against a mix of Ethertypes and IP versions */ 304bd670b35SErik Nordmark if (IPH_HDR_VERSION(ip6h) != IPV6_VERSION) { 305bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInHdrErrors); 306bd670b35SErik Nordmark ip_drop_input("ipIfStatsInHdrErrors", mp, ill); 307bd670b35SErik Nordmark freemsg(mp); 308bd670b35SErik Nordmark /* mhip might point into 1st packet in the chain. */ 309bd670b35SErik Nordmark iras.ira_mhip = NULL; 310bd670b35SErik Nordmark continue; 311bd670b35SErik Nordmark } 312bd670b35SErik Nordmark 313bd670b35SErik Nordmark /* 314bd670b35SErik Nordmark * Check for Martian addrs; we have to explicitly 315bd670b35SErik Nordmark * test for for zero dst since this is also used as 316bd670b35SErik Nordmark * an indication that the rtc is not used. 317bd670b35SErik Nordmark */ 318bd670b35SErik Nordmark if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_dst)) { 319bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 320bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 321bd670b35SErik Nordmark freemsg(mp); 322bd670b35SErik Nordmark /* mhip might point into 1st packet in the chain. */ 323bd670b35SErik Nordmark iras.ira_mhip = NULL; 324bd670b35SErik Nordmark continue; 325bd670b35SErik Nordmark } 326bd670b35SErik Nordmark /* 327bd670b35SErik Nordmark * Keep L2SRC from a previous packet in chain since mhip 328bd670b35SErik Nordmark * might point into an earlier packet in the chain. 329bd670b35SErik Nordmark */ 330bd670b35SErik Nordmark chain_flags |= (iras.ira_flags & IRAF_L2SRC_SET); 331bd670b35SErik Nordmark 332bd670b35SErik Nordmark iras.ira_flags = IRAF_VERIFY_ULP_CKSUM | chain_flags; 333bd670b35SErik Nordmark iras.ira_free_flags = 0; 334bd670b35SErik Nordmark iras.ira_cred = NULL; 335bd670b35SErik Nordmark iras.ira_cpid = NOPID; 336bd670b35SErik Nordmark iras.ira_tsl = NULL; 337bd670b35SErik Nordmark iras.ira_zoneid = ALL_ZONES; /* Default for forwarding */ 338bd670b35SErik Nordmark 339bd670b35SErik Nordmark /* 340bd670b35SErik Nordmark * We must count all incoming packets, even if they end 341bd670b35SErik Nordmark * up being dropped later on. Defer counting bytes until 342bd670b35SErik Nordmark * we have the whole IP header in first mblk. 343bd670b35SErik Nordmark */ 344bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInReceives); 345bd670b35SErik Nordmark 346bd670b35SErik Nordmark iras.ira_pktlen = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; 347bd670b35SErik Nordmark UPDATE_MIB(ill->ill_ip_mib, ipIfStatsHCInOctets, 348bd670b35SErik Nordmark iras.ira_pktlen); 349bd670b35SErik Nordmark 350bd670b35SErik Nordmark /* 351bd670b35SErik Nordmark * Call one of: 352bd670b35SErik Nordmark * ill_input_full_v6 353bd670b35SErik Nordmark * ill_input_short_v6 354bd670b35SErik Nordmark * The former is used in the case of TX. See ill_set_inputfn(). 355bd670b35SErik Nordmark */ 356bd670b35SErik Nordmark (*ill->ill_inputfn)(mp, ip6h, &ip6h->ip6_dst, &iras, &rtc); 357bd670b35SErik Nordmark 358bd670b35SErik Nordmark /* Any references to clean up? No hold on ira_ill */ 359bd670b35SErik Nordmark if (iras.ira_flags & (IRAF_IPSEC_SECURE|IRAF_SYSTEM_LABELED)) 360bd670b35SErik Nordmark ira_cleanup(&iras, B_FALSE); 361bd670b35SErik Nordmark 362bd670b35SErik Nordmark if (iras.ira_target_sqp_mp != NULL) { 363bd670b35SErik Nordmark /* Better be called from ip_accept_tcp */ 364bd670b35SErik Nordmark ASSERT(target_sqp != NULL); 365bd670b35SErik Nordmark 366bd670b35SErik Nordmark /* Found one packet to accept */ 367bd670b35SErik Nordmark mp = iras.ira_target_sqp_mp; 368bd670b35SErik Nordmark iras.ira_target_sqp_mp = NULL; 369bd670b35SErik Nordmark ASSERT(ip_recv_attr_is_mblk(mp)); 370bd670b35SErik Nordmark 371bd670b35SErik Nordmark if (atail != NULL) 372bd670b35SErik Nordmark atail->b_next = mp; 373bd670b35SErik Nordmark else 374bd670b35SErik Nordmark ahead = mp; 375bd670b35SErik Nordmark atail = mp; 376bd670b35SErik Nordmark acnt++; 377bd670b35SErik Nordmark mp = NULL; 378bd670b35SErik Nordmark } 379bd670b35SErik Nordmark /* mhip might point into 1st packet in the chain. */ 380bd670b35SErik Nordmark iras.ira_mhip = NULL; 381bd670b35SErik Nordmark } 382bd670b35SErik Nordmark /* Any remaining references to the route cache? */ 383bd670b35SErik Nordmark if (rtc.rtc_ire != NULL) { 384bd670b35SErik Nordmark ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&rtc.rtc_ip6addr)); 385bd670b35SErik Nordmark ire_refrele(rtc.rtc_ire); 386bd670b35SErik Nordmark } 387bd670b35SErik Nordmark 388bd670b35SErik Nordmark if (ahead != NULL) { 389bd670b35SErik Nordmark /* Better be called from ip_accept_tcp */ 390bd670b35SErik Nordmark ASSERT(target_sqp != NULL); 391bd670b35SErik Nordmark *last = atail; 392bd670b35SErik Nordmark *cnt = acnt; 393bd670b35SErik Nordmark return (ahead); 394bd670b35SErik Nordmark } 395bd670b35SErik Nordmark 396bd670b35SErik Nordmark return (NULL); 397bd670b35SErik Nordmark } 398bd670b35SErik Nordmark 399bd670b35SErik Nordmark /* 400bd670b35SErik Nordmark * This input function is used when 401bd670b35SErik Nordmark * - is_system_labeled() 402bd670b35SErik Nordmark * 403bd670b35SErik Nordmark * Note that for IPv6 CGTP filtering is handled only when receiving fragment 404bd670b35SErik Nordmark * headers, and RSVP uses router alert options, thus we don't need anything 405bd670b35SErik Nordmark * extra for them. 406bd670b35SErik Nordmark */ 407bd670b35SErik Nordmark void 408bd670b35SErik Nordmark ill_input_full_v6(mblk_t *mp, void *iph_arg, void *nexthop_arg, 409bd670b35SErik Nordmark ip_recv_attr_t *ira, rtc_t *rtc) 410bd670b35SErik Nordmark { 411bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 412bd670b35SErik Nordmark in6_addr_t *nexthop = (in6_addr_t *)nexthop_arg; 413bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 414bd670b35SErik Nordmark 415bd670b35SErik Nordmark ASSERT(ira->ira_tsl == NULL); 416bd670b35SErik Nordmark 417bd670b35SErik Nordmark /* 418bd670b35SErik Nordmark * Attach any necessary label information to 419bd670b35SErik Nordmark * this packet 420bd670b35SErik Nordmark */ 421bd670b35SErik Nordmark if (is_system_labeled()) { 422bd670b35SErik Nordmark ira->ira_flags |= IRAF_SYSTEM_LABELED; 423bd670b35SErik Nordmark 424bd670b35SErik Nordmark /* 425bd670b35SErik Nordmark * This updates ira_cred, ira_tsl and ira_free_flags based 426bd670b35SErik Nordmark * on the label. 427bd670b35SErik Nordmark */ 428bd670b35SErik Nordmark if (!tsol_get_pkt_label(mp, IPV6_VERSION, ira)) { 429bd670b35SErik Nordmark if (ip6opt_ls != 0) 430bd670b35SErik Nordmark ip0dbg(("tsol_get_pkt_label v6 failed\n")); 431bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 432bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 433bd670b35SErik Nordmark freemsg(mp); 434bd670b35SErik Nordmark return; 435bd670b35SErik Nordmark } 436bd670b35SErik Nordmark /* Note that ira_tsl can be NULL here. */ 437bd670b35SErik Nordmark 438bd670b35SErik Nordmark /* tsol_get_pkt_label sometimes does pullupmsg */ 439bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 440bd670b35SErik Nordmark } 441bd670b35SErik Nordmark ill_input_short_v6(mp, ip6h, nexthop, ira, rtc); 442bd670b35SErik Nordmark } 443bd670b35SErik Nordmark 444bd670b35SErik Nordmark /* 445bd670b35SErik Nordmark * Check for IPv6 addresses that should not appear on the wire 446bd670b35SErik Nordmark * as either source or destination. 447bd670b35SErik Nordmark * If we ever implement Stateless IPv6 Translators (SIIT) we'd have 448bd670b35SErik Nordmark * to revisit the IPv4-mapped part. 449bd670b35SErik Nordmark */ 450bd670b35SErik Nordmark static boolean_t 451bd670b35SErik Nordmark ip6_bad_address(in6_addr_t *addr, boolean_t is_src) 452bd670b35SErik Nordmark { 453bd670b35SErik Nordmark if (IN6_IS_ADDR_V4MAPPED(addr)) { 454bd670b35SErik Nordmark ip1dbg(("ip_input_v6: pkt with IPv4-mapped addr")); 455bd670b35SErik Nordmark return (B_TRUE); 456bd670b35SErik Nordmark } 457bd670b35SErik Nordmark if (IN6_IS_ADDR_LOOPBACK(addr)) { 458bd670b35SErik Nordmark ip1dbg(("ip_input_v6: pkt with loopback addr")); 459bd670b35SErik Nordmark return (B_TRUE); 460bd670b35SErik Nordmark } 461bd670b35SErik Nordmark if (!is_src && IN6_IS_ADDR_UNSPECIFIED(addr)) { 462bd670b35SErik Nordmark /* 463bd670b35SErik Nordmark * having :: in the src is ok: it's used for DAD. 464bd670b35SErik Nordmark */ 465bd670b35SErik Nordmark ip1dbg(("ip_input_v6: pkt with unspecified addr")); 466bd670b35SErik Nordmark return (B_TRUE); 467bd670b35SErik Nordmark } 468bd670b35SErik Nordmark return (B_FALSE); 469bd670b35SErik Nordmark } 470bd670b35SErik Nordmark 471bd670b35SErik Nordmark /* 472bd670b35SErik Nordmark * Routing lookup for IPv6 link-locals. 473bd670b35SErik Nordmark * First we look on the inbound interface, then we check for IPMP and 474bd670b35SErik Nordmark * look on the upper interface. 475bd670b35SErik Nordmark * We update ira_ruifindex if we find the IRE on the upper interface. 476bd670b35SErik Nordmark */ 477bd670b35SErik Nordmark static ire_t * 478bd670b35SErik Nordmark ire_linklocal(const in6_addr_t *nexthop, ill_t *ill, ip_recv_attr_t *ira, 4799e3469d3SErik Nordmark uint_t irr_flags, ip_stack_t *ipst) 480bd670b35SErik Nordmark { 481bd670b35SErik Nordmark int match_flags = MATCH_IRE_SECATTR | MATCH_IRE_ILL; 482bd670b35SErik Nordmark ire_t *ire; 483bd670b35SErik Nordmark 484bd670b35SErik Nordmark ASSERT(IN6_IS_ADDR_LINKLOCAL(nexthop)); 485bd670b35SErik Nordmark ire = ire_route_recursive_v6(nexthop, 0, ill, ALL_ZONES, ira->ira_tsl, 4869e3469d3SErik Nordmark match_flags, irr_flags, ira->ira_xmit_hint, ipst, NULL, NULL, NULL); 487bd670b35SErik Nordmark if (!(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) || 488bd670b35SErik Nordmark !IS_UNDER_IPMP(ill)) 489bd670b35SErik Nordmark return (ire); 490bd670b35SErik Nordmark 491bd670b35SErik Nordmark /* 492bd670b35SErik Nordmark * When we are using IMP we need to look for an IRE on both the 493bd670b35SErik Nordmark * under and upper interfaces since there are different 494bd670b35SErik Nordmark * link-local addresses for the under and upper. 495bd670b35SErik Nordmark */ 496bd670b35SErik Nordmark ill = ipmp_ill_hold_ipmp_ill(ill); 497bd670b35SErik Nordmark if (ill == NULL) 498bd670b35SErik Nordmark return (ire); 499bd670b35SErik Nordmark 500bd670b35SErik Nordmark ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 501bd670b35SErik Nordmark 502bd670b35SErik Nordmark ire_refrele(ire); 503bd670b35SErik Nordmark ire = ire_route_recursive_v6(nexthop, 0, ill, ALL_ZONES, ira->ira_tsl, 5049e3469d3SErik Nordmark match_flags, irr_flags, ira->ira_xmit_hint, ipst, NULL, NULL, NULL); 505bd670b35SErik Nordmark ill_refrele(ill); 506bd670b35SErik Nordmark return (ire); 507bd670b35SErik Nordmark } 508bd670b35SErik Nordmark 509bd670b35SErik Nordmark /* 510bd670b35SErik Nordmark * This is the tail-end of the full receive side packet handling. 511bd670b35SErik Nordmark * It can be used directly when the configuration is simple. 512bd670b35SErik Nordmark */ 513bd670b35SErik Nordmark void 514bd670b35SErik Nordmark ill_input_short_v6(mblk_t *mp, void *iph_arg, void *nexthop_arg, 515bd670b35SErik Nordmark ip_recv_attr_t *ira, rtc_t *rtc) 516bd670b35SErik Nordmark { 517bd670b35SErik Nordmark ire_t *ire; 518bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 519bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 520bd670b35SErik Nordmark uint_t pkt_len; 521bd670b35SErik Nordmark ssize_t len; 522bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 523bd670b35SErik Nordmark in6_addr_t nexthop = *(in6_addr_t *)nexthop_arg; 524bd670b35SErik Nordmark ilb_stack_t *ilbs = ipst->ips_netstack->netstack_ilb; 5259e3469d3SErik Nordmark uint_t irr_flags; 526bd670b35SErik Nordmark #define rptr ((uchar_t *)ip6h) 527bd670b35SErik Nordmark 528bd670b35SErik Nordmark ASSERT(DB_TYPE(mp) == M_DATA); 529bd670b35SErik Nordmark 530bd670b35SErik Nordmark /* 531bd670b35SErik Nordmark * Check for source/dest being a bad address: loopback, any, or 532bd670b35SErik Nordmark * v4mapped. All of them start with a 64 bits of zero. 533bd670b35SErik Nordmark */ 534bd670b35SErik Nordmark if (ip6h->ip6_src.s6_addr32[0] == 0 && 535bd670b35SErik Nordmark ip6h->ip6_src.s6_addr32[1] == 0) { 536bd670b35SErik Nordmark if (ip6_bad_address(&ip6h->ip6_src, B_TRUE)) { 537bd670b35SErik Nordmark ip1dbg(("ip_input_v6: pkt with bad src addr\n")); 538bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 539bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 540bd670b35SErik Nordmark freemsg(mp); 541bd670b35SErik Nordmark return; 542bd670b35SErik Nordmark } 543bd670b35SErik Nordmark } 544bd670b35SErik Nordmark if (ip6h->ip6_dst.s6_addr32[0] == 0 && 545bd670b35SErik Nordmark ip6h->ip6_dst.s6_addr32[1] == 0) { 546bd670b35SErik Nordmark if (ip6_bad_address(&ip6h->ip6_dst, B_FALSE)) { 547bd670b35SErik Nordmark ip1dbg(("ip_input_v6: pkt with bad dst addr\n")); 548bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 549bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 550bd670b35SErik Nordmark freemsg(mp); 551bd670b35SErik Nordmark return; 552bd670b35SErik Nordmark } 553bd670b35SErik Nordmark } 554bd670b35SErik Nordmark 555bd670b35SErik Nordmark len = mp->b_wptr - rptr; 556bd670b35SErik Nordmark pkt_len = ira->ira_pktlen; 557bd670b35SErik Nordmark 558bd670b35SErik Nordmark /* multiple mblk or too short */ 559bd670b35SErik Nordmark len -= pkt_len; 560bd670b35SErik Nordmark if (len != 0) { 561bd670b35SErik Nordmark mp = ip_check_length(mp, rptr, len, pkt_len, IPV6_HDR_LEN, ira); 562bd670b35SErik Nordmark if (mp == NULL) 563bd670b35SErik Nordmark return; 564bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 565bd670b35SErik Nordmark } 566bd670b35SErik Nordmark 567bd670b35SErik Nordmark DTRACE_IP7(receive, mblk_t *, mp, conn_t *, NULL, void_ip_t *, 568bd670b35SErik Nordmark ip6h, __dtrace_ipsr_ill_t *, ill, ipha_t *, NULL, ip6_t *, ip6h, 569bd670b35SErik Nordmark int, 0); 570bd670b35SErik Nordmark /* 571bd670b35SErik Nordmark * The event for packets being received from a 'physical' 572bd670b35SErik Nordmark * interface is placed after validation of the source and/or 573bd670b35SErik Nordmark * destination address as being local so that packets can be 574bd670b35SErik Nordmark * redirected to loopback addresses using ipnat. 575bd670b35SErik Nordmark */ 576bd670b35SErik Nordmark DTRACE_PROBE4(ip6__physical__in__start, 577bd670b35SErik Nordmark ill_t *, ill, ill_t *, NULL, 578bd670b35SErik Nordmark ip6_t *, ip6h, mblk_t *, mp); 579bd670b35SErik Nordmark 580bd670b35SErik Nordmark if (HOOKS6_INTERESTED_PHYSICAL_IN(ipst)) { 581bd670b35SErik Nordmark int ll_multicast = 0; 582bd670b35SErik Nordmark int error; 583bd670b35SErik Nordmark in6_addr_t orig_dst = ip6h->ip6_dst; 584bd670b35SErik Nordmark 585bd670b35SErik Nordmark if (ira->ira_flags & IRAF_L2DST_MULTICAST) 586bd670b35SErik Nordmark ll_multicast = HPE_MULTICAST; 587bd670b35SErik Nordmark else if (ira->ira_flags & IRAF_L2DST_BROADCAST) 588bd670b35SErik Nordmark ll_multicast = HPE_BROADCAST; 589bd670b35SErik Nordmark 590bd670b35SErik Nordmark FW_HOOKS6(ipst->ips_ip6_physical_in_event, 591bd670b35SErik Nordmark ipst->ips_ipv6firewall_physical_in, 592bd670b35SErik Nordmark ill, NULL, ip6h, mp, mp, ll_multicast, ipst, error); 593bd670b35SErik Nordmark 594bd670b35SErik Nordmark DTRACE_PROBE1(ip6__physical__in__end, mblk_t *, mp); 595bd670b35SErik Nordmark 596bd670b35SErik Nordmark if (mp == NULL) 597bd670b35SErik Nordmark return; 598bd670b35SErik Nordmark 599bd670b35SErik Nordmark /* The length could have changed */ 600bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 601bd670b35SErik Nordmark ira->ira_pktlen = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; 602bd670b35SErik Nordmark pkt_len = ira->ira_pktlen; 603bd670b35SErik Nordmark 604bd670b35SErik Nordmark /* 605bd670b35SErik Nordmark * In case the destination changed we override any previous 606bd670b35SErik Nordmark * change to nexthop. 607bd670b35SErik Nordmark */ 608bd670b35SErik Nordmark if (!IN6_ARE_ADDR_EQUAL(&orig_dst, &ip6h->ip6_dst)) 609bd670b35SErik Nordmark nexthop = ip6h->ip6_dst; 610bd670b35SErik Nordmark 611bd670b35SErik Nordmark if (IN6_IS_ADDR_UNSPECIFIED(&nexthop)) { 612bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 613bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 614bd670b35SErik Nordmark freemsg(mp); 615bd670b35SErik Nordmark return; 616bd670b35SErik Nordmark } 617bd670b35SErik Nordmark 618bd670b35SErik Nordmark } 619bd670b35SErik Nordmark 620bd670b35SErik Nordmark if (ipst->ips_ip6_observe.he_interested) { 621bd670b35SErik Nordmark zoneid_t dzone; 622bd670b35SErik Nordmark 623bd670b35SErik Nordmark /* 624bd670b35SErik Nordmark * On the inbound path the src zone will be unknown as 625bd670b35SErik Nordmark * this packet has come from the wire. 626bd670b35SErik Nordmark */ 627bd670b35SErik Nordmark dzone = ip_get_zoneid_v6(&nexthop, mp, ill, ira, ALL_ZONES); 628bd670b35SErik Nordmark ipobs_hook(mp, IPOBS_HOOK_INBOUND, ALL_ZONES, dzone, ill, ipst); 629bd670b35SErik Nordmark } 630bd670b35SErik Nordmark 631bd670b35SErik Nordmark if ((ip6h->ip6_vcf & IPV6_VERS_AND_FLOW_MASK) != 632bd670b35SErik Nordmark IPV6_DEFAULT_VERS_AND_FLOW) { 633bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInHdrErrors); 634bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInWrongIPVersion); 635bd670b35SErik Nordmark ip_drop_input("ipIfStatsInWrongIPVersion", mp, ill); 636bd670b35SErik Nordmark freemsg(mp); 637bd670b35SErik Nordmark return; 638bd670b35SErik Nordmark } 639bd670b35SErik Nordmark 640bd670b35SErik Nordmark /* 641bd670b35SErik Nordmark * For IPv6 we update ira_ip_hdr_length and ira_protocol as 642bd670b35SErik Nordmark * we parse the headers, starting with the hop-by-hop options header. 643bd670b35SErik Nordmark */ 644bd670b35SErik Nordmark ira->ira_ip_hdr_length = IPV6_HDR_LEN; 645bd670b35SErik Nordmark if ((ira->ira_protocol = ip6h->ip6_nxt) == IPPROTO_HOPOPTS) { 646bd670b35SErik Nordmark ip6_hbh_t *hbhhdr; 647bd670b35SErik Nordmark uint_t ehdrlen; 648bd670b35SErik Nordmark uint8_t *optptr; 649bd670b35SErik Nordmark 650bd670b35SErik Nordmark if (pkt_len < IPV6_HDR_LEN + MIN_EHDR_LEN) { 651bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts); 652bd670b35SErik Nordmark ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill); 653bd670b35SErik Nordmark freemsg(mp); 654bd670b35SErik Nordmark return; 655bd670b35SErik Nordmark } 656bd670b35SErik Nordmark if (mp->b_cont != NULL && 657bd670b35SErik Nordmark rptr + IPV6_HDR_LEN + MIN_EHDR_LEN > mp->b_wptr) { 658bd670b35SErik Nordmark ip6h = ip_pullup(mp, IPV6_HDR_LEN + MIN_EHDR_LEN, ira); 659bd670b35SErik Nordmark if (ip6h == NULL) { 660bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 661bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 662bd670b35SErik Nordmark freemsg(mp); 663bd670b35SErik Nordmark return; 664bd670b35SErik Nordmark } 665bd670b35SErik Nordmark } 666bd670b35SErik Nordmark hbhhdr = (ip6_hbh_t *)&ip6h[1]; 667bd670b35SErik Nordmark ehdrlen = 8 * (hbhhdr->ip6h_len + 1); 668bd670b35SErik Nordmark 669bd670b35SErik Nordmark if (pkt_len < IPV6_HDR_LEN + ehdrlen) { 670bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts); 671bd670b35SErik Nordmark ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill); 672bd670b35SErik Nordmark freemsg(mp); 673bd670b35SErik Nordmark return; 674bd670b35SErik Nordmark } 675bd670b35SErik Nordmark if (mp->b_cont != NULL && 676bd670b35SErik Nordmark rptr + IPV6_HDR_LEN + ehdrlen > mp->b_wptr) { 677bd670b35SErik Nordmark ip6h = ip_pullup(mp, IPV6_HDR_LEN + ehdrlen, ira); 678bd670b35SErik Nordmark if (ip6h == NULL) { 679bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 680bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 681bd670b35SErik Nordmark freemsg(mp); 682bd670b35SErik Nordmark return; 683bd670b35SErik Nordmark } 684bd670b35SErik Nordmark hbhhdr = (ip6_hbh_t *)&ip6h[1]; 685bd670b35SErik Nordmark } 686bd670b35SErik Nordmark 687bd670b35SErik Nordmark /* 688bd670b35SErik Nordmark * Update ira_ip_hdr_length to skip the hop-by-hop header 689bd670b35SErik Nordmark * once we get to ip_fanout_v6 690bd670b35SErik Nordmark */ 691bd670b35SErik Nordmark ira->ira_ip_hdr_length += ehdrlen; 692bd670b35SErik Nordmark ira->ira_protocol = hbhhdr->ip6h_nxt; 693bd670b35SErik Nordmark 694bd670b35SErik Nordmark optptr = (uint8_t *)&hbhhdr[1]; 695bd670b35SErik Nordmark switch (ip_process_options_v6(mp, ip6h, optptr, 696bd670b35SErik Nordmark ehdrlen - 2, IPPROTO_HOPOPTS, ira)) { 697bd670b35SErik Nordmark case -1: 698bd670b35SErik Nordmark /* 699bd670b35SErik Nordmark * Packet has been consumed and any 700bd670b35SErik Nordmark * needed ICMP messages sent. 701bd670b35SErik Nordmark */ 702bd670b35SErik Nordmark return; 703bd670b35SErik Nordmark case 0: 704bd670b35SErik Nordmark /* no action needed */ 705bd670b35SErik Nordmark break; 706bd670b35SErik Nordmark case 1: 707bd670b35SErik Nordmark /* 708bd670b35SErik Nordmark * Known router alert. Make use handle it as local 709bd670b35SErik Nordmark * by setting the nexthop to be the all-host multicast 710bd670b35SErik Nordmark * address, and skip multicast membership filter by 711bd670b35SErik Nordmark * marking as a router alert. 712bd670b35SErik Nordmark */ 713bd670b35SErik Nordmark ira->ira_flags |= IRAF_ROUTER_ALERT; 714bd670b35SErik Nordmark nexthop = ipv6_all_hosts_mcast; 715bd670b35SErik Nordmark break; 716bd670b35SErik Nordmark } 717bd670b35SErik Nordmark } 718bd670b35SErik Nordmark 719bd670b35SErik Nordmark /* 720bd670b35SErik Nordmark * Here we check to see if we machine is setup as 721bd670b35SErik Nordmark * L3 loadbalancer and if the incoming packet is for a VIP 722bd670b35SErik Nordmark * 723bd670b35SErik Nordmark * Check the following: 724bd670b35SErik Nordmark * - there is at least a rule 725bd670b35SErik Nordmark * - protocol of the packet is supported 726bd670b35SErik Nordmark * 727bd670b35SErik Nordmark * We don't load balance IPv6 link-locals. 728bd670b35SErik Nordmark */ 729bd670b35SErik Nordmark if (ilb_has_rules(ilbs) && ILB_SUPP_L4(ira->ira_protocol) && 730bd670b35SErik Nordmark !IN6_IS_ADDR_LINKLOCAL(&nexthop)) { 731bd670b35SErik Nordmark in6_addr_t lb_dst; 732bd670b35SErik Nordmark int lb_ret; 733bd670b35SErik Nordmark 734bd670b35SErik Nordmark /* For convenience, we just pull up the mblk. */ 735bd670b35SErik Nordmark if (mp->b_cont != NULL) { 736bd670b35SErik Nordmark if (pullupmsg(mp, -1) == 0) { 737bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 738bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards - pullupmsg", 739bd670b35SErik Nordmark mp, ill); 740bd670b35SErik Nordmark freemsg(mp); 741bd670b35SErik Nordmark return; 742bd670b35SErik Nordmark } 743bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 744bd670b35SErik Nordmark } 745bd670b35SErik Nordmark lb_ret = ilb_check_v6(ilbs, ill, mp, ip6h, ira->ira_protocol, 746bd670b35SErik Nordmark (uint8_t *)ip6h + ira->ira_ip_hdr_length, &lb_dst); 747bd670b35SErik Nordmark if (lb_ret == ILB_DROPPED) { 748bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 749bd670b35SErik Nordmark ip_drop_input("ILB_DROPPED", mp, ill); 750bd670b35SErik Nordmark freemsg(mp); 751bd670b35SErik Nordmark return; 752bd670b35SErik Nordmark } 753bd670b35SErik Nordmark if (lb_ret == ILB_BALANCED) { 754bd670b35SErik Nordmark /* Set the dst to that of the chosen server */ 755bd670b35SErik Nordmark nexthop = lb_dst; 756bd670b35SErik Nordmark DB_CKSUMFLAGS(mp) = 0; 757bd670b35SErik Nordmark } 758bd670b35SErik Nordmark } 759bd670b35SErik Nordmark 7609e3469d3SErik Nordmark if (ill->ill_flags & ILLF_ROUTER) 7619e3469d3SErik Nordmark irr_flags = IRR_ALLOCATE; 7629e3469d3SErik Nordmark else 7639e3469d3SErik Nordmark irr_flags = IRR_NONE; 7649e3469d3SErik Nordmark 765bd670b35SErik Nordmark /* Can not use route cache with TX since the labels can differ */ 766bd670b35SErik Nordmark if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 767bd670b35SErik Nordmark if (IN6_IS_ADDR_MULTICAST(&nexthop)) { 768bd670b35SErik Nordmark ire = ire_multicast(ill); 769bd670b35SErik Nordmark } else if (IN6_IS_ADDR_LINKLOCAL(&nexthop)) { 7709e3469d3SErik Nordmark ire = ire_linklocal(&nexthop, ill, ira, irr_flags, 7719e3469d3SErik Nordmark ipst); 772bd670b35SErik Nordmark } else { 773bd670b35SErik Nordmark /* Match destination and label */ 774bd670b35SErik Nordmark ire = ire_route_recursive_v6(&nexthop, 0, NULL, 775bd670b35SErik Nordmark ALL_ZONES, ira->ira_tsl, MATCH_IRE_SECATTR, 7769e3469d3SErik Nordmark irr_flags, ira->ira_xmit_hint, ipst, NULL, NULL, 7779e3469d3SErik Nordmark NULL); 778bd670b35SErik Nordmark } 779bd670b35SErik Nordmark /* Update the route cache so we do the ire_refrele */ 780bd670b35SErik Nordmark ASSERT(ire != NULL); 781bd670b35SErik Nordmark if (rtc->rtc_ire != NULL) 782bd670b35SErik Nordmark ire_refrele(rtc->rtc_ire); 783bd670b35SErik Nordmark rtc->rtc_ire = ire; 784bd670b35SErik Nordmark rtc->rtc_ip6addr = nexthop; 785*af10b639SDan McDonald } else if (IN6_ARE_ADDR_EQUAL(&nexthop, &rtc->rtc_ip6addr) && 786*af10b639SDan McDonald rtc->rtc_ire != NULL) { 787bd670b35SErik Nordmark /* Use the route cache */ 788bd670b35SErik Nordmark ire = rtc->rtc_ire; 789bd670b35SErik Nordmark } else { 790bd670b35SErik Nordmark /* Update the route cache */ 791bd670b35SErik Nordmark if (IN6_IS_ADDR_MULTICAST(&nexthop)) { 792bd670b35SErik Nordmark ire = ire_multicast(ill); 793bd670b35SErik Nordmark } else if (IN6_IS_ADDR_LINKLOCAL(&nexthop)) { 7949e3469d3SErik Nordmark ire = ire_linklocal(&nexthop, ill, ira, irr_flags, 7959e3469d3SErik Nordmark ipst); 796bd670b35SErik Nordmark } else { 797bd670b35SErik Nordmark ire = ire_route_recursive_dstonly_v6(&nexthop, 7989e3469d3SErik Nordmark irr_flags, ira->ira_xmit_hint, ipst); 799bd670b35SErik Nordmark } 800bd670b35SErik Nordmark ASSERT(ire != NULL); 801bd670b35SErik Nordmark if (rtc->rtc_ire != NULL) 802bd670b35SErik Nordmark ire_refrele(rtc->rtc_ire); 803bd670b35SErik Nordmark rtc->rtc_ire = ire; 804bd670b35SErik Nordmark rtc->rtc_ip6addr = nexthop; 805bd670b35SErik Nordmark } 806bd670b35SErik Nordmark 807bd670b35SErik Nordmark ire->ire_ib_pkt_count++; 808bd670b35SErik Nordmark 809bd670b35SErik Nordmark /* 810bd670b35SErik Nordmark * Based on ire_type and ire_flags call one of: 811bd670b35SErik Nordmark * ire_recv_local_v6 - for IRE_LOCAL 812bd670b35SErik Nordmark * ire_recv_loopback_v6 - for IRE_LOOPBACK 813bd670b35SErik Nordmark * ire_recv_multirt_v6 - if RTF_MULTIRT 814bd670b35SErik Nordmark * ire_recv_noroute_v6 - if RTF_REJECT or RTF_BLACHOLE 815bd670b35SErik Nordmark * ire_recv_multicast_v6 - for IRE_MULTICAST 816bd670b35SErik Nordmark * ire_recv_noaccept_v6 - for ire_noaccept ones 817bd670b35SErik Nordmark * ire_recv_forward_v6 - for the rest. 818bd670b35SErik Nordmark */ 819bd670b35SErik Nordmark 820bd670b35SErik Nordmark (*ire->ire_recvfn)(ire, mp, ip6h, ira); 821bd670b35SErik Nordmark } 822bd670b35SErik Nordmark #undef rptr 823bd670b35SErik Nordmark 824bd670b35SErik Nordmark /* 825bd670b35SErik Nordmark * ire_recvfn for IREs that need forwarding 826bd670b35SErik Nordmark */ 827bd670b35SErik Nordmark void 828bd670b35SErik Nordmark ire_recv_forward_v6(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 829bd670b35SErik Nordmark { 830bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 831bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 832bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 833bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 834bd670b35SErik Nordmark ill_t *dst_ill; 835bd670b35SErik Nordmark nce_t *nce; 836bd670b35SErik Nordmark uint32_t added_tx_len; 837bd670b35SErik Nordmark uint32_t mtu, iremtu; 838bd670b35SErik Nordmark 839bd670b35SErik Nordmark if (iraflags & (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) { 840bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 841bd670b35SErik Nordmark ip_drop_input("l2 multicast not forwarded", mp, ill); 842bd670b35SErik Nordmark freemsg(mp); 843bd670b35SErik Nordmark return; 844bd670b35SErik Nordmark } 845bd670b35SErik Nordmark 846bd670b35SErik Nordmark if (!(ill->ill_flags & ILLF_ROUTER)) { 847bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 848bd670b35SErik Nordmark ip_drop_input("ipIfStatsForwProhibits", mp, ill); 849bd670b35SErik Nordmark freemsg(mp); 850bd670b35SErik Nordmark return; 851bd670b35SErik Nordmark } 852bd670b35SErik Nordmark 853bd670b35SErik Nordmark /* 854bd670b35SErik Nordmark * Either ire_nce_capable or ire_dep_parent would be set for the IRE 855bd670b35SErik Nordmark * when it is found by ire_route_recursive, but that some other thread 856bd670b35SErik Nordmark * could have changed the routes with the effect of clearing 857bd670b35SErik Nordmark * ire_dep_parent. In that case we'd end up dropping the packet, or 858bd670b35SErik Nordmark * finding a new nce below. 859bd670b35SErik Nordmark * Get, allocate, or update the nce. 860bd670b35SErik Nordmark * We get a refhold on ire_nce_cache as a result of this to avoid races 861bd670b35SErik Nordmark * where ire_nce_cache is deleted. 862bd670b35SErik Nordmark * 863bd670b35SErik Nordmark * This ensures that we don't forward if the interface is down since 864bd670b35SErik Nordmark * ipif_down removes all the nces. 865bd670b35SErik Nordmark */ 866bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 867bd670b35SErik Nordmark nce = ire->ire_nce_cache; 868bd670b35SErik Nordmark if (nce == NULL) { 869bd670b35SErik Nordmark /* Not yet set up - try to set one up */ 870bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 871bd670b35SErik Nordmark (void) ire_revalidate_nce(ire); 872bd670b35SErik Nordmark mutex_enter(&ire->ire_lock); 873bd670b35SErik Nordmark nce = ire->ire_nce_cache; 874bd670b35SErik Nordmark if (nce == NULL) { 875bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 876bd670b35SErik Nordmark /* The ire_dep_parent chain went bad, or no memory */ 877bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 878bd670b35SErik Nordmark ip_drop_input("No ire_dep_parent", mp, ill); 879bd670b35SErik Nordmark freemsg(mp); 880bd670b35SErik Nordmark return; 881bd670b35SErik Nordmark } 882bd670b35SErik Nordmark } 883bd670b35SErik Nordmark nce_refhold(nce); 884bd670b35SErik Nordmark mutex_exit(&ire->ire_lock); 885bd670b35SErik Nordmark 886bd670b35SErik Nordmark if (nce->nce_is_condemned) { 887bd670b35SErik Nordmark nce_t *nce1; 888bd670b35SErik Nordmark 889bd670b35SErik Nordmark nce1 = ire_handle_condemned_nce(nce, ire, NULL, ip6h, B_FALSE); 890bd670b35SErik Nordmark nce_refrele(nce); 891bd670b35SErik Nordmark if (nce1 == NULL) { 892bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 893bd670b35SErik Nordmark ip_drop_input("No nce", mp, ill); 894bd670b35SErik Nordmark freemsg(mp); 895bd670b35SErik Nordmark return; 896bd670b35SErik Nordmark } 897bd670b35SErik Nordmark nce = nce1; 898bd670b35SErik Nordmark } 899bd670b35SErik Nordmark dst_ill = nce->nce_ill; 900bd670b35SErik Nordmark 901bd670b35SErik Nordmark /* 902bd670b35SErik Nordmark * Unless we are forwarding, drop the packet. 903bd670b35SErik Nordmark * Unlike IPv4 we don't allow source routed packets out the same 904bd670b35SErik Nordmark * interface when we are not a router. 905bd670b35SErik Nordmark * Note that ill_forward_set() will set the ILLF_ROUTER on 906bd670b35SErik Nordmark * all the group members when it gets an ipmp-ill or under-ill. 907bd670b35SErik Nordmark */ 908bd670b35SErik Nordmark if (!(dst_ill->ill_flags & ILLF_ROUTER)) { 909bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 910bd670b35SErik Nordmark ip_drop_input("ipIfStatsForwProhibits", mp, ill); 911bd670b35SErik Nordmark freemsg(mp); 912bd670b35SErik Nordmark nce_refrele(nce); 913bd670b35SErik Nordmark return; 914bd670b35SErik Nordmark } 915bd670b35SErik Nordmark 916bd670b35SErik Nordmark if (ire->ire_zoneid != GLOBAL_ZONEID && ire->ire_zoneid != ALL_ZONES) { 917bd670b35SErik Nordmark ire->ire_ib_pkt_count--; 918bd670b35SErik Nordmark /* 919bd670b35SErik Nordmark * Should only use IREs that are visible from the 920bd670b35SErik Nordmark * global zone for forwarding. 921bd670b35SErik Nordmark * For IPv6 any source route would have already been 922bd670b35SErik Nordmark * advanced in ip_fanout_v6 923bd670b35SErik Nordmark */ 924bd670b35SErik Nordmark ire = ire_route_recursive_v6(&ip6h->ip6_dst, 0, NULL, 925bd670b35SErik Nordmark GLOBAL_ZONEID, ira->ira_tsl, MATCH_IRE_SECATTR, 9269e3469d3SErik Nordmark (ill->ill_flags & ILLF_ROUTER) ? IRR_ALLOCATE : IRR_NONE, 9279e3469d3SErik Nordmark ira->ira_xmit_hint, ipst, NULL, NULL, NULL); 928bd670b35SErik Nordmark ire->ire_ib_pkt_count++; 929bd670b35SErik Nordmark (*ire->ire_recvfn)(ire, mp, ip6h, ira); 930bd670b35SErik Nordmark ire_refrele(ire); 931bd670b35SErik Nordmark nce_refrele(nce); 932bd670b35SErik Nordmark return; 933bd670b35SErik Nordmark } 934bd670b35SErik Nordmark /* 935bd670b35SErik Nordmark * ipIfStatsHCInForwDatagrams should only be increment if there 936bd670b35SErik Nordmark * will be an attempt to forward the packet, which is why we 937bd670b35SErik Nordmark * increment after the above condition has been checked. 938bd670b35SErik Nordmark */ 939bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInForwDatagrams); 940bd670b35SErik Nordmark 941bd670b35SErik Nordmark /* Initiate Read side IPPF processing */ 942bd670b35SErik Nordmark if (IPP_ENABLED(IPP_FWD_IN, ipst)) { 943bd670b35SErik Nordmark /* ip_process translates an IS_UNDER_IPMP */ 944bd670b35SErik Nordmark mp = ip_process(IPP_FWD_IN, mp, ill, ill); 945bd670b35SErik Nordmark if (mp == NULL) { 946bd670b35SErik Nordmark /* ip_drop_packet and MIB done */ 947bd670b35SErik Nordmark ip2dbg(("ire_recv_forward_v6: pkt dropped/deferred " 948bd670b35SErik Nordmark "during IPPF processing\n")); 949bd670b35SErik Nordmark nce_refrele(nce); 950bd670b35SErik Nordmark return; 951bd670b35SErik Nordmark } 952bd670b35SErik Nordmark } 953bd670b35SErik Nordmark 954bd670b35SErik Nordmark DTRACE_PROBE4(ip6__forwarding__start, 955bd670b35SErik Nordmark ill_t *, ill, ill_t *, dst_ill, ip6_t *, ip6h, mblk_t *, mp); 956bd670b35SErik Nordmark 957bd670b35SErik Nordmark if (HOOKS6_INTERESTED_FORWARDING(ipst)) { 958bd670b35SErik Nordmark int error; 959bd670b35SErik Nordmark 960bd670b35SErik Nordmark FW_HOOKS(ipst->ips_ip6_forwarding_event, 961bd670b35SErik Nordmark ipst->ips_ipv6firewall_forwarding, 962bd670b35SErik Nordmark ill, dst_ill, ip6h, mp, mp, 0, ipst, error); 963bd670b35SErik Nordmark 964bd670b35SErik Nordmark DTRACE_PROBE1(ip6__forwarding__end, mblk_t *, mp); 965bd670b35SErik Nordmark 966bd670b35SErik Nordmark if (mp == NULL) { 967bd670b35SErik Nordmark nce_refrele(nce); 968bd670b35SErik Nordmark return; 969bd670b35SErik Nordmark } 970bd670b35SErik Nordmark /* 971bd670b35SErik Nordmark * Even if the destination was changed by the filter we use the 972bd670b35SErik Nordmark * forwarding decision that was made based on the address 973bd670b35SErik Nordmark * in ip_input. 974bd670b35SErik Nordmark */ 975bd670b35SErik Nordmark 976bd670b35SErik Nordmark /* Might have changed */ 977bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 978bd670b35SErik Nordmark ira->ira_pktlen = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; 979bd670b35SErik Nordmark } 980bd670b35SErik Nordmark 981bd670b35SErik Nordmark /* Packet is being forwarded. Turning off hwcksum flag. */ 982bd670b35SErik Nordmark DB_CKSUMFLAGS(mp) = 0; 983bd670b35SErik Nordmark 984bd670b35SErik Nordmark /* 985bd670b35SErik Nordmark * Per RFC 3513 section 2.5.2, we must not forward packets with 986bd670b35SErik Nordmark * an unspecified source address. 987bd670b35SErik Nordmark * The loopback address check for both src and dst has already 988bd670b35SErik Nordmark * been checked in ip_input_v6 989bd670b35SErik Nordmark * In the future one can envision adding RPF checks using number 3. 990bd670b35SErik Nordmark */ 991bd670b35SErik Nordmark switch (ipst->ips_src_check) { 992bd670b35SErik Nordmark case 0: 993bd670b35SErik Nordmark break; 994bd670b35SErik Nordmark case 1: 995bd670b35SErik Nordmark case 2: 996bd670b35SErik Nordmark if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src) || 997bd670b35SErik Nordmark IN6_IS_ADDR_MULTICAST(&ip6h->ip6_src)) { 998bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 999bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 1000bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 1001bd670b35SErik Nordmark nce_refrele(nce); 1002bd670b35SErik Nordmark freemsg(mp); 1003bd670b35SErik Nordmark return; 1004bd670b35SErik Nordmark } 1005bd670b35SErik Nordmark break; 1006bd670b35SErik Nordmark } 1007bd670b35SErik Nordmark 1008bd670b35SErik Nordmark /* 1009bd670b35SErik Nordmark * Check to see if we're forwarding the packet to a 1010bd670b35SErik Nordmark * different link from which it came. If so, check the 1011bd670b35SErik Nordmark * source and destination addresses since routers must not 1012bd670b35SErik Nordmark * forward any packets with link-local source or 1013bd670b35SErik Nordmark * destination addresses to other links. Otherwise (if 1014bd670b35SErik Nordmark * we're forwarding onto the same link), conditionally send 1015bd670b35SErik Nordmark * a redirect message. 1016bd670b35SErik Nordmark */ 1017bd670b35SErik Nordmark if (!IS_ON_SAME_LAN(dst_ill, ill)) { 1018bd670b35SErik Nordmark if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) || 1019bd670b35SErik Nordmark IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src)) { 1020bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 1021bd670b35SErik Nordmark ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 1022bd670b35SErik Nordmark freemsg(mp); 1023bd670b35SErik Nordmark nce_refrele(nce); 1024bd670b35SErik Nordmark return; 1025bd670b35SErik Nordmark } 1026bd670b35SErik Nordmark /* TBD add site-local check at site boundary? */ 1027bd670b35SErik Nordmark } else if (ipst->ips_ipv6_send_redirects) { 1028bd670b35SErik Nordmark ip_send_potential_redirect_v6(mp, ip6h, ire, ira); 1029bd670b35SErik Nordmark } 1030bd670b35SErik Nordmark 1031bd670b35SErik Nordmark added_tx_len = 0; 1032bd670b35SErik Nordmark if (iraflags & IRAF_SYSTEM_LABELED) { 1033bd670b35SErik Nordmark mblk_t *mp1; 1034bd670b35SErik Nordmark uint32_t old_pkt_len = ira->ira_pktlen; 1035bd670b35SErik Nordmark 1036bd670b35SErik Nordmark /* 1037bd670b35SErik Nordmark * Check if it can be forwarded and add/remove 1038bd670b35SErik Nordmark * CIPSO options as needed. 1039bd670b35SErik Nordmark */ 1040bd670b35SErik Nordmark if ((mp1 = tsol_ip_forward(ire, mp, ira)) == NULL) { 1041bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 1042bd670b35SErik Nordmark ip_drop_input("tsol_ip_forward", mp, ill); 1043bd670b35SErik Nordmark freemsg(mp); 1044bd670b35SErik Nordmark nce_refrele(nce); 1045bd670b35SErik Nordmark return; 1046bd670b35SErik Nordmark } 1047bd670b35SErik Nordmark /* 1048bd670b35SErik Nordmark * Size may have changed. Remember amount added in case 1049bd670b35SErik Nordmark * ip_fragment needs to send an ICMP too big. 1050bd670b35SErik Nordmark */ 1051bd670b35SErik Nordmark mp = mp1; 1052bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 1053bd670b35SErik Nordmark ira->ira_pktlen = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; 1054bd670b35SErik Nordmark ira->ira_ip_hdr_length = IPV6_HDR_LEN; 1055bd670b35SErik Nordmark if (ira->ira_pktlen > old_pkt_len) 1056bd670b35SErik Nordmark added_tx_len = ira->ira_pktlen - old_pkt_len; 1057bd670b35SErik Nordmark } 1058bd670b35SErik Nordmark 1059bd670b35SErik Nordmark mtu = dst_ill->ill_mtu; 1060bd670b35SErik Nordmark if ((iremtu = ire->ire_metrics.iulp_mtu) != 0 && iremtu < mtu) 1061bd670b35SErik Nordmark mtu = iremtu; 1062bd670b35SErik Nordmark ip_forward_xmit_v6(nce, mp, ip6h, ira, mtu, added_tx_len); 1063bd670b35SErik Nordmark nce_refrele(nce); 1064bd670b35SErik Nordmark return; 1065bd670b35SErik Nordmark 1066bd670b35SErik Nordmark } 1067bd670b35SErik Nordmark 1068bd670b35SErik Nordmark /* 1069bd670b35SErik Nordmark * Used for sending out unicast and multicast packets that are 1070bd670b35SErik Nordmark * forwarded. 1071bd670b35SErik Nordmark */ 1072bd670b35SErik Nordmark void 1073bd670b35SErik Nordmark ip_forward_xmit_v6(nce_t *nce, mblk_t *mp, ip6_t *ip6h, ip_recv_attr_t *ira, 1074bd670b35SErik Nordmark uint32_t mtu, uint32_t added_tx_len) 1075bd670b35SErik Nordmark { 1076bd670b35SErik Nordmark ill_t *dst_ill = nce->nce_ill; 1077bd670b35SErik Nordmark uint32_t pkt_len; 1078bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 1079bd670b35SErik Nordmark ip_stack_t *ipst = dst_ill->ill_ipst; 1080bd670b35SErik Nordmark 1081bd670b35SErik Nordmark if (ip6h->ip6_hops-- <= 1) { 1082bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 1083bd670b35SErik Nordmark ip_drop_input("ICMP6_TIME_EXCEED_TRANSIT", mp, ira->ira_ill); 1084bd670b35SErik Nordmark icmp_time_exceeded_v6(mp, ICMP6_TIME_EXCEED_TRANSIT, B_FALSE, 1085bd670b35SErik Nordmark ira); 1086bd670b35SErik Nordmark return; 1087bd670b35SErik Nordmark } 1088bd670b35SErik Nordmark 1089bd670b35SErik Nordmark /* Initiate Write side IPPF processing before any fragmentation */ 1090bd670b35SErik Nordmark if (IPP_ENABLED(IPP_FWD_OUT, ipst)) { 1091bd670b35SErik Nordmark /* ip_process translates an IS_UNDER_IPMP */ 1092bd670b35SErik Nordmark mp = ip_process(IPP_FWD_OUT, mp, dst_ill, dst_ill); 1093bd670b35SErik Nordmark if (mp == NULL) { 1094bd670b35SErik Nordmark /* ip_drop_packet and MIB done */ 1095bd670b35SErik Nordmark ip2dbg(("ire_recv_forward_v6: pkt dropped/deferred" \ 1096bd670b35SErik Nordmark " during IPPF processing\n")); 1097bd670b35SErik Nordmark return; 1098bd670b35SErik Nordmark } 1099bd670b35SErik Nordmark } 1100bd670b35SErik Nordmark 1101bd670b35SErik Nordmark pkt_len = ira->ira_pktlen; 1102bd670b35SErik Nordmark 1103bd670b35SErik Nordmark BUMP_MIB(dst_ill->ill_ip_mib, ipIfStatsHCOutForwDatagrams); 1104bd670b35SErik Nordmark 1105bd670b35SErik Nordmark if (pkt_len > mtu) { 1106bd670b35SErik Nordmark BUMP_MIB(dst_ill->ill_ip_mib, ipIfStatsOutFragFails); 1107bd670b35SErik Nordmark ip_drop_output("ipIfStatsOutFragFails", mp, dst_ill); 1108bd670b35SErik Nordmark if (iraflags & IRAF_SYSTEM_LABELED) { 1109bd670b35SErik Nordmark /* 1110bd670b35SErik Nordmark * Remove any CIPSO option added by 1111bd670b35SErik Nordmark * tsol_ip_forward, and make sure we report 1112bd670b35SErik Nordmark * a path MTU so that there 1113bd670b35SErik Nordmark * is room to add such a CIPSO option for future 1114bd670b35SErik Nordmark * packets. 1115bd670b35SErik Nordmark */ 1116bd670b35SErik Nordmark mtu = tsol_pmtu_adjust(mp, mtu, added_tx_len, AF_INET6); 1117bd670b35SErik Nordmark } 1118bd670b35SErik Nordmark icmp_pkt2big_v6(mp, mtu, B_TRUE, ira); 1119bd670b35SErik Nordmark return; 1120bd670b35SErik Nordmark } 1121bd670b35SErik Nordmark 1122bd670b35SErik Nordmark ASSERT(pkt_len == 1123bd670b35SErik Nordmark ntohs(((ip6_t *)mp->b_rptr)->ip6_plen) + IPV6_HDR_LEN); 1124bd670b35SErik Nordmark 1125bd670b35SErik Nordmark if (iraflags & IRAF_LOOPBACK_COPY) { 1126bd670b35SErik Nordmark /* 1127bd670b35SErik Nordmark * IXAF_NO_LOOP_ZONEID is not set hence 6th arg 1128bd670b35SErik Nordmark * is don't care 1129bd670b35SErik Nordmark */ 1130bd670b35SErik Nordmark (void) ip_postfrag_loopcheck(mp, nce, 1131bd670b35SErik Nordmark (IXAF_LOOPBACK_COPY | IXAF_NO_DEV_FLOW_CTL), 1132bd670b35SErik Nordmark pkt_len, ira->ira_xmit_hint, GLOBAL_ZONEID, 0, NULL); 1133bd670b35SErik Nordmark } else { 1134bd670b35SErik Nordmark (void) ip_xmit(mp, nce, IXAF_NO_DEV_FLOW_CTL, 1135bd670b35SErik Nordmark pkt_len, ira->ira_xmit_hint, GLOBAL_ZONEID, 0, NULL); 1136bd670b35SErik Nordmark } 1137bd670b35SErik Nordmark } 1138bd670b35SErik Nordmark 1139bd670b35SErik Nordmark /* 1140bd670b35SErik Nordmark * ire_recvfn for RTF_REJECT and RTF_BLACKHOLE routes, including IRE_NOROUTE, 1141bd670b35SErik Nordmark * which is what ire_route_recursive returns when there is no matching ire. 1142bd670b35SErik Nordmark * Send ICMP unreachable unless blackhole. 1143bd670b35SErik Nordmark */ 1144bd670b35SErik Nordmark void 1145bd670b35SErik Nordmark ire_recv_noroute_v6(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 1146bd670b35SErik Nordmark { 1147bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 1148bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1149bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1150bd670b35SErik Nordmark 1151bd670b35SErik Nordmark /* Would we have forwarded this packet if we had a route? */ 1152bd670b35SErik Nordmark if (ira->ira_flags & (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) { 1153bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 1154bd670b35SErik Nordmark ip_drop_input("l2 multicast not forwarded", mp, ill); 1155bd670b35SErik Nordmark freemsg(mp); 1156bd670b35SErik Nordmark return; 1157bd670b35SErik Nordmark } 1158bd670b35SErik Nordmark 1159bd670b35SErik Nordmark if (!(ill->ill_flags & ILLF_ROUTER)) { 1160bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 1161bd670b35SErik Nordmark ip_drop_input("ipIfStatsForwProhibits", mp, ill); 1162bd670b35SErik Nordmark freemsg(mp); 1163bd670b35SErik Nordmark return; 1164bd670b35SErik Nordmark } 1165bd670b35SErik Nordmark /* 1166bd670b35SErik Nordmark * If we had a route this could have been forwarded. Count as such. 1167bd670b35SErik Nordmark * 1168bd670b35SErik Nordmark * ipIfStatsHCInForwDatagrams should only be increment if there 1169bd670b35SErik Nordmark * will be an attempt to forward the packet, which is why we 1170bd670b35SErik Nordmark * increment after the above condition has been checked. 1171bd670b35SErik Nordmark */ 1172bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInForwDatagrams); 1173bd670b35SErik Nordmark 1174bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInNoRoutes); 1175bd670b35SErik Nordmark 1176bd670b35SErik Nordmark ip_rts_change_v6(RTM_MISS, &ip6h->ip6_dst, 0, 0, 0, 0, 0, 0, RTA_DST, 1177bd670b35SErik Nordmark ipst); 1178bd670b35SErik Nordmark 1179bd670b35SErik Nordmark if (ire->ire_flags & RTF_BLACKHOLE) { 1180bd670b35SErik Nordmark ip_drop_input("ipIfStatsInNoRoutes RTF_BLACKHOLE", mp, ill); 1181bd670b35SErik Nordmark freemsg(mp); 1182bd670b35SErik Nordmark } else { 1183bd670b35SErik Nordmark ip_drop_input("ipIfStatsInNoRoutes RTF_REJECT", mp, ill); 1184bd670b35SErik Nordmark 1185bd670b35SErik Nordmark icmp_unreachable_v6(mp, ICMP6_DST_UNREACH_NOROUTE, B_FALSE, 1186bd670b35SErik Nordmark ira); 1187bd670b35SErik Nordmark } 1188bd670b35SErik Nordmark } 1189bd670b35SErik Nordmark 1190bd670b35SErik Nordmark /* 1191bd670b35SErik Nordmark * ire_recvfn for IRE_LOCALs marked with ire_noaccept. Such IREs are used for 1192bd670b35SErik Nordmark * VRRP when in noaccept mode. 1193bd670b35SErik Nordmark * We silently drop packets except for Neighbor Solicitations and 1194bd670b35SErik Nordmark * Neighbor Advertisements. 1195bd670b35SErik Nordmark */ 1196bd670b35SErik Nordmark void 1197bd670b35SErik Nordmark ire_recv_noaccept_v6(ire_t *ire, mblk_t *mp, void *iph_arg, 1198bd670b35SErik Nordmark ip_recv_attr_t *ira) 1199bd670b35SErik Nordmark { 1200bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 1201bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1202bd670b35SErik Nordmark icmp6_t *icmp6; 1203bd670b35SErik Nordmark int ip_hdr_length; 1204bd670b35SErik Nordmark 1205bd670b35SErik Nordmark if (ip6h->ip6_nxt != IPPROTO_ICMPV6) { 1206bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 1207bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards - noaccept", mp, ill); 1208bd670b35SErik Nordmark freemsg(mp); 1209bd670b35SErik Nordmark return; 1210bd670b35SErik Nordmark } 1211bd670b35SErik Nordmark ip_hdr_length = ira->ira_ip_hdr_length; 1212bd670b35SErik Nordmark if ((mp->b_wptr - mp->b_rptr) < (ip_hdr_length + ICMP6_MINLEN)) { 1213bd670b35SErik Nordmark if (ira->ira_pktlen < (ip_hdr_length + ICMP6_MINLEN)) { 1214bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts); 1215bd670b35SErik Nordmark ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill); 1216bd670b35SErik Nordmark freemsg(mp); 1217bd670b35SErik Nordmark return; 1218bd670b35SErik Nordmark } 1219bd670b35SErik Nordmark ip6h = ip_pullup(mp, ip_hdr_length + ICMP6_MINLEN, ira); 1220bd670b35SErik Nordmark if (ip6h == NULL) { 1221bd670b35SErik Nordmark BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors); 1222bd670b35SErik Nordmark freemsg(mp); 1223bd670b35SErik Nordmark return; 1224bd670b35SErik Nordmark } 1225bd670b35SErik Nordmark } 1226bd670b35SErik Nordmark icmp6 = (icmp6_t *)(&mp->b_rptr[ip_hdr_length]); 1227bd670b35SErik Nordmark 1228bd670b35SErik Nordmark if (icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT && 1229bd670b35SErik Nordmark icmp6->icmp6_type != ND_NEIGHBOR_ADVERT) { 1230bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 1231bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards - noaccept", mp, ill); 1232bd670b35SErik Nordmark freemsg(mp); 1233bd670b35SErik Nordmark return; 1234bd670b35SErik Nordmark } 1235bd670b35SErik Nordmark ire_recv_local_v6(ire, mp, ip6h, ira); 1236bd670b35SErik Nordmark } 1237bd670b35SErik Nordmark 1238bd670b35SErik Nordmark /* 1239bd670b35SErik Nordmark * ire_recvfn for IRE_MULTICAST. 1240bd670b35SErik Nordmark */ 1241bd670b35SErik Nordmark void 1242bd670b35SErik Nordmark ire_recv_multicast_v6(ire_t *ire, mblk_t *mp, void *iph_arg, 1243bd670b35SErik Nordmark ip_recv_attr_t *ira) 1244bd670b35SErik Nordmark { 1245bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 1246bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1247bd670b35SErik Nordmark 1248bd670b35SErik Nordmark ASSERT(ire->ire_ill == ira->ira_ill); 1249bd670b35SErik Nordmark 1250bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInMcastPkts); 1251bd670b35SErik Nordmark UPDATE_MIB(ill->ill_ip_mib, ipIfStatsHCInMcastOctets, ira->ira_pktlen); 1252bd670b35SErik Nordmark 1253bd670b35SErik Nordmark /* Tag for higher-level protocols */ 1254bd670b35SErik Nordmark ira->ira_flags |= IRAF_MULTICAST; 1255bd670b35SErik Nordmark 1256bd670b35SErik Nordmark /* 1257bd670b35SErik Nordmark * So that we don't end up with dups, only one ill an IPMP group is 1258bd670b35SErik Nordmark * nominated to receive multicast traffic. 1259bd670b35SErik Nordmark * If we have no cast_ill we are liberal and accept everything. 1260bd670b35SErik Nordmark */ 1261bd670b35SErik Nordmark if (IS_UNDER_IPMP(ill)) { 1262bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1263bd670b35SErik Nordmark 1264bd670b35SErik Nordmark /* For an under ill_grp can change under lock */ 1265bd670b35SErik Nordmark rw_enter(&ipst->ips_ill_g_lock, RW_READER); 1266bd670b35SErik Nordmark if (!ill->ill_nom_cast && ill->ill_grp != NULL && 1267bd670b35SErik Nordmark ill->ill_grp->ig_cast_ill != NULL) { 1268bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 1269bd670b35SErik Nordmark ip_drop_input("not on cast ill", mp, ill); 1270bd670b35SErik Nordmark freemsg(mp); 1271bd670b35SErik Nordmark return; 1272bd670b35SErik Nordmark } 1273bd670b35SErik Nordmark rw_exit(&ipst->ips_ill_g_lock); 1274bd670b35SErik Nordmark /* 1275bd670b35SErik Nordmark * We switch to the upper ill so that mrouter and hasmembers 1276bd670b35SErik Nordmark * can operate on upper here and in ip_input_multicast. 1277bd670b35SErik Nordmark */ 1278bd670b35SErik Nordmark ill = ipmp_ill_hold_ipmp_ill(ill); 1279bd670b35SErik Nordmark if (ill != NULL) { 1280bd670b35SErik Nordmark ASSERT(ill != ira->ira_ill); 1281bd670b35SErik Nordmark ASSERT(ire->ire_ill == ira->ira_ill); 1282bd670b35SErik Nordmark ira->ira_ill = ill; 1283bd670b35SErik Nordmark ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 1284bd670b35SErik Nordmark } else { 1285bd670b35SErik Nordmark ill = ira->ira_ill; 1286bd670b35SErik Nordmark } 1287bd670b35SErik Nordmark } 1288bd670b35SErik Nordmark 1289bd670b35SErik Nordmark #ifdef notdef 1290bd670b35SErik Nordmark /* 1291bd670b35SErik Nordmark * Check if we are a multicast router - send ip_mforward a copy of 1292bd670b35SErik Nordmark * the packet. 1293bd670b35SErik Nordmark * Due to mroute_decap tunnels we consider forwarding packets even if 1294bd670b35SErik Nordmark * mrouted has not joined the allmulti group on this interface. 1295bd670b35SErik Nordmark */ 1296bd670b35SErik Nordmark if (ipst->ips_ip_g_mrouter) { 1297bd670b35SErik Nordmark int retval; 1298bd670b35SErik Nordmark 1299bd670b35SErik Nordmark /* 1300bd670b35SErik Nordmark * Clear the indication that this may have hardware 1301bd670b35SErik Nordmark * checksum as we are not using it for forwarding. 1302bd670b35SErik Nordmark */ 1303bd670b35SErik Nordmark DB_CKSUMFLAGS(mp) = 0; 1304bd670b35SErik Nordmark 1305bd670b35SErik Nordmark /* 1306bd670b35SErik Nordmark * ip_mforward helps us make these distinctions: If received 1307bd670b35SErik Nordmark * on tunnel and not IGMP, then drop. 1308bd670b35SErik Nordmark * If IGMP packet, then don't check membership 1309bd670b35SErik Nordmark * If received on a phyint and IGMP or PIM, then 1310bd670b35SErik Nordmark * don't check membership 1311bd670b35SErik Nordmark */ 1312bd670b35SErik Nordmark retval = ip_mforward_v6(mp, ira); 1313bd670b35SErik Nordmark /* ip_mforward updates mib variables if needed */ 1314bd670b35SErik Nordmark 1315bd670b35SErik Nordmark switch (retval) { 1316bd670b35SErik Nordmark case 0: 1317bd670b35SErik Nordmark /* 1318bd670b35SErik Nordmark * pkt is okay and arrived on phyint. 1319bd670b35SErik Nordmark */ 1320bd670b35SErik Nordmark break; 1321bd670b35SErik Nordmark case -1: 1322bd670b35SErik Nordmark /* pkt is mal-formed, toss it */ 1323bd670b35SErik Nordmark freemsg(mp); 1324bd670b35SErik Nordmark goto done; 1325bd670b35SErik Nordmark case 1: 1326bd670b35SErik Nordmark /* 1327bd670b35SErik Nordmark * pkt is okay and arrived on a tunnel 1328bd670b35SErik Nordmark * 1329bd670b35SErik Nordmark * If we are running a multicast router 1330bd670b35SErik Nordmark * we need to see all mld packets, which 1331bd670b35SErik Nordmark * are marked with router alerts. 1332bd670b35SErik Nordmark */ 1333bd670b35SErik Nordmark if (ira->ira_flags & IRAF_ROUTER_ALERT) 1334bd670b35SErik Nordmark goto forus; 1335bd670b35SErik Nordmark ip_drop_input("Multicast on tunnel ignored", mp, ill); 1336bd670b35SErik Nordmark freemsg(mp); 1337bd670b35SErik Nordmark goto done; 1338bd670b35SErik Nordmark } 1339bd670b35SErik Nordmark } 1340bd670b35SErik Nordmark #endif /* notdef */ 1341bd670b35SErik Nordmark 1342bd670b35SErik Nordmark /* 1343bd670b35SErik Nordmark * If this was a router alert we skip the group membership check. 1344bd670b35SErik Nordmark */ 1345bd670b35SErik Nordmark if (ira->ira_flags & IRAF_ROUTER_ALERT) 1346bd670b35SErik Nordmark goto forus; 1347bd670b35SErik Nordmark 1348bd670b35SErik Nordmark /* 1349bd670b35SErik Nordmark * Check if we have members on this ill. This is not necessary for 1350bd670b35SErik Nordmark * correctness because even if the NIC/GLD had a leaky filter, we 1351bd670b35SErik Nordmark * filter before passing to each conn_t. 1352bd670b35SErik Nordmark */ 1353bd670b35SErik Nordmark if (!ill_hasmembers_v6(ill, &ip6h->ip6_dst)) { 1354bd670b35SErik Nordmark /* 1355bd670b35SErik Nordmark * Nobody interested 1356bd670b35SErik Nordmark * 1357bd670b35SErik Nordmark * This might just be caused by the fact that 1358bd670b35SErik Nordmark * multiple IP Multicast addresses map to the same 1359bd670b35SErik Nordmark * link layer multicast - no need to increment counter! 1360bd670b35SErik Nordmark */ 1361bd670b35SErik Nordmark ip_drop_input("Multicast with no members", mp, ill); 1362bd670b35SErik Nordmark freemsg(mp); 1363bd670b35SErik Nordmark goto done; 1364bd670b35SErik Nordmark } 1365bd670b35SErik Nordmark forus: 1366bd670b35SErik Nordmark ip2dbg(("ire_recv_multicast_v6: multicast for us\n")); 1367bd670b35SErik Nordmark 1368bd670b35SErik Nordmark /* 1369bd670b35SErik Nordmark * After reassembly and IPsec we will need to duplicate the 1370bd670b35SErik Nordmark * multicast packet for all matching zones on the ill. 1371bd670b35SErik Nordmark */ 1372bd670b35SErik Nordmark ira->ira_zoneid = ALL_ZONES; 1373bd670b35SErik Nordmark 1374bd670b35SErik Nordmark /* Reassemble on the ill on which the packet arrived */ 1375bd670b35SErik Nordmark ip_input_local_v6(ire, mp, ip6h, ira); 1376bd670b35SErik Nordmark done: 1377bd670b35SErik Nordmark if (ill != ire->ire_ill) { 1378bd670b35SErik Nordmark ill_refrele(ill); 1379bd670b35SErik Nordmark ira->ira_ill = ire->ire_ill; 1380bd670b35SErik Nordmark ira->ira_ruifindex = ira->ira_ill->ill_phyint->phyint_ifindex; 1381bd670b35SErik Nordmark } 1382bd670b35SErik Nordmark } 1383bd670b35SErik Nordmark 1384bd670b35SErik Nordmark /* 1385bd670b35SErik Nordmark * ire_recvfn for IRE_OFFLINK with RTF_MULTIRT. 1386bd670b35SErik Nordmark * Drop packets since we don't forward out multirt routes. 1387bd670b35SErik Nordmark */ 1388bd670b35SErik Nordmark /* ARGSUSED */ 1389bd670b35SErik Nordmark void 1390bd670b35SErik Nordmark ire_recv_multirt_v6(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 1391bd670b35SErik Nordmark { 1392bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1393bd670b35SErik Nordmark 1394bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInNoRoutes); 1395bd670b35SErik Nordmark ip_drop_input("Not forwarding out MULTIRT", mp, ill); 1396bd670b35SErik Nordmark freemsg(mp); 1397bd670b35SErik Nordmark } 1398bd670b35SErik Nordmark 1399bd670b35SErik Nordmark /* 1400bd670b35SErik Nordmark * ire_recvfn for IRE_LOOPBACK. This is only used when a FW_HOOK 1401bd670b35SErik Nordmark * has rewritten the packet to have a loopback destination address (We 1402bd670b35SErik Nordmark * filter out packet with a loopback destination from arriving over the wire). 1403bd670b35SErik Nordmark * We don't know what zone to use, thus we always use the GLOBAL_ZONEID. 1404bd670b35SErik Nordmark */ 1405bd670b35SErik Nordmark void 1406bd670b35SErik Nordmark ire_recv_loopback_v6(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 1407bd670b35SErik Nordmark { 1408bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 1409bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1410bd670b35SErik Nordmark ill_t *ire_ill = ire->ire_ill; 1411bd670b35SErik Nordmark 1412bd670b35SErik Nordmark ira->ira_zoneid = GLOBAL_ZONEID; 1413bd670b35SErik Nordmark 1414bd670b35SErik Nordmark /* Switch to the lo0 ill for further processing */ 1415bd670b35SErik Nordmark if (ire_ill != ill) { 1416bd670b35SErik Nordmark /* 1417bd670b35SErik Nordmark * Update ira_ill to be the ILL on which the IP address 1418bd670b35SErik Nordmark * is hosted. 1419bd670b35SErik Nordmark * No need to hold the ill since we have a hold on the ire 1420bd670b35SErik Nordmark */ 1421bd670b35SErik Nordmark ASSERT(ira->ira_ill == ira->ira_rill); 1422bd670b35SErik Nordmark ira->ira_ill = ire_ill; 1423bd670b35SErik Nordmark 1424bd670b35SErik Nordmark ip_input_local_v6(ire, mp, ip6h, ira); 1425bd670b35SErik Nordmark 1426bd670b35SErik Nordmark /* Restore */ 1427bd670b35SErik Nordmark ASSERT(ira->ira_ill == ire_ill); 1428bd670b35SErik Nordmark ira->ira_ill = ill; 1429bd670b35SErik Nordmark return; 1430bd670b35SErik Nordmark 1431bd670b35SErik Nordmark } 1432bd670b35SErik Nordmark ip_input_local_v6(ire, mp, ip6h, ira); 1433bd670b35SErik Nordmark } 1434bd670b35SErik Nordmark 1435bd670b35SErik Nordmark /* 1436bd670b35SErik Nordmark * ire_recvfn for IRE_LOCAL. 1437bd670b35SErik Nordmark */ 1438bd670b35SErik Nordmark void 1439bd670b35SErik Nordmark ire_recv_local_v6(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 1440bd670b35SErik Nordmark { 1441bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)iph_arg; 1442bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1443bd670b35SErik Nordmark ill_t *ire_ill = ire->ire_ill; 1444bd670b35SErik Nordmark 1445bd670b35SErik Nordmark /* Make a note for DAD that this address is in use */ 1446b36a561eSErik Nordmark ire->ire_last_used_time = LBOLT_FASTPATH; 1447bd670b35SErik Nordmark 1448bd670b35SErik Nordmark /* Only target the IRE_LOCAL with the right zoneid. */ 1449bd670b35SErik Nordmark ira->ira_zoneid = ire->ire_zoneid; 1450bd670b35SErik Nordmark 1451bd670b35SErik Nordmark /* 1452bd670b35SErik Nordmark * If the packet arrived on the wrong ill, we check that 1453bd670b35SErik Nordmark * this is ok. 1454bd670b35SErik Nordmark * If it is, then we ensure that we do the reassembly on 1455bd670b35SErik Nordmark * the ill on which the address is hosted. We keep ira_rill as 1456bd670b35SErik Nordmark * the one on which the packet arrived, so that IP_PKTINFO and 1457bd670b35SErik Nordmark * friends can report this. 1458bd670b35SErik Nordmark */ 1459bd670b35SErik Nordmark if (ire_ill != ill) { 1460bd670b35SErik Nordmark ire_t *new_ire; 1461bd670b35SErik Nordmark 1462bd670b35SErik Nordmark new_ire = ip_check_multihome(&ip6h->ip6_dst, ire, ill); 1463bd670b35SErik Nordmark if (new_ire == NULL) { 1464bd670b35SErik Nordmark /* Drop packet */ 1465bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 1466bd670b35SErik Nordmark ip_drop_input("ipIfStatsInForwProhibits", mp, ill); 1467bd670b35SErik Nordmark freemsg(mp); 1468bd670b35SErik Nordmark return; 1469bd670b35SErik Nordmark } 1470bd670b35SErik Nordmark /* 1471bd670b35SErik Nordmark * Update ira_ill to be the ILL on which the IP address 1472bd670b35SErik Nordmark * is hosted. No need to hold the ill since we have a 1473bd670b35SErik Nordmark * hold on the ire. Note that we do the switch even if 1474bd670b35SErik Nordmark * new_ire == ire (for IPMP, ire would be the one corresponding 1475bd670b35SErik Nordmark * to the IPMP ill). 1476bd670b35SErik Nordmark */ 1477bd670b35SErik Nordmark ASSERT(ira->ira_ill == ira->ira_rill); 1478bd670b35SErik Nordmark ira->ira_ill = new_ire->ire_ill; 1479bd670b35SErik Nordmark 1480bd670b35SErik Nordmark /* ira_ruifindex tracks the upper for ira_rill */ 1481bd670b35SErik Nordmark if (IS_UNDER_IPMP(ill)) 1482bd670b35SErik Nordmark ira->ira_ruifindex = ill_get_upper_ifindex(ill); 1483bd670b35SErik Nordmark 1484bd670b35SErik Nordmark ip_input_local_v6(new_ire, mp, ip6h, ira); 1485bd670b35SErik Nordmark 1486bd670b35SErik Nordmark /* Restore */ 1487bd670b35SErik Nordmark ASSERT(ira->ira_ill == new_ire->ire_ill); 1488bd670b35SErik Nordmark ira->ira_ill = ill; 1489bd670b35SErik Nordmark ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 1490bd670b35SErik Nordmark 1491bd670b35SErik Nordmark if (new_ire != ire) 1492bd670b35SErik Nordmark ire_refrele(new_ire); 1493bd670b35SErik Nordmark return; 1494bd670b35SErik Nordmark } 1495bd670b35SErik Nordmark 1496bd670b35SErik Nordmark ip_input_local_v6(ire, mp, ip6h, ira); 1497bd670b35SErik Nordmark } 1498bd670b35SErik Nordmark 1499bd670b35SErik Nordmark /* 1500bd670b35SErik Nordmark * Common function for packets arriving for the host. Handles 1501bd670b35SErik Nordmark * checksum verification, reassembly checks, etc. 1502bd670b35SErik Nordmark */ 1503bd670b35SErik Nordmark static void 1504bd670b35SErik Nordmark ip_input_local_v6(ire_t *ire, mblk_t *mp, ip6_t *ip6h, ip_recv_attr_t *ira) 1505bd670b35SErik Nordmark { 1506bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 1507bd670b35SErik Nordmark 1508bd670b35SErik Nordmark /* 1509bd670b35SErik Nordmark * For multicast we need some extra work before 1510bd670b35SErik Nordmark * we call ip_fanout_v6(), since in the case of shared-IP zones 1511bd670b35SErik Nordmark * we need to pretend that a packet arrived for each zoneid. 1512bd670b35SErik Nordmark */ 1513bd670b35SErik Nordmark if (iraflags & IRAF_MULTICAST) { 1514bd670b35SErik Nordmark ip_input_multicast_v6(ire, mp, ip6h, ira); 1515bd670b35SErik Nordmark return; 1516bd670b35SErik Nordmark } 1517bd670b35SErik Nordmark ip_fanout_v6(mp, ip6h, ira); 1518bd670b35SErik Nordmark } 1519bd670b35SErik Nordmark 1520bd670b35SErik Nordmark /* 1521bd670b35SErik Nordmark * Handle multiple zones which want to receive the same multicast packets 1522bd670b35SErik Nordmark * on this ill by delivering a packet to each of them. 1523bd670b35SErik Nordmark * 1524bd670b35SErik Nordmark * Note that for packets delivered to transports we could instead do this 1525bd670b35SErik Nordmark * as part of the fanout code, but since we need to handle icmp_inbound 1526bd670b35SErik Nordmark * it is simpler to have multicast work the same as IPv4 broadcast. 1527bd670b35SErik Nordmark * 1528bd670b35SErik Nordmark * The ip_fanout matching for multicast matches based on ilm independent of 1529bd670b35SErik Nordmark * zoneid since the zoneid restriction is applied when joining a multicast 1530bd670b35SErik Nordmark * group. 1531bd670b35SErik Nordmark */ 1532bd670b35SErik Nordmark /* ARGSUSED */ 1533bd670b35SErik Nordmark static void 1534bd670b35SErik Nordmark ip_input_multicast_v6(ire_t *ire, mblk_t *mp, ip6_t *ip6h, ip_recv_attr_t *ira) 1535bd670b35SErik Nordmark { 1536bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1537bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 1538bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1539bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack; 1540bd670b35SErik Nordmark zoneid_t zoneid; 1541bd670b35SErik Nordmark mblk_t *mp1; 1542bd670b35SErik Nordmark ip6_t *ip6h1; 154344b099c4SSowmini Varadhan uint_t ira_pktlen = ira->ira_pktlen; 154444b099c4SSowmini Varadhan uint16_t ira_ip_hdr_length = ira->ira_ip_hdr_length; 1545bd670b35SErik Nordmark 1546bd670b35SErik Nordmark /* ire_recv_multicast has switched to the upper ill for IPMP */ 1547bd670b35SErik Nordmark ASSERT(!IS_UNDER_IPMP(ill)); 1548bd670b35SErik Nordmark 1549bd670b35SErik Nordmark /* 1550bd670b35SErik Nordmark * If we don't have more than one shared-IP zone, or if 1551bd670b35SErik Nordmark * there are no members in anything but the global zone, 1552bd670b35SErik Nordmark * then just set the zoneid and proceed. 1553bd670b35SErik Nordmark */ 1554bd670b35SErik Nordmark if (ns->netstack_numzones == 1 || 1555bd670b35SErik Nordmark !ill_hasmembers_otherzones_v6(ill, &ip6h->ip6_dst, 1556bd670b35SErik Nordmark GLOBAL_ZONEID)) { 1557bd670b35SErik Nordmark ira->ira_zoneid = GLOBAL_ZONEID; 1558bd670b35SErik Nordmark 1559bd670b35SErik Nordmark /* If sender didn't want this zone to receive it, drop */ 1560bd670b35SErik Nordmark if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 1561bd670b35SErik Nordmark ira->ira_no_loop_zoneid == ira->ira_zoneid) { 1562bd670b35SErik Nordmark ip_drop_input("Multicast but wrong zoneid", mp, ill); 1563bd670b35SErik Nordmark freemsg(mp); 1564bd670b35SErik Nordmark return; 1565bd670b35SErik Nordmark } 1566bd670b35SErik Nordmark ip_fanout_v6(mp, ip6h, ira); 1567bd670b35SErik Nordmark return; 1568bd670b35SErik Nordmark } 1569bd670b35SErik Nordmark 1570bd670b35SErik Nordmark /* 1571bd670b35SErik Nordmark * Here we loop over all zoneids that have members in the group 1572bd670b35SErik Nordmark * and deliver a packet to ip_fanout for each zoneid. 1573bd670b35SErik Nordmark * 1574bd670b35SErik Nordmark * First find any members in the lowest numeric zoneid by looking for 1575bd670b35SErik Nordmark * first zoneid larger than -1 (ALL_ZONES). 1576bd670b35SErik Nordmark * We terminate the loop when we receive -1 (ALL_ZONES). 1577bd670b35SErik Nordmark */ 1578bd670b35SErik Nordmark zoneid = ill_hasmembers_nextzone_v6(ill, &ip6h->ip6_dst, ALL_ZONES); 1579bd670b35SErik Nordmark for (; zoneid != ALL_ZONES; 1580bd670b35SErik Nordmark zoneid = ill_hasmembers_nextzone_v6(ill, &ip6h->ip6_dst, zoneid)) { 1581bd670b35SErik Nordmark /* 1582bd670b35SErik Nordmark * Avoid an extra copymsg/freemsg by skipping global zone here 1583bd670b35SErik Nordmark * and doing that at the end. 1584bd670b35SErik Nordmark */ 1585bd670b35SErik Nordmark if (zoneid == GLOBAL_ZONEID) 1586bd670b35SErik Nordmark continue; 1587bd670b35SErik Nordmark 1588bd670b35SErik Nordmark ira->ira_zoneid = zoneid; 1589bd670b35SErik Nordmark 1590bd670b35SErik Nordmark /* If sender didn't want this zone to receive it, skip */ 1591bd670b35SErik Nordmark if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 1592bd670b35SErik Nordmark ira->ira_no_loop_zoneid == ira->ira_zoneid) 1593bd670b35SErik Nordmark continue; 1594bd670b35SErik Nordmark 1595bd670b35SErik Nordmark mp1 = copymsg(mp); 1596bd670b35SErik Nordmark if (mp1 == NULL) { 1597bd670b35SErik Nordmark /* Failed to deliver to one zone */ 1598bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 1599bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 1600bd670b35SErik Nordmark continue; 1601bd670b35SErik Nordmark } 1602bd670b35SErik Nordmark ip6h1 = (ip6_t *)mp1->b_rptr; 1603bd670b35SErik Nordmark ip_fanout_v6(mp1, ip6h1, ira); 160444b099c4SSowmini Varadhan /* 160544b099c4SSowmini Varadhan * IPsec might have modified ira_pktlen and ira_ip_hdr_length 160644b099c4SSowmini Varadhan * so we restore them for a potential next iteration 160744b099c4SSowmini Varadhan */ 160844b099c4SSowmini Varadhan ira->ira_pktlen = ira_pktlen; 160944b099c4SSowmini Varadhan ira->ira_ip_hdr_length = ira_ip_hdr_length; 1610bd670b35SErik Nordmark } 1611bd670b35SErik Nordmark 1612bd670b35SErik Nordmark /* Do the main ire */ 1613bd670b35SErik Nordmark ira->ira_zoneid = GLOBAL_ZONEID; 1614bd670b35SErik Nordmark /* If sender didn't want this zone to receive it, drop */ 1615bd670b35SErik Nordmark if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 1616bd670b35SErik Nordmark ira->ira_no_loop_zoneid == ira->ira_zoneid) { 1617bd670b35SErik Nordmark ip_drop_input("Multicast but wrong zoneid", mp, ill); 1618bd670b35SErik Nordmark freemsg(mp); 1619bd670b35SErik Nordmark } else { 1620bd670b35SErik Nordmark ip_fanout_v6(mp, ip6h, ira); 1621bd670b35SErik Nordmark } 1622bd670b35SErik Nordmark } 1623bd670b35SErik Nordmark 1624bd670b35SErik Nordmark 1625bd670b35SErik Nordmark /* 1626bd670b35SErik Nordmark * Determine the zoneid and IRAF_TX_MAC_EXEMPTABLE if trusted extensions 1627bd670b35SErik Nordmark * is in use. Updates ira_zoneid and ira_flags as a result. 1628bd670b35SErik Nordmark */ 1629bd670b35SErik Nordmark static void 1630bd670b35SErik Nordmark ip_fanout_tx_v6(mblk_t *mp, ip6_t *ip6h, uint8_t protocol, uint_t ip_hdr_length, 1631bd670b35SErik Nordmark ip_recv_attr_t *ira) 1632bd670b35SErik Nordmark { 1633bd670b35SErik Nordmark uint16_t *up; 1634bd670b35SErik Nordmark uint16_t lport; 1635bd670b35SErik Nordmark zoneid_t zoneid; 1636bd670b35SErik Nordmark 1637bd670b35SErik Nordmark ASSERT(ira->ira_flags & IRAF_SYSTEM_LABELED); 1638bd670b35SErik Nordmark 1639bd670b35SErik Nordmark /* 1640bd670b35SErik Nordmark * If the packet is unlabeled we might allow read-down 1641bd670b35SErik Nordmark * for MAC_EXEMPT. Below we clear this if it is a multi-level 1642bd670b35SErik Nordmark * port (MLP). 1643bd670b35SErik Nordmark * Note that ira_tsl can be NULL here. 1644bd670b35SErik Nordmark */ 1645bd670b35SErik Nordmark if (ira->ira_tsl != NULL && ira->ira_tsl->tsl_flags & TSLF_UNLABELED) 1646bd670b35SErik Nordmark ira->ira_flags |= IRAF_TX_MAC_EXEMPTABLE; 1647bd670b35SErik Nordmark 1648bd670b35SErik Nordmark if (ira->ira_zoneid != ALL_ZONES) 1649bd670b35SErik Nordmark return; 1650bd670b35SErik Nordmark 1651bd670b35SErik Nordmark ira->ira_flags |= IRAF_TX_SHARED_ADDR; 1652bd670b35SErik Nordmark 1653bd670b35SErik Nordmark up = (uint16_t *)((uchar_t *)ip6h + ip_hdr_length); 1654bd670b35SErik Nordmark switch (protocol) { 1655bd670b35SErik Nordmark case IPPROTO_TCP: 1656bd670b35SErik Nordmark case IPPROTO_SCTP: 1657bd670b35SErik Nordmark case IPPROTO_UDP: 1658bd670b35SErik Nordmark /* Caller ensures this */ 1659bd670b35SErik Nordmark ASSERT(((uchar_t *)ip6h) + ip_hdr_length +4 <= mp->b_wptr); 1660bd670b35SErik Nordmark 1661bd670b35SErik Nordmark /* 1662bd670b35SErik Nordmark * Only these transports support MLP. 1663bd670b35SErik Nordmark * We know their destination port numbers is in 1664bd670b35SErik Nordmark * the same place in the header. 1665bd670b35SErik Nordmark */ 1666bd670b35SErik Nordmark lport = up[1]; 1667bd670b35SErik Nordmark 1668bd670b35SErik Nordmark /* 1669bd670b35SErik Nordmark * No need to handle exclusive-stack zones 1670bd670b35SErik Nordmark * since ALL_ZONES only applies to the shared IP instance. 1671bd670b35SErik Nordmark */ 1672bd670b35SErik Nordmark zoneid = tsol_mlp_findzone(protocol, lport); 1673bd670b35SErik Nordmark /* 1674bd670b35SErik Nordmark * If no shared MLP is found, tsol_mlp_findzone returns 1675bd670b35SErik Nordmark * ALL_ZONES. In that case, we assume it's SLP, and 1676bd670b35SErik Nordmark * search for the zone based on the packet label. 1677bd670b35SErik Nordmark * 1678bd670b35SErik Nordmark * If there is such a zone, we prefer to find a 1679bd670b35SErik Nordmark * connection in it. Otherwise, we look for a 1680bd670b35SErik Nordmark * MAC-exempt connection in any zone whose label 1681bd670b35SErik Nordmark * dominates the default label on the packet. 1682bd670b35SErik Nordmark */ 1683bd670b35SErik Nordmark if (zoneid == ALL_ZONES) 1684bd670b35SErik Nordmark zoneid = tsol_attr_to_zoneid(ira); 1685bd670b35SErik Nordmark else 1686bd670b35SErik Nordmark ira->ira_flags &= ~IRAF_TX_MAC_EXEMPTABLE; 1687bd670b35SErik Nordmark break; 1688bd670b35SErik Nordmark default: 1689bd670b35SErik Nordmark /* Handle shared address for other protocols */ 1690bd670b35SErik Nordmark zoneid = tsol_attr_to_zoneid(ira); 1691bd670b35SErik Nordmark break; 1692bd670b35SErik Nordmark } 1693bd670b35SErik Nordmark ira->ira_zoneid = zoneid; 1694bd670b35SErik Nordmark } 1695bd670b35SErik Nordmark 1696bd670b35SErik Nordmark /* 1697bd670b35SErik Nordmark * Increment checksum failure statistics 1698bd670b35SErik Nordmark */ 1699bd670b35SErik Nordmark static void 1700bd670b35SErik Nordmark ip_input_cksum_err_v6(uint8_t protocol, uint16_t hck_flags, ill_t *ill) 1701bd670b35SErik Nordmark { 1702bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1703bd670b35SErik Nordmark 1704bd670b35SErik Nordmark switch (protocol) { 1705bd670b35SErik Nordmark case IPPROTO_TCP: 1706bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, tcpIfStatsInErrs); 1707bd670b35SErik Nordmark 1708bd670b35SErik Nordmark if (hck_flags & HCK_FULLCKSUM) 1709bd670b35SErik Nordmark IP6_STAT(ipst, ip6_tcp_in_full_hw_cksum_err); 1710bd670b35SErik Nordmark else if (hck_flags & HCK_PARTIALCKSUM) 1711bd670b35SErik Nordmark IP6_STAT(ipst, ip6_tcp_in_part_hw_cksum_err); 1712bd670b35SErik Nordmark else 1713bd670b35SErik Nordmark IP6_STAT(ipst, ip6_tcp_in_sw_cksum_err); 1714bd670b35SErik Nordmark break; 1715bd670b35SErik Nordmark case IPPROTO_UDP: 1716bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, udpIfStatsInCksumErrs); 1717bd670b35SErik Nordmark if (hck_flags & HCK_FULLCKSUM) 1718bd670b35SErik Nordmark IP6_STAT(ipst, ip6_udp_in_full_hw_cksum_err); 1719bd670b35SErik Nordmark else if (hck_flags & HCK_PARTIALCKSUM) 1720bd670b35SErik Nordmark IP6_STAT(ipst, ip6_udp_in_part_hw_cksum_err); 1721bd670b35SErik Nordmark else 1722bd670b35SErik Nordmark IP6_STAT(ipst, ip6_udp_in_sw_cksum_err); 1723bd670b35SErik Nordmark break; 1724bd670b35SErik Nordmark case IPPROTO_ICMPV6: 1725bd670b35SErik Nordmark BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInMsgs); 1726bd670b35SErik Nordmark BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInErrors); 1727bd670b35SErik Nordmark break; 1728bd670b35SErik Nordmark default: 1729bd670b35SErik Nordmark ASSERT(0); 1730bd670b35SErik Nordmark break; 1731bd670b35SErik Nordmark } 1732bd670b35SErik Nordmark } 1733bd670b35SErik Nordmark 1734bd670b35SErik Nordmark /* Calculate the IPv6 pseudo-header checksum for TCP, UDP, and ICMPV6 */ 1735bd670b35SErik Nordmark uint32_t 1736bd670b35SErik Nordmark ip_input_cksum_pseudo_v6(ip6_t *ip6h, ip_recv_attr_t *ira) 1737bd670b35SErik Nordmark { 1738bd670b35SErik Nordmark uint_t ulp_len; 1739bd670b35SErik Nordmark uint32_t cksum; 1740bd670b35SErik Nordmark uint8_t protocol = ira->ira_protocol; 1741bd670b35SErik Nordmark uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 1742bd670b35SErik Nordmark 1743bd670b35SErik Nordmark #define iphs ((uint16_t *)ip6h) 1744bd670b35SErik Nordmark 1745bd670b35SErik Nordmark switch (protocol) { 1746bd670b35SErik Nordmark case IPPROTO_TCP: 1747bd670b35SErik Nordmark ulp_len = ira->ira_pktlen - ip_hdr_length; 1748bd670b35SErik Nordmark 1749bd670b35SErik Nordmark /* Protocol and length */ 1750bd670b35SErik Nordmark cksum = htons(ulp_len) + IP_TCP_CSUM_COMP; 1751bd670b35SErik Nordmark /* IP addresses */ 1752bd670b35SErik Nordmark cksum += iphs[4] + iphs[5] + iphs[6] + iphs[7] + 1753bd670b35SErik Nordmark iphs[8] + iphs[9] + iphs[10] + iphs[11] + 1754bd670b35SErik Nordmark iphs[12] + iphs[13] + iphs[14] + iphs[15] + 1755bd670b35SErik Nordmark iphs[16] + iphs[17] + iphs[18] + iphs[19]; 1756bd670b35SErik Nordmark break; 1757bd670b35SErik Nordmark 1758bd670b35SErik Nordmark case IPPROTO_UDP: { 1759bd670b35SErik Nordmark udpha_t *udpha; 1760bd670b35SErik Nordmark 1761bd670b35SErik Nordmark udpha = (udpha_t *)((uchar_t *)ip6h + ip_hdr_length); 1762bd670b35SErik Nordmark 1763bd670b35SErik Nordmark /* Protocol and length */ 1764bd670b35SErik Nordmark cksum = udpha->uha_length + IP_UDP_CSUM_COMP; 1765bd670b35SErik Nordmark /* IP addresses */ 1766bd670b35SErik Nordmark cksum += iphs[4] + iphs[5] + iphs[6] + iphs[7] + 1767bd670b35SErik Nordmark iphs[8] + iphs[9] + iphs[10] + iphs[11] + 1768bd670b35SErik Nordmark iphs[12] + iphs[13] + iphs[14] + iphs[15] + 1769bd670b35SErik Nordmark iphs[16] + iphs[17] + iphs[18] + iphs[19]; 1770bd670b35SErik Nordmark break; 1771bd670b35SErik Nordmark } 1772bd670b35SErik Nordmark case IPPROTO_ICMPV6: 1773bd670b35SErik Nordmark ulp_len = ira->ira_pktlen - ip_hdr_length; 1774bd670b35SErik Nordmark 1775bd670b35SErik Nordmark /* Protocol and length */ 1776bd670b35SErik Nordmark cksum = htons(ulp_len) + IP_ICMPV6_CSUM_COMP; 1777bd670b35SErik Nordmark /* IP addresses */ 1778bd670b35SErik Nordmark cksum += iphs[4] + iphs[5] + iphs[6] + iphs[7] + 1779bd670b35SErik Nordmark iphs[8] + iphs[9] + iphs[10] + iphs[11] + 1780bd670b35SErik Nordmark iphs[12] + iphs[13] + iphs[14] + iphs[15] + 1781bd670b35SErik Nordmark iphs[16] + iphs[17] + iphs[18] + iphs[19]; 1782bd670b35SErik Nordmark break; 1783bd670b35SErik Nordmark default: 1784bd670b35SErik Nordmark cksum = 0; 1785bd670b35SErik Nordmark break; 1786bd670b35SErik Nordmark } 1787bd670b35SErik Nordmark #undef iphs 1788bd670b35SErik Nordmark return (cksum); 1789bd670b35SErik Nordmark } 1790bd670b35SErik Nordmark 1791bd670b35SErik Nordmark 1792bd670b35SErik Nordmark /* 1793bd670b35SErik Nordmark * Software verification of the ULP checksums. 1794bd670b35SErik Nordmark * Returns B_TRUE if ok. 1795bd670b35SErik Nordmark * Increments statistics of failed. 1796bd670b35SErik Nordmark */ 1797bd670b35SErik Nordmark static boolean_t 1798bd670b35SErik Nordmark ip_input_sw_cksum_v6(mblk_t *mp, ip6_t *ip6h, ip_recv_attr_t *ira) 1799bd670b35SErik Nordmark { 1800bd670b35SErik Nordmark ip_stack_t *ipst = ira->ira_ill->ill_ipst; 1801bd670b35SErik Nordmark uint32_t cksum; 1802bd670b35SErik Nordmark uint8_t protocol = ira->ira_protocol; 1803bd670b35SErik Nordmark uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 1804bd670b35SErik Nordmark 1805bd670b35SErik Nordmark IP6_STAT(ipst, ip6_in_sw_cksum); 1806bd670b35SErik Nordmark 1807bd670b35SErik Nordmark ASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || 1808bd670b35SErik Nordmark protocol == IPPROTO_ICMPV6); 1809bd670b35SErik Nordmark 1810bd670b35SErik Nordmark cksum = ip_input_cksum_pseudo_v6(ip6h, ira); 1811bd670b35SErik Nordmark cksum = IP_CSUM(mp, ip_hdr_length, cksum); 1812bd670b35SErik Nordmark if (cksum == 0) 1813bd670b35SErik Nordmark return (B_TRUE); 1814bd670b35SErik Nordmark 1815bd670b35SErik Nordmark ip_input_cksum_err_v6(protocol, 0, ira->ira_ill); 1816bd670b35SErik Nordmark return (B_FALSE); 1817bd670b35SErik Nordmark } 1818bd670b35SErik Nordmark 1819bd670b35SErik Nordmark /* 1820bd670b35SErik Nordmark * Verify the ULP checksums. 1821bd670b35SErik Nordmark * Returns B_TRUE if ok, or if the ULP doesn't have a well-defined checksum 1822bd670b35SErik Nordmark * algorithm. 1823bd670b35SErik Nordmark * Increments statistics if failed. 1824bd670b35SErik Nordmark */ 1825bd670b35SErik Nordmark static boolean_t 1826bd670b35SErik Nordmark ip_input_cksum_v6(iaflags_t iraflags, mblk_t *mp, ip6_t *ip6h, 1827bd670b35SErik Nordmark ip_recv_attr_t *ira) 1828bd670b35SErik Nordmark { 1829bd670b35SErik Nordmark ill_t *ill = ira->ira_rill; 1830bd670b35SErik Nordmark uint16_t hck_flags; 1831bd670b35SErik Nordmark uint32_t cksum; 1832bd670b35SErik Nordmark mblk_t *mp1; 1833bd670b35SErik Nordmark uint_t len; 1834bd670b35SErik Nordmark uint8_t protocol = ira->ira_protocol; 1835bd670b35SErik Nordmark uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 1836bd670b35SErik Nordmark 1837bd670b35SErik Nordmark 1838bd670b35SErik Nordmark switch (protocol) { 1839bd670b35SErik Nordmark case IPPROTO_TCP: 1840bd670b35SErik Nordmark case IPPROTO_ICMPV6: 1841bd670b35SErik Nordmark break; 1842bd670b35SErik Nordmark 1843bd670b35SErik Nordmark case IPPROTO_UDP: { 1844bd670b35SErik Nordmark udpha_t *udpha; 1845bd670b35SErik Nordmark 1846bd670b35SErik Nordmark udpha = (udpha_t *)((uchar_t *)ip6h + ip_hdr_length); 1847bd670b35SErik Nordmark /* 1848bd670b35SErik Nordmark * Before going through the regular checksum 1849bd670b35SErik Nordmark * calculation, make sure the received checksum 1850bd670b35SErik Nordmark * is non-zero. RFC 2460 says, a 0x0000 checksum 1851bd670b35SErik Nordmark * in a UDP packet (within IPv6 packet) is invalid 1852bd670b35SErik Nordmark * and should be replaced by 0xffff. This makes 1853bd670b35SErik Nordmark * sense as regular checksum calculation will 1854bd670b35SErik Nordmark * pass for both the cases i.e. 0x0000 and 0xffff. 1855bd670b35SErik Nordmark * Removing one of the case makes error detection 1856bd670b35SErik Nordmark * stronger. 1857bd670b35SErik Nordmark */ 1858bd670b35SErik Nordmark if (udpha->uha_checksum == 0) { 1859bd670b35SErik Nordmark /* 0x0000 checksum is invalid */ 1860bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, udpIfStatsInCksumErrs); 1861bd670b35SErik Nordmark return (B_FALSE); 1862bd670b35SErik Nordmark } 1863bd670b35SErik Nordmark break; 1864bd670b35SErik Nordmark } 1865bd670b35SErik Nordmark case IPPROTO_SCTP: { 1866bd670b35SErik Nordmark sctp_hdr_t *sctph; 1867bd670b35SErik Nordmark uint32_t pktsum; 1868bd670b35SErik Nordmark 1869bd670b35SErik Nordmark sctph = (sctp_hdr_t *)((uchar_t *)ip6h + ip_hdr_length); 1870bd670b35SErik Nordmark #ifdef DEBUG 1871bd670b35SErik Nordmark if (skip_sctp_cksum) 1872bd670b35SErik Nordmark return (B_TRUE); 1873bd670b35SErik Nordmark #endif 1874bd670b35SErik Nordmark pktsum = sctph->sh_chksum; 1875bd670b35SErik Nordmark sctph->sh_chksum = 0; 1876bd670b35SErik Nordmark cksum = sctp_cksum(mp, ip_hdr_length); 1877bd670b35SErik Nordmark sctph->sh_chksum = pktsum; 1878bd670b35SErik Nordmark if (cksum == pktsum) 1879bd670b35SErik Nordmark return (B_TRUE); 1880bd670b35SErik Nordmark 1881bd670b35SErik Nordmark /* 1882bd670b35SErik Nordmark * Defer until later whether a bad checksum is ok 1883bd670b35SErik Nordmark * in order to allow RAW sockets to use Adler checksum 1884bd670b35SErik Nordmark * with SCTP. 1885bd670b35SErik Nordmark */ 1886bd670b35SErik Nordmark ira->ira_flags |= IRAF_SCTP_CSUM_ERR; 1887bd670b35SErik Nordmark return (B_TRUE); 1888bd670b35SErik Nordmark } 1889bd670b35SErik Nordmark 1890bd670b35SErik Nordmark default: 1891bd670b35SErik Nordmark /* No ULP checksum to verify. */ 1892bd670b35SErik Nordmark return (B_TRUE); 1893bd670b35SErik Nordmark } 1894bd670b35SErik Nordmark 1895bd670b35SErik Nordmark /* 1896bd670b35SErik Nordmark * Revert to software checksum calculation if the interface 1897bd670b35SErik Nordmark * isn't capable of checksum offload. 1898bd670b35SErik Nordmark * We clear DB_CKSUMFLAGS when going through IPsec in ip_fanout. 1899bd670b35SErik Nordmark * Note: IRAF_NO_HW_CKSUM is not currently used. 1900bd670b35SErik Nordmark */ 1901bd670b35SErik Nordmark ASSERT(!IS_IPMP(ill)); 1902bd670b35SErik Nordmark if ((iraflags & IRAF_NO_HW_CKSUM) || !ILL_HCKSUM_CAPABLE(ill) || 1903bd670b35SErik Nordmark !dohwcksum) { 1904bd670b35SErik Nordmark return (ip_input_sw_cksum_v6(mp, ip6h, ira)); 1905bd670b35SErik Nordmark } 1906bd670b35SErik Nordmark 1907bd670b35SErik Nordmark /* 1908bd670b35SErik Nordmark * We apply this for all ULP protocols. Does the HW know to 1909bd670b35SErik Nordmark * not set the flags for SCTP and other protocols. 1910bd670b35SErik Nordmark */ 1911bd670b35SErik Nordmark 1912bd670b35SErik Nordmark hck_flags = DB_CKSUMFLAGS(mp); 1913bd670b35SErik Nordmark 19140dc2366fSVenugopal Iyer if (hck_flags & HCK_FULLCKSUM_OK) { 19150dc2366fSVenugopal Iyer /* 19160dc2366fSVenugopal Iyer * Hardware has already verified the checksum. 19170dc2366fSVenugopal Iyer */ 19180dc2366fSVenugopal Iyer return (B_TRUE); 19190dc2366fSVenugopal Iyer } 19200dc2366fSVenugopal Iyer 1921bd670b35SErik Nordmark if (hck_flags & HCK_FULLCKSUM) { 1922bd670b35SErik Nordmark /* 1923bd670b35SErik Nordmark * Full checksum has been computed by the hardware 1924bd670b35SErik Nordmark * and has been attached. If the driver wants us to 1925bd670b35SErik Nordmark * verify the correctness of the attached value, in 1926bd670b35SErik Nordmark * order to protect against faulty hardware, compare 1927bd670b35SErik Nordmark * it against -0 (0xFFFF) to see if it's valid. 1928bd670b35SErik Nordmark */ 1929bd670b35SErik Nordmark cksum = DB_CKSUM16(mp); 1930bd670b35SErik Nordmark if (cksum == 0xFFFF) 1931bd670b35SErik Nordmark return (B_TRUE); 1932bd670b35SErik Nordmark ip_input_cksum_err_v6(protocol, hck_flags, ira->ira_ill); 1933bd670b35SErik Nordmark return (B_FALSE); 1934bd670b35SErik Nordmark } 1935bd670b35SErik Nordmark 1936bd670b35SErik Nordmark mp1 = mp->b_cont; 1937bd670b35SErik Nordmark if ((hck_flags & HCK_PARTIALCKSUM) && 1938bd670b35SErik Nordmark (mp1 == NULL || mp1->b_cont == NULL) && 1939bd670b35SErik Nordmark ip_hdr_length >= DB_CKSUMSTART(mp) && 1940bd670b35SErik Nordmark ((len = ip_hdr_length - DB_CKSUMSTART(mp)) & 1) == 0) { 1941bd670b35SErik Nordmark uint32_t adj; 1942bd670b35SErik Nordmark uchar_t *cksum_start; 1943bd670b35SErik Nordmark 1944bd670b35SErik Nordmark cksum = ip_input_cksum_pseudo_v6(ip6h, ira); 1945bd670b35SErik Nordmark 1946bd670b35SErik Nordmark cksum_start = ((uchar_t *)ip6h + DB_CKSUMSTART(mp)); 1947bd670b35SErik Nordmark 1948bd670b35SErik Nordmark /* 1949bd670b35SErik Nordmark * Partial checksum has been calculated by hardware 1950bd670b35SErik Nordmark * and attached to the packet; in addition, any 1951bd670b35SErik Nordmark * prepended extraneous data is even byte aligned, 1952bd670b35SErik Nordmark * and there are at most two mblks associated with 1953bd670b35SErik Nordmark * the packet. If any such data exists, we adjust 1954bd670b35SErik Nordmark * the checksum; also take care any postpended data. 1955bd670b35SErik Nordmark */ 1956bd670b35SErik Nordmark IP_ADJCKSUM_PARTIAL(cksum_start, mp, mp1, len, adj); 1957bd670b35SErik Nordmark /* 1958bd670b35SErik Nordmark * One's complement subtract extraneous checksum 1959bd670b35SErik Nordmark */ 1960bd670b35SErik Nordmark cksum += DB_CKSUM16(mp); 1961bd670b35SErik Nordmark if (adj >= cksum) 1962bd670b35SErik Nordmark cksum = ~(adj - cksum) & 0xFFFF; 1963bd670b35SErik Nordmark else 1964bd670b35SErik Nordmark cksum -= adj; 1965bd670b35SErik Nordmark cksum = (cksum & 0xFFFF) + ((int)cksum >> 16); 1966bd670b35SErik Nordmark cksum = (cksum & 0xFFFF) + ((int)cksum >> 16); 1967bd670b35SErik Nordmark if (!(~cksum & 0xFFFF)) 1968bd670b35SErik Nordmark return (B_TRUE); 1969bd670b35SErik Nordmark 1970bd670b35SErik Nordmark ip_input_cksum_err_v6(protocol, hck_flags, ira->ira_ill); 1971bd670b35SErik Nordmark return (B_FALSE); 1972bd670b35SErik Nordmark } 1973bd670b35SErik Nordmark return (ip_input_sw_cksum_v6(mp, ip6h, ira)); 1974bd670b35SErik Nordmark } 1975bd670b35SErik Nordmark 1976bd670b35SErik Nordmark 1977bd670b35SErik Nordmark /* 1978bd670b35SErik Nordmark * Handle fanout of received packets. 1979bd670b35SErik Nordmark * Unicast packets that are looped back (from ire_send_local_v6) and packets 1980bd670b35SErik Nordmark * from the wire are differentiated by checking IRAF_VERIFY_ULP_CKSUM. 1981bd670b35SErik Nordmark * 1982bd670b35SErik Nordmark * IPQoS Notes 1983bd670b35SErik Nordmark * Before sending it to the client, invoke IPPF processing. Policy processing 1984bd670b35SErik Nordmark * takes place only if the callout_position, IPP_LOCAL_IN, is enabled. 1985bd670b35SErik Nordmark */ 1986bd670b35SErik Nordmark void 1987bd670b35SErik Nordmark ip_fanout_v6(mblk_t *mp, ip6_t *ip6h, ip_recv_attr_t *ira) 1988bd670b35SErik Nordmark { 1989bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 1990bd670b35SErik Nordmark iaflags_t iraflags = ira->ira_flags; 1991bd670b35SErik Nordmark ip_stack_t *ipst = ill->ill_ipst; 1992bd670b35SErik Nordmark uint8_t protocol; 1993bd670b35SErik Nordmark conn_t *connp; 1994bd670b35SErik Nordmark #define rptr ((uchar_t *)ip6h) 1995bd670b35SErik Nordmark uint_t ip_hdr_length; 1996bd670b35SErik Nordmark uint_t min_ulp_header_length; 1997bd670b35SErik Nordmark int offset; 1998bd670b35SErik Nordmark ssize_t len; 1999bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack; 2000bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 2001bd670b35SErik Nordmark ill_t *rill = ira->ira_rill; 2002bd670b35SErik Nordmark 2003bd670b35SErik Nordmark ASSERT(ira->ira_pktlen == ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN); 2004bd670b35SErik Nordmark 2005bd670b35SErik Nordmark /* 2006bd670b35SErik Nordmark * We repeat this as we parse over destination options header and 2007bd670b35SErik Nordmark * fragment headers (earlier we've handled any hop-by-hop options 2008bd670b35SErik Nordmark * header.) 2009bd670b35SErik Nordmark * We update ira_protocol and ira_ip_hdr_length as we skip past 2010bd670b35SErik Nordmark * the intermediate headers; they already point past any 2011bd670b35SErik Nordmark * hop-by-hop header. 2012bd670b35SErik Nordmark */ 2013bd670b35SErik Nordmark repeat: 2014bd670b35SErik Nordmark protocol = ira->ira_protocol; 2015bd670b35SErik Nordmark ip_hdr_length = ira->ira_ip_hdr_length; 2016bd670b35SErik Nordmark 2017bd670b35SErik Nordmark /* 2018bd670b35SErik Nordmark * Time for IPP once we've done reassembly and IPsec. 2019bd670b35SErik Nordmark * We skip this for loopback packets since we don't do IPQoS 2020bd670b35SErik Nordmark * on loopback. 2021bd670b35SErik Nordmark */ 2022bd670b35SErik Nordmark if (IPP_ENABLED(IPP_LOCAL_IN, ipst) && 2023bd670b35SErik Nordmark !(iraflags & IRAF_LOOPBACK) && 2024bd670b35SErik Nordmark (protocol != IPPROTO_ESP || protocol != IPPROTO_AH || 2025bd670b35SErik Nordmark protocol != IPPROTO_DSTOPTS || protocol != IPPROTO_ROUTING || 2026bd670b35SErik Nordmark protocol != IPPROTO_FRAGMENT)) { 2027bd670b35SErik Nordmark /* 2028bd670b35SErik Nordmark * Use the interface on which the packet arrived - not where 2029bd670b35SErik Nordmark * the IP address is hosted. 2030bd670b35SErik Nordmark */ 2031bd670b35SErik Nordmark /* ip_process translates an IS_UNDER_IPMP */ 2032bd670b35SErik Nordmark mp = ip_process(IPP_LOCAL_IN, mp, rill, ill); 2033bd670b35SErik Nordmark if (mp == NULL) { 2034bd670b35SErik Nordmark /* ip_drop_packet and MIB done */ 2035bd670b35SErik Nordmark return; 2036bd670b35SErik Nordmark } 2037bd670b35SErik Nordmark } 2038bd670b35SErik Nordmark 2039bd670b35SErik Nordmark /* Determine the minimum required size of the upper-layer header */ 2040bd670b35SErik Nordmark /* Need to do this for at least the set of ULPs that TX handles. */ 2041bd670b35SErik Nordmark switch (protocol) { 2042bd670b35SErik Nordmark case IPPROTO_TCP: 2043bd670b35SErik Nordmark min_ulp_header_length = TCP_MIN_HEADER_LENGTH; 2044bd670b35SErik Nordmark break; 2045bd670b35SErik Nordmark case IPPROTO_SCTP: 2046bd670b35SErik Nordmark min_ulp_header_length = SCTP_COMMON_HDR_LENGTH; 2047bd670b35SErik Nordmark break; 2048bd670b35SErik Nordmark case IPPROTO_UDP: 2049bd670b35SErik Nordmark min_ulp_header_length = UDPH_SIZE; 2050bd670b35SErik Nordmark break; 2051bd670b35SErik Nordmark case IPPROTO_ICMP: 2052bd670b35SErik Nordmark case IPPROTO_ICMPV6: 2053bd670b35SErik Nordmark min_ulp_header_length = ICMPH_SIZE; 2054bd670b35SErik Nordmark break; 2055bd670b35SErik Nordmark case IPPROTO_FRAGMENT: 2056bd670b35SErik Nordmark case IPPROTO_DSTOPTS: 2057bd670b35SErik Nordmark case IPPROTO_ROUTING: 2058bd670b35SErik Nordmark min_ulp_header_length = MIN_EHDR_LEN; 2059bd670b35SErik Nordmark break; 2060bd670b35SErik Nordmark default: 2061bd670b35SErik Nordmark min_ulp_header_length = 0; 2062bd670b35SErik Nordmark break; 2063bd670b35SErik Nordmark } 2064bd670b35SErik Nordmark /* Make sure we have the min ULP header length */ 2065bd670b35SErik Nordmark len = mp->b_wptr - rptr; 2066bd670b35SErik Nordmark if (len < ip_hdr_length + min_ulp_header_length) { 2067bd670b35SErik Nordmark if (ira->ira_pktlen < ip_hdr_length + min_ulp_header_length) 2068bd670b35SErik Nordmark goto pkt_too_short; 2069bd670b35SErik Nordmark 2070bd670b35SErik Nordmark IP6_STAT(ipst, ip6_recv_pullup); 2071bd670b35SErik Nordmark ip6h = ip_pullup(mp, ip_hdr_length + min_ulp_header_length, 2072bd670b35SErik Nordmark ira); 2073bd670b35SErik Nordmark if (ip6h == NULL) 2074bd670b35SErik Nordmark goto discard; 2075bd670b35SErik Nordmark len = mp->b_wptr - rptr; 2076bd670b35SErik Nordmark } 2077bd670b35SErik Nordmark 2078bd670b35SErik Nordmark /* 2079bd670b35SErik Nordmark * If trusted extensions then determine the zoneid and TX specific 2080bd670b35SErik Nordmark * ira_flags. 2081bd670b35SErik Nordmark */ 2082bd670b35SErik Nordmark if (iraflags & IRAF_SYSTEM_LABELED) { 2083bd670b35SErik Nordmark /* This can update ira->ira_flags and ira->ira_zoneid */ 2084bd670b35SErik Nordmark ip_fanout_tx_v6(mp, ip6h, protocol, ip_hdr_length, ira); 2085bd670b35SErik Nordmark iraflags = ira->ira_flags; 2086bd670b35SErik Nordmark } 2087bd670b35SErik Nordmark 2088bd670b35SErik Nordmark 2089bd670b35SErik Nordmark /* Verify ULP checksum. Handles TCP, UDP, and SCTP */ 2090bd670b35SErik Nordmark if (iraflags & IRAF_VERIFY_ULP_CKSUM) { 2091bd670b35SErik Nordmark if (!ip_input_cksum_v6(iraflags, mp, ip6h, ira)) { 2092bd670b35SErik Nordmark /* Bad checksum. Stats are already incremented */ 2093bd670b35SErik Nordmark ip_drop_input("Bad ULP checksum", mp, ill); 2094bd670b35SErik Nordmark freemsg(mp); 2095bd670b35SErik Nordmark return; 2096bd670b35SErik Nordmark } 2097bd670b35SErik Nordmark /* IRAF_SCTP_CSUM_ERR could have been set */ 2098bd670b35SErik Nordmark iraflags = ira->ira_flags; 2099bd670b35SErik Nordmark } 2100bd670b35SErik Nordmark switch (protocol) { 2101bd670b35SErik Nordmark case IPPROTO_TCP: 2102bd670b35SErik Nordmark /* For TCP, discard multicast packets. */ 2103bd670b35SErik Nordmark if (iraflags & IRAF_MULTIBROADCAST) 2104bd670b35SErik Nordmark goto discard; 2105bd670b35SErik Nordmark 2106bd670b35SErik Nordmark /* First mblk contains IP+TCP headers per above check */ 2107bd670b35SErik Nordmark ASSERT(len >= ip_hdr_length + TCP_MIN_HEADER_LENGTH); 2108bd670b35SErik Nordmark 2109bd670b35SErik Nordmark /* TCP options present? */ 2110bd670b35SErik Nordmark offset = ((uchar_t *)ip6h)[ip_hdr_length + 12] >> 4; 2111bd670b35SErik Nordmark if (offset != 5) { 2112bd670b35SErik Nordmark if (offset < 5) 2113bd670b35SErik Nordmark goto discard; 2114bd670b35SErik Nordmark 2115bd670b35SErik Nordmark /* 2116bd670b35SErik Nordmark * There must be TCP options. 2117bd670b35SErik Nordmark * Make sure we can grab them. 2118bd670b35SErik Nordmark */ 2119bd670b35SErik Nordmark offset <<= 2; 2120bd670b35SErik Nordmark offset += ip_hdr_length; 2121bd670b35SErik Nordmark if (len < offset) { 2122bd670b35SErik Nordmark if (ira->ira_pktlen < offset) 2123bd670b35SErik Nordmark goto pkt_too_short; 2124bd670b35SErik Nordmark 2125bd670b35SErik Nordmark IP6_STAT(ipst, ip6_recv_pullup); 2126bd670b35SErik Nordmark ip6h = ip_pullup(mp, offset, ira); 2127bd670b35SErik Nordmark if (ip6h == NULL) 2128bd670b35SErik Nordmark goto discard; 2129bd670b35SErik Nordmark len = mp->b_wptr - rptr; 2130bd670b35SErik Nordmark } 2131bd670b35SErik Nordmark } 2132bd670b35SErik Nordmark 2133bd670b35SErik Nordmark /* 2134bd670b35SErik Nordmark * Pass up a squeue hint to tcp. 2135bd670b35SErik Nordmark * If ira_sqp is already set (this is loopback) we leave it 2136bd670b35SErik Nordmark * alone. 2137bd670b35SErik Nordmark */ 2138bd670b35SErik Nordmark if (ira->ira_sqp == NULL) { 2139bd670b35SErik Nordmark ira->ira_sqp = ip_squeue_get(ira->ira_ring); 2140bd670b35SErik Nordmark } 2141bd670b35SErik Nordmark 2142bd670b35SErik Nordmark /* Look for AF_INET or AF_INET6 that matches */ 2143bd670b35SErik Nordmark connp = ipcl_classify_v6(mp, IPPROTO_TCP, ip_hdr_length, 2144bd670b35SErik Nordmark ira, ipst); 2145bd670b35SErik Nordmark if (connp == NULL) { 2146bd670b35SErik Nordmark /* Send the TH_RST */ 2147bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2148bd670b35SErik Nordmark tcp_xmit_listeners_reset(mp, ira, ipst, NULL); 2149bd670b35SErik Nordmark return; 2150bd670b35SErik Nordmark } 2151bd670b35SErik Nordmark if (connp->conn_incoming_ifindex != 0 && 2152bd670b35SErik Nordmark connp->conn_incoming_ifindex != ira->ira_ruifindex) { 2153bd670b35SErik Nordmark CONN_DEC_REF(connp); 2154bd670b35SErik Nordmark 2155bd670b35SErik Nordmark /* Send the TH_RST */ 2156bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2157bd670b35SErik Nordmark tcp_xmit_listeners_reset(mp, ira, ipst, NULL); 2158bd670b35SErik Nordmark return; 2159bd670b35SErik Nordmark } 2160bd670b35SErik Nordmark if (CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss) || 2161bd670b35SErik Nordmark (iraflags & IRAF_IPSEC_SECURE)) { 2162bd670b35SErik Nordmark mp = ipsec_check_inbound_policy(mp, connp, 2163bd670b35SErik Nordmark NULL, ip6h, ira); 2164bd670b35SErik Nordmark if (mp == NULL) { 2165bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 2166bd670b35SErik Nordmark /* Note that mp is NULL */ 2167bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 2168bd670b35SErik Nordmark CONN_DEC_REF(connp); 2169bd670b35SErik Nordmark return; 2170bd670b35SErik Nordmark } 2171bd670b35SErik Nordmark } 2172bd670b35SErik Nordmark /* Found a client; up it goes */ 2173bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2174bd670b35SErik Nordmark ira->ira_ill = ira->ira_rill = NULL; 2175bd670b35SErik Nordmark if (!IPCL_IS_TCP(connp)) { 2176bd670b35SErik Nordmark /* Not TCP; must be SOCK_RAW, IPPROTO_TCP */ 2177bd670b35SErik Nordmark (connp->conn_recv)(connp, mp, NULL, ira); 2178bd670b35SErik Nordmark CONN_DEC_REF(connp); 2179bd670b35SErik Nordmark ira->ira_ill = ill; 2180bd670b35SErik Nordmark ira->ira_rill = rill; 2181bd670b35SErik Nordmark return; 2182bd670b35SErik Nordmark } 2183bd670b35SErik Nordmark 2184bd670b35SErik Nordmark /* 2185bd670b35SErik Nordmark * We do different processing whether called from 2186bd670b35SErik Nordmark * ip_accept_tcp and we match the target, don't match 2187bd670b35SErik Nordmark * the target, and when we are called by ip_input. 2188bd670b35SErik Nordmark */ 2189bd670b35SErik Nordmark if (iraflags & IRAF_TARGET_SQP) { 2190bd670b35SErik Nordmark if (ira->ira_target_sqp == connp->conn_sqp) { 2191bd670b35SErik Nordmark mblk_t *attrmp; 2192bd670b35SErik Nordmark 2193bd670b35SErik Nordmark attrmp = ip_recv_attr_to_mblk(ira); 2194bd670b35SErik Nordmark if (attrmp == NULL) { 2195bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, 2196bd670b35SErik Nordmark ipIfStatsInDiscards); 2197bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", 2198bd670b35SErik Nordmark mp, ill); 2199bd670b35SErik Nordmark freemsg(mp); 2200bd670b35SErik Nordmark CONN_DEC_REF(connp); 2201bd670b35SErik Nordmark } else { 2202bd670b35SErik Nordmark SET_SQUEUE(attrmp, connp->conn_recv, 2203bd670b35SErik Nordmark connp); 2204bd670b35SErik Nordmark attrmp->b_cont = mp; 2205bd670b35SErik Nordmark ASSERT(ira->ira_target_sqp_mp == NULL); 2206bd670b35SErik Nordmark ira->ira_target_sqp_mp = attrmp; 2207bd670b35SErik Nordmark /* 2208bd670b35SErik Nordmark * Conn ref release when drained from 2209bd670b35SErik Nordmark * the squeue. 2210bd670b35SErik Nordmark */ 2211bd670b35SErik Nordmark } 2212bd670b35SErik Nordmark } else { 2213bd670b35SErik Nordmark SQUEUE_ENTER_ONE(connp->conn_sqp, mp, 2214bd670b35SErik Nordmark connp->conn_recv, connp, ira, SQ_FILL, 2215bd670b35SErik Nordmark SQTAG_IP6_TCP_INPUT); 2216bd670b35SErik Nordmark } 2217bd670b35SErik Nordmark } else { 2218bd670b35SErik Nordmark SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, 2219bd670b35SErik Nordmark connp, ira, ip_squeue_flag, SQTAG_IP6_TCP_INPUT); 2220bd670b35SErik Nordmark } 2221bd670b35SErik Nordmark ira->ira_ill = ill; 2222bd670b35SErik Nordmark ira->ira_rill = rill; 2223bd670b35SErik Nordmark return; 2224bd670b35SErik Nordmark 2225bd670b35SErik Nordmark case IPPROTO_SCTP: { 2226bd670b35SErik Nordmark sctp_hdr_t *sctph; 2227bd670b35SErik Nordmark uint32_t ports; /* Source and destination ports */ 2228bd670b35SErik Nordmark sctp_stack_t *sctps = ipst->ips_netstack->netstack_sctp; 2229bd670b35SErik Nordmark 2230bd670b35SErik Nordmark /* For SCTP, discard multicast packets. */ 2231bd670b35SErik Nordmark if (iraflags & IRAF_MULTIBROADCAST) 2232bd670b35SErik Nordmark goto discard; 2233bd670b35SErik Nordmark 2234bd670b35SErik Nordmark /* 2235bd670b35SErik Nordmark * Since there is no SCTP h/w cksum support yet, just 2236bd670b35SErik Nordmark * clear the flag. 2237bd670b35SErik Nordmark */ 2238bd670b35SErik Nordmark DB_CKSUMFLAGS(mp) = 0; 2239bd670b35SErik Nordmark 2240bd670b35SErik Nordmark /* Length ensured above */ 2241bd670b35SErik Nordmark ASSERT(MBLKL(mp) >= ip_hdr_length + SCTP_COMMON_HDR_LENGTH); 2242bd670b35SErik Nordmark sctph = (sctp_hdr_t *)(rptr + ip_hdr_length); 2243bd670b35SErik Nordmark 2244bd670b35SErik Nordmark /* get the ports */ 2245bd670b35SErik Nordmark ports = *(uint32_t *)&sctph->sh_sport; 2246bd670b35SErik Nordmark 2247bd670b35SErik Nordmark if (iraflags & IRAF_SCTP_CSUM_ERR) { 2248bd670b35SErik Nordmark /* 2249bd670b35SErik Nordmark * No potential sctp checksum errors go to the Sun 2250bd670b35SErik Nordmark * sctp stack however they might be Adler-32 summed 2251bd670b35SErik Nordmark * packets a userland stack bound to a raw IP socket 2252bd670b35SErik Nordmark * could reasonably use. Note though that Adler-32 is 2253bd670b35SErik Nordmark * a long deprecated algorithm and customer sctp 2254bd670b35SErik Nordmark * networks should eventually migrate to CRC-32 at 2255bd670b35SErik Nordmark * which time this facility should be removed. 2256bd670b35SErik Nordmark */ 2257bd670b35SErik Nordmark ip_fanout_sctp_raw(mp, NULL, ip6h, ports, ira); 2258bd670b35SErik Nordmark return; 2259bd670b35SErik Nordmark } 2260bd670b35SErik Nordmark connp = sctp_fanout(&ip6h->ip6_src, &ip6h->ip6_dst, ports, 2261a5407c02SAnil udupa ira, mp, sctps, sctph); 2262bd670b35SErik Nordmark if (connp == NULL) { 2263bd670b35SErik Nordmark /* Check for raw socket or OOTB handling */ 2264bd670b35SErik Nordmark ip_fanout_sctp_raw(mp, NULL, ip6h, ports, ira); 2265bd670b35SErik Nordmark return; 2266bd670b35SErik Nordmark } 2267bd670b35SErik Nordmark if (connp->conn_incoming_ifindex != 0 && 2268bd670b35SErik Nordmark connp->conn_incoming_ifindex != ira->ira_ruifindex) { 2269bd670b35SErik Nordmark CONN_DEC_REF(connp); 2270bd670b35SErik Nordmark 2271bd670b35SErik Nordmark /* Check for raw socket or OOTB handling */ 2272bd670b35SErik Nordmark ip_fanout_sctp_raw(mp, NULL, ip6h, ports, ira); 2273bd670b35SErik Nordmark return; 2274bd670b35SErik Nordmark } 2275bd670b35SErik Nordmark 2276bd670b35SErik Nordmark /* Found a client; up it goes */ 2277bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2278bd670b35SErik Nordmark sctp_input(connp, NULL, ip6h, mp, ira); 2279bd670b35SErik Nordmark /* sctp_input does a rele of the sctp_t */ 2280bd670b35SErik Nordmark return; 2281bd670b35SErik Nordmark } 2282bd670b35SErik Nordmark 2283bd670b35SErik Nordmark case IPPROTO_UDP: 2284bd670b35SErik Nordmark /* First mblk contains IP+UDP headers as checked above */ 2285bd670b35SErik Nordmark ASSERT(MBLKL(mp) >= ip_hdr_length + UDPH_SIZE); 2286bd670b35SErik Nordmark 2287bd670b35SErik Nordmark if (iraflags & IRAF_MULTIBROADCAST) { 2288bd670b35SErik Nordmark uint16_t *up; /* Pointer to ports in ULP header */ 2289bd670b35SErik Nordmark 2290bd670b35SErik Nordmark up = (uint16_t *)((uchar_t *)ip6h + ip_hdr_length); 2291bd670b35SErik Nordmark 2292bd670b35SErik Nordmark ip_fanout_udp_multi_v6(mp, ip6h, up[1], up[0], ira); 2293bd670b35SErik Nordmark return; 2294bd670b35SErik Nordmark } 2295bd670b35SErik Nordmark 2296bd670b35SErik Nordmark /* Look for AF_INET or AF_INET6 that matches */ 2297bd670b35SErik Nordmark connp = ipcl_classify_v6(mp, IPPROTO_UDP, ip_hdr_length, 2298bd670b35SErik Nordmark ira, ipst); 2299bd670b35SErik Nordmark if (connp == NULL) { 2300bd670b35SErik Nordmark no_udp_match: 2301bd670b35SErik Nordmark if (ipst->ips_ipcl_proto_fanout_v6[IPPROTO_UDP]. 2302bd670b35SErik Nordmark connf_head != NULL) { 2303bd670b35SErik Nordmark ASSERT(ira->ira_protocol == IPPROTO_UDP); 2304bd670b35SErik Nordmark ip_fanout_proto_v6(mp, ip6h, ira); 2305bd670b35SErik Nordmark } else { 2306bd670b35SErik Nordmark ip_fanout_send_icmp_v6(mp, ICMP6_DST_UNREACH, 2307bd670b35SErik Nordmark ICMP6_DST_UNREACH_NOPORT, ira); 2308bd670b35SErik Nordmark } 2309bd670b35SErik Nordmark return; 2310bd670b35SErik Nordmark 2311bd670b35SErik Nordmark } 2312bd670b35SErik Nordmark if (connp->conn_incoming_ifindex != 0 && 2313bd670b35SErik Nordmark connp->conn_incoming_ifindex != ira->ira_ruifindex) { 2314bd670b35SErik Nordmark CONN_DEC_REF(connp); 2315bd670b35SErik Nordmark goto no_udp_match; 2316bd670b35SErik Nordmark } 2317bd670b35SErik Nordmark if (IPCL_IS_NONSTR(connp) ? connp->conn_flow_cntrld : 2318bd670b35SErik Nordmark !canputnext(connp->conn_rq)) { 2319bd670b35SErik Nordmark CONN_DEC_REF(connp); 2320bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, udpIfStatsInOverflows); 2321bd670b35SErik Nordmark ip_drop_input("udpIfStatsInOverflows", mp, ill); 2322bd670b35SErik Nordmark freemsg(mp); 2323bd670b35SErik Nordmark return; 2324bd670b35SErik Nordmark } 2325bd670b35SErik Nordmark if (CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss) || 2326bd670b35SErik Nordmark (iraflags & IRAF_IPSEC_SECURE)) { 2327bd670b35SErik Nordmark mp = ipsec_check_inbound_policy(mp, connp, 2328bd670b35SErik Nordmark NULL, ip6h, ira); 2329bd670b35SErik Nordmark if (mp == NULL) { 2330bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 2331bd670b35SErik Nordmark /* Note that mp is NULL */ 2332bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 2333bd670b35SErik Nordmark CONN_DEC_REF(connp); 2334bd670b35SErik Nordmark return; 2335bd670b35SErik Nordmark } 2336bd670b35SErik Nordmark } 2337bd670b35SErik Nordmark 2338bd670b35SErik Nordmark /* Found a client; up it goes */ 2339bd670b35SErik Nordmark IP6_STAT(ipst, ip6_udp_fannorm); 2340bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2341bd670b35SErik Nordmark ira->ira_ill = ira->ira_rill = NULL; 2342bd670b35SErik Nordmark (connp->conn_recv)(connp, mp, NULL, ira); 2343bd670b35SErik Nordmark CONN_DEC_REF(connp); 2344bd670b35SErik Nordmark ira->ira_ill = ill; 2345bd670b35SErik Nordmark ira->ira_rill = rill; 2346bd670b35SErik Nordmark return; 2347bd670b35SErik Nordmark default: 2348bd670b35SErik Nordmark break; 2349bd670b35SErik Nordmark } 2350bd670b35SErik Nordmark 2351bd670b35SErik Nordmark /* 2352bd670b35SErik Nordmark * Clear hardware checksumming flag as it is currently only 2353bd670b35SErik Nordmark * used by TCP and UDP. 2354bd670b35SErik Nordmark */ 2355bd670b35SErik Nordmark DB_CKSUMFLAGS(mp) = 0; 2356bd670b35SErik Nordmark 2357bd670b35SErik Nordmark switch (protocol) { 2358bd670b35SErik Nordmark case IPPROTO_ICMPV6: 2359bd670b35SErik Nordmark BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInMsgs); 2360bd670b35SErik Nordmark 2361bd670b35SErik Nordmark /* Check variable for testing applications */ 2362bd670b35SErik Nordmark if (ipst->ips_ipv6_drop_inbound_icmpv6) { 2363bd670b35SErik Nordmark ip_drop_input("ipv6_drop_inbound_icmpv6", mp, ill); 2364bd670b35SErik Nordmark freemsg(mp); 2365bd670b35SErik Nordmark return; 2366bd670b35SErik Nordmark } 2367bd670b35SErik Nordmark /* 2368bd670b35SErik Nordmark * We need to accomodate icmp messages coming in clear 2369bd670b35SErik Nordmark * until we get everything secure from the wire. If 2370bd670b35SErik Nordmark * icmp_accept_clear_messages is zero we check with 2371bd670b35SErik Nordmark * the global policy and act accordingly. If it is 2372bd670b35SErik Nordmark * non-zero, we accept the message without any checks. 2373bd670b35SErik Nordmark * But *this does not mean* that this will be delivered 2374bd670b35SErik Nordmark * to RAW socket clients. By accepting we might send 2375bd670b35SErik Nordmark * replies back, change our MTU value etc., 2376bd670b35SErik Nordmark * but delivery to the ULP/clients depends on their 2377bd670b35SErik Nordmark * policy dispositions. 2378bd670b35SErik Nordmark */ 2379bd670b35SErik Nordmark if (ipst->ips_icmp_accept_clear_messages == 0) { 2380bd670b35SErik Nordmark mp = ipsec_check_global_policy(mp, NULL, 2381bd670b35SErik Nordmark NULL, ip6h, ira, ns); 2382bd670b35SErik Nordmark if (mp == NULL) 2383bd670b35SErik Nordmark return; 2384bd670b35SErik Nordmark } 2385bd670b35SErik Nordmark 2386bd670b35SErik Nordmark /* 2387bd670b35SErik Nordmark * On a labeled system, we have to check whether the zone 2388bd670b35SErik Nordmark * itself is permitted to receive raw traffic. 2389bd670b35SErik Nordmark */ 2390bd670b35SErik Nordmark if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 2391bd670b35SErik Nordmark if (!tsol_can_accept_raw(mp, ira, B_FALSE)) { 2392bd670b35SErik Nordmark BUMP_MIB(ill->ill_icmp6_mib, 2393bd670b35SErik Nordmark ipv6IfIcmpInErrors); 2394bd670b35SErik Nordmark ip_drop_input("tsol_can_accept_raw", mp, ill); 2395bd670b35SErik Nordmark freemsg(mp); 2396bd670b35SErik Nordmark return; 2397bd670b35SErik Nordmark } 2398bd670b35SErik Nordmark } 2399bd670b35SErik Nordmark 2400bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2401bd670b35SErik Nordmark mp = icmp_inbound_v6(mp, ira); 2402bd670b35SErik Nordmark if (mp == NULL) { 2403bd670b35SErik Nordmark /* No need to pass to RAW sockets */ 2404bd670b35SErik Nordmark return; 2405bd670b35SErik Nordmark } 2406bd670b35SErik Nordmark break; 2407bd670b35SErik Nordmark 2408bd670b35SErik Nordmark case IPPROTO_DSTOPTS: { 2409bd670b35SErik Nordmark ip6_dest_t *desthdr; 2410bd670b35SErik Nordmark uint_t ehdrlen; 2411bd670b35SErik Nordmark uint8_t *optptr; 2412bd670b35SErik Nordmark 2413bd670b35SErik Nordmark /* We already check for MIN_EHDR_LEN above */ 2414bd670b35SErik Nordmark 2415bd670b35SErik Nordmark /* Check if AH is present and needs to be processed. */ 2416bd670b35SErik Nordmark mp = ipsec_early_ah_v6(mp, ira); 2417bd670b35SErik Nordmark if (mp == NULL) 2418bd670b35SErik Nordmark return; 2419bd670b35SErik Nordmark 2420bd670b35SErik Nordmark /* 2421bd670b35SErik Nordmark * Reinitialize pointers, as ipsec_early_ah_v6() does 2422bd670b35SErik Nordmark * complete pullups. We don't have to do more pullups 2423bd670b35SErik Nordmark * as a result. 2424bd670b35SErik Nordmark */ 2425bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 2426bd670b35SErik Nordmark 2427bd670b35SErik Nordmark if (ira->ira_pktlen - ip_hdr_length < MIN_EHDR_LEN) 2428bd670b35SErik Nordmark goto pkt_too_short; 2429bd670b35SErik Nordmark 2430bd670b35SErik Nordmark if (mp->b_cont != NULL && 2431bd670b35SErik Nordmark rptr + ip_hdr_length + MIN_EHDR_LEN > mp->b_wptr) { 2432bd670b35SErik Nordmark ip6h = ip_pullup(mp, ip_hdr_length + MIN_EHDR_LEN, ira); 2433bd670b35SErik Nordmark if (ip6h == NULL) 2434bd670b35SErik Nordmark goto discard; 2435bd670b35SErik Nordmark } 2436bd670b35SErik Nordmark desthdr = (ip6_dest_t *)(rptr + ip_hdr_length); 2437bd670b35SErik Nordmark ehdrlen = 8 * (desthdr->ip6d_len + 1); 2438bd670b35SErik Nordmark if (ira->ira_pktlen - ip_hdr_length < ehdrlen) 2439bd670b35SErik Nordmark goto pkt_too_short; 2440bd670b35SErik Nordmark if (mp->b_cont != NULL && 2441bd670b35SErik Nordmark rptr + IPV6_HDR_LEN + ehdrlen > mp->b_wptr) { 2442bd670b35SErik Nordmark ip6h = ip_pullup(mp, IPV6_HDR_LEN + ehdrlen, ira); 2443bd670b35SErik Nordmark if (ip6h == NULL) 2444bd670b35SErik Nordmark goto discard; 2445bd670b35SErik Nordmark 2446bd670b35SErik Nordmark desthdr = (ip6_dest_t *)(rptr + ip_hdr_length); 2447bd670b35SErik Nordmark } 2448bd670b35SErik Nordmark optptr = (uint8_t *)&desthdr[1]; 2449bd670b35SErik Nordmark 2450bd670b35SErik Nordmark /* 2451bd670b35SErik Nordmark * Update ira_ip_hdr_length to skip the destination header 2452bd670b35SErik Nordmark * when we repeat. 2453bd670b35SErik Nordmark */ 2454bd670b35SErik Nordmark ira->ira_ip_hdr_length += ehdrlen; 2455bd670b35SErik Nordmark 2456bd670b35SErik Nordmark ira->ira_protocol = desthdr->ip6d_nxt; 2457bd670b35SErik Nordmark 2458bd670b35SErik Nordmark /* 2459bd670b35SErik Nordmark * Note: XXX This code does not seem to make 2460bd670b35SErik Nordmark * distinction between Destination Options Header 2461bd670b35SErik Nordmark * being before/after Routing Header which can 2462bd670b35SErik Nordmark * happen if we are at the end of source route. 2463bd670b35SErik Nordmark * This may become significant in future. 2464bd670b35SErik Nordmark * (No real significant Destination Options are 2465bd670b35SErik Nordmark * defined/implemented yet ). 2466bd670b35SErik Nordmark */ 2467bd670b35SErik Nordmark switch (ip_process_options_v6(mp, ip6h, optptr, 2468bd670b35SErik Nordmark ehdrlen - 2, IPPROTO_DSTOPTS, ira)) { 2469bd670b35SErik Nordmark case -1: 2470bd670b35SErik Nordmark /* 2471bd670b35SErik Nordmark * Packet has been consumed and any needed 2472bd670b35SErik Nordmark * ICMP errors sent. 2473bd670b35SErik Nordmark */ 2474bd670b35SErik Nordmark return; 2475bd670b35SErik Nordmark case 0: 2476bd670b35SErik Nordmark /* No action needed continue */ 2477bd670b35SErik Nordmark break; 2478bd670b35SErik Nordmark case 1: 2479bd670b35SErik Nordmark /* 2480bd670b35SErik Nordmark * Unnexpected return value 2481bd670b35SErik Nordmark * (Router alert is a Hop-by-Hop option) 2482bd670b35SErik Nordmark */ 2483bd670b35SErik Nordmark #ifdef DEBUG 2484bd670b35SErik Nordmark panic("ip_fanout_v6: router " 2485bd670b35SErik Nordmark "alert hbh opt indication in dest opt"); 2486bd670b35SErik Nordmark /*NOTREACHED*/ 2487bd670b35SErik Nordmark #else 2488bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 2489bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 2490bd670b35SErik Nordmark freemsg(mp); 2491bd670b35SErik Nordmark return; 2492bd670b35SErik Nordmark #endif 2493bd670b35SErik Nordmark } 2494bd670b35SErik Nordmark goto repeat; 2495bd670b35SErik Nordmark } 2496bd670b35SErik Nordmark case IPPROTO_FRAGMENT: { 2497bd670b35SErik Nordmark ip6_frag_t *fraghdr; 2498bd670b35SErik Nordmark 2499bd670b35SErik Nordmark if (ira->ira_pktlen - ip_hdr_length < sizeof (ip6_frag_t)) 2500bd670b35SErik Nordmark goto pkt_too_short; 2501bd670b35SErik Nordmark 2502bd670b35SErik Nordmark if (mp->b_cont != NULL && 2503bd670b35SErik Nordmark rptr + ip_hdr_length + sizeof (ip6_frag_t) > mp->b_wptr) { 2504bd670b35SErik Nordmark ip6h = ip_pullup(mp, 2505bd670b35SErik Nordmark ip_hdr_length + sizeof (ip6_frag_t), ira); 2506bd670b35SErik Nordmark if (ip6h == NULL) 2507bd670b35SErik Nordmark goto discard; 2508bd670b35SErik Nordmark } 2509bd670b35SErik Nordmark 2510bd670b35SErik Nordmark fraghdr = (ip6_frag_t *)(rptr + ip_hdr_length); 2511bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsReasmReqds); 2512bd670b35SErik Nordmark 2513bd670b35SErik Nordmark /* 2514bd670b35SErik Nordmark * Invoke the CGTP (multirouting) filtering module to 2515bd670b35SErik Nordmark * process the incoming packet. Packets identified as 2516bd670b35SErik Nordmark * duplicates must be discarded. Filtering is active 2517bd670b35SErik Nordmark * only if the ip_cgtp_filter ndd variable is 2518bd670b35SErik Nordmark * non-zero. 2519bd670b35SErik Nordmark */ 2520bd670b35SErik Nordmark if (ipst->ips_ip_cgtp_filter && 2521bd670b35SErik Nordmark ipst->ips_ip_cgtp_filter_ops != NULL) { 2522bd670b35SErik Nordmark int cgtp_flt_pkt; 2523bd670b35SErik Nordmark netstackid_t stackid; 2524bd670b35SErik Nordmark 2525bd670b35SErik Nordmark stackid = ipst->ips_netstack->netstack_stackid; 2526bd670b35SErik Nordmark 2527bd670b35SErik Nordmark /* 2528bd670b35SErik Nordmark * CGTP and IPMP are mutually exclusive so 2529bd670b35SErik Nordmark * phyint_ifindex is fine here. 2530bd670b35SErik Nordmark */ 2531bd670b35SErik Nordmark cgtp_flt_pkt = 2532bd670b35SErik Nordmark ipst->ips_ip_cgtp_filter_ops->cfo_filter_v6( 2533bd670b35SErik Nordmark stackid, ill->ill_phyint->phyint_ifindex, 2534bd670b35SErik Nordmark ip6h, fraghdr); 2535bd670b35SErik Nordmark if (cgtp_flt_pkt == CGTP_IP_PKT_DUPLICATE) { 2536bd670b35SErik Nordmark ip_drop_input("CGTP_IP_PKT_DUPLICATE", mp, ill); 2537bd670b35SErik Nordmark freemsg(mp); 2538bd670b35SErik Nordmark return; 2539bd670b35SErik Nordmark } 2540bd670b35SErik Nordmark } 2541bd670b35SErik Nordmark 2542bd670b35SErik Nordmark /* 2543bd670b35SErik Nordmark * Update ip_hdr_length to skip the frag header 2544bd670b35SErik Nordmark * ip_input_fragment_v6 will determine the extension header 2545bd670b35SErik Nordmark * prior to the fragment header and update its nexthdr value, 2546bd670b35SErik Nordmark * and also set ira_protocol to the nexthdr that follows the 2547bd670b35SErik Nordmark * completed fragment. 2548bd670b35SErik Nordmark */ 2549bd670b35SErik Nordmark ip_hdr_length += sizeof (ip6_frag_t); 2550bd670b35SErik Nordmark 2551bd670b35SErik Nordmark /* 2552bd670b35SErik Nordmark * Make sure we have ira_l2src before we loose the original 2553bd670b35SErik Nordmark * mblk 2554bd670b35SErik Nordmark */ 2555bd670b35SErik Nordmark if (!(ira->ira_flags & IRAF_L2SRC_SET)) 2556bd670b35SErik Nordmark ip_setl2src(mp, ira, ira->ira_rill); 2557bd670b35SErik Nordmark 2558bd670b35SErik Nordmark mp = ip_input_fragment_v6(mp, ip6h, fraghdr, 2559bd670b35SErik Nordmark ira->ira_pktlen - ip_hdr_length, ira); 2560bd670b35SErik Nordmark if (mp == NULL) { 2561bd670b35SErik Nordmark /* Reassembly is still pending */ 2562bd670b35SErik Nordmark return; 2563bd670b35SErik Nordmark } 2564bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsReasmOKs); 2565bd670b35SErik Nordmark 2566bd670b35SErik Nordmark /* 2567bd670b35SErik Nordmark * The mblk chain has the frag header removed and 2568bd670b35SErik Nordmark * ira_protocol, ira_pktlen, ira_ip_hdr_length as well as the 2569bd670b35SErik Nordmark * IP header has been updated to refleact the result. 2570bd670b35SErik Nordmark */ 2571bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 2572bd670b35SErik Nordmark ip_hdr_length = ira->ira_ip_hdr_length; 2573bd670b35SErik Nordmark goto repeat; 2574bd670b35SErik Nordmark } 2575bd670b35SErik Nordmark case IPPROTO_HOPOPTS: 2576bd670b35SErik Nordmark /* 2577bd670b35SErik Nordmark * Illegal header sequence. 2578bd670b35SErik Nordmark * (Hop-by-hop headers are processed above 2579bd670b35SErik Nordmark * and required to immediately follow IPv6 header) 2580bd670b35SErik Nordmark */ 2581bd670b35SErik Nordmark ip_drop_input("ICMP_PARAM_PROBLEM", mp, ill); 2582bd670b35SErik Nordmark icmp_param_problem_nexthdr_v6(mp, B_FALSE, ira); 2583bd670b35SErik Nordmark return; 2584bd670b35SErik Nordmark 2585bd670b35SErik Nordmark case IPPROTO_ROUTING: { 2586bd670b35SErik Nordmark uint_t ehdrlen; 2587bd670b35SErik Nordmark ip6_rthdr_t *rthdr; 2588bd670b35SErik Nordmark 2589bd670b35SErik Nordmark /* Check if AH is present and needs to be processed. */ 2590bd670b35SErik Nordmark mp = ipsec_early_ah_v6(mp, ira); 2591bd670b35SErik Nordmark if (mp == NULL) 2592bd670b35SErik Nordmark return; 2593bd670b35SErik Nordmark 2594bd670b35SErik Nordmark /* 2595bd670b35SErik Nordmark * Reinitialize pointers, as ipsec_early_ah_v6() does 2596bd670b35SErik Nordmark * complete pullups. We don't have to do more pullups 2597bd670b35SErik Nordmark * as a result. 2598bd670b35SErik Nordmark */ 2599bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 2600bd670b35SErik Nordmark 2601bd670b35SErik Nordmark if (ira->ira_pktlen - ip_hdr_length < MIN_EHDR_LEN) 2602bd670b35SErik Nordmark goto pkt_too_short; 2603bd670b35SErik Nordmark 2604bd670b35SErik Nordmark if (mp->b_cont != NULL && 2605bd670b35SErik Nordmark rptr + ip_hdr_length + MIN_EHDR_LEN > mp->b_wptr) { 2606bd670b35SErik Nordmark ip6h = ip_pullup(mp, ip_hdr_length + MIN_EHDR_LEN, ira); 2607bd670b35SErik Nordmark if (ip6h == NULL) 2608bd670b35SErik Nordmark goto discard; 2609bd670b35SErik Nordmark } 2610bd670b35SErik Nordmark rthdr = (ip6_rthdr_t *)(rptr + ip_hdr_length); 2611bd670b35SErik Nordmark protocol = ira->ira_protocol = rthdr->ip6r_nxt; 2612bd670b35SErik Nordmark ehdrlen = 8 * (rthdr->ip6r_len + 1); 2613bd670b35SErik Nordmark if (ira->ira_pktlen - ip_hdr_length < ehdrlen) 2614bd670b35SErik Nordmark goto pkt_too_short; 2615bd670b35SErik Nordmark if (mp->b_cont != NULL && 2616bd670b35SErik Nordmark rptr + IPV6_HDR_LEN + ehdrlen > mp->b_wptr) { 2617bd670b35SErik Nordmark ip6h = ip_pullup(mp, IPV6_HDR_LEN + ehdrlen, ira); 2618bd670b35SErik Nordmark if (ip6h == NULL) 2619bd670b35SErik Nordmark goto discard; 2620bd670b35SErik Nordmark rthdr = (ip6_rthdr_t *)(rptr + ip_hdr_length); 2621bd670b35SErik Nordmark } 2622bd670b35SErik Nordmark if (rthdr->ip6r_segleft != 0) { 2623bd670b35SErik Nordmark /* Not end of source route */ 2624bd670b35SErik Nordmark if (ira->ira_flags & 2625bd670b35SErik Nordmark (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) { 2626bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, 2627bd670b35SErik Nordmark ipIfStatsForwProhibits); 2628bd670b35SErik Nordmark ip_drop_input("ipIfStatsInForwProhibits", 2629bd670b35SErik Nordmark mp, ill); 2630bd670b35SErik Nordmark freemsg(mp); 2631bd670b35SErik Nordmark return; 2632bd670b35SErik Nordmark } 2633bd670b35SErik Nordmark ip_process_rthdr(mp, ip6h, rthdr, ira); 2634bd670b35SErik Nordmark return; 2635bd670b35SErik Nordmark } 2636bd670b35SErik Nordmark ira->ira_ip_hdr_length += ehdrlen; 2637bd670b35SErik Nordmark goto repeat; 2638bd670b35SErik Nordmark } 2639bd670b35SErik Nordmark 2640bd670b35SErik Nordmark case IPPROTO_AH: 2641bd670b35SErik Nordmark case IPPROTO_ESP: { 2642bd670b35SErik Nordmark /* 2643bd670b35SErik Nordmark * Fast path for AH/ESP. 2644bd670b35SErik Nordmark */ 2645bd670b35SErik Nordmark netstack_t *ns = ipst->ips_netstack; 2646bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 2647bd670b35SErik Nordmark 2648bd670b35SErik Nordmark IP_STAT(ipst, ipsec_proto_ahesp); 2649bd670b35SErik Nordmark 2650bd670b35SErik Nordmark if (!ipsec_loaded(ipss)) { 2651bd670b35SErik Nordmark ip_proto_not_sup(mp, ira); 2652bd670b35SErik Nordmark return; 2653bd670b35SErik Nordmark } 2654bd670b35SErik Nordmark 2655bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2656bd670b35SErik Nordmark /* select inbound SA and have IPsec process the pkt */ 2657bd670b35SErik Nordmark if (protocol == IPPROTO_ESP) { 2658bd670b35SErik Nordmark esph_t *esph; 2659bd670b35SErik Nordmark 2660bd670b35SErik Nordmark mp = ipsec_inbound_esp_sa(mp, ira, &esph); 2661bd670b35SErik Nordmark if (mp == NULL) 2662bd670b35SErik Nordmark return; 2663bd670b35SErik Nordmark 2664bd670b35SErik Nordmark ASSERT(esph != NULL); 2665bd670b35SErik Nordmark ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 2666bd670b35SErik Nordmark ASSERT(ira->ira_ipsec_esp_sa != NULL); 2667bd670b35SErik Nordmark ASSERT(ira->ira_ipsec_esp_sa->ipsa_input_func != NULL); 2668bd670b35SErik Nordmark 2669bd670b35SErik Nordmark mp = ira->ira_ipsec_esp_sa->ipsa_input_func(mp, esph, 2670bd670b35SErik Nordmark ira); 2671bd670b35SErik Nordmark } else { 2672bd670b35SErik Nordmark ah_t *ah; 2673bd670b35SErik Nordmark 2674bd670b35SErik Nordmark mp = ipsec_inbound_ah_sa(mp, ira, &ah); 2675bd670b35SErik Nordmark if (mp == NULL) 2676bd670b35SErik Nordmark return; 2677bd670b35SErik Nordmark 2678bd670b35SErik Nordmark ASSERT(ah != NULL); 2679bd670b35SErik Nordmark ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 2680bd670b35SErik Nordmark ASSERT(ira->ira_ipsec_ah_sa != NULL); 2681bd670b35SErik Nordmark ASSERT(ira->ira_ipsec_ah_sa->ipsa_input_func != NULL); 2682bd670b35SErik Nordmark mp = ira->ira_ipsec_ah_sa->ipsa_input_func(mp, ah, 2683bd670b35SErik Nordmark ira); 2684bd670b35SErik Nordmark } 2685bd670b35SErik Nordmark 2686bd670b35SErik Nordmark if (mp == NULL) { 2687bd670b35SErik Nordmark /* 2688bd670b35SErik Nordmark * Either it failed or is pending. In the former case 2689bd670b35SErik Nordmark * ipIfStatsInDiscards was increased. 2690bd670b35SErik Nordmark */ 2691bd670b35SErik Nordmark return; 2692bd670b35SErik Nordmark } 2693bd670b35SErik Nordmark /* we're done with IPsec processing, send it up */ 2694bd670b35SErik Nordmark ip_input_post_ipsec(mp, ira); 2695bd670b35SErik Nordmark return; 2696bd670b35SErik Nordmark } 2697bd670b35SErik Nordmark case IPPROTO_NONE: 2698bd670b35SErik Nordmark /* All processing is done. Count as "delivered". */ 2699bd670b35SErik Nordmark freemsg(mp); 2700bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2701bd670b35SErik Nordmark return; 2702bd670b35SErik Nordmark 2703bd670b35SErik Nordmark case IPPROTO_ENCAP: 2704bd670b35SErik Nordmark case IPPROTO_IPV6: 2705bd670b35SErik Nordmark /* iptun will verify trusted label */ 2706bd670b35SErik Nordmark connp = ipcl_classify_v6(mp, protocol, ip_hdr_length, 2707bd670b35SErik Nordmark ira, ipst); 2708bd670b35SErik Nordmark if (connp != NULL) { 2709bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 2710bd670b35SErik Nordmark ira->ira_ill = ira->ira_rill = NULL; 2711bd670b35SErik Nordmark connp->conn_recv(connp, mp, NULL, ira); 2712bd670b35SErik Nordmark CONN_DEC_REF(connp); 2713bd670b35SErik Nordmark ira->ira_ill = ill; 2714bd670b35SErik Nordmark ira->ira_rill = rill; 2715bd670b35SErik Nordmark return; 2716bd670b35SErik Nordmark } 2717bd670b35SErik Nordmark /* FALLTHRU */ 2718bd670b35SErik Nordmark default: 2719bd670b35SErik Nordmark /* 2720bd670b35SErik Nordmark * On a labeled system, we have to check whether the zone 2721bd670b35SErik Nordmark * itself is permitted to receive raw traffic. 2722bd670b35SErik Nordmark */ 2723bd670b35SErik Nordmark if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 2724bd670b35SErik Nordmark if (!tsol_can_accept_raw(mp, ira, B_FALSE)) { 2725bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 2726bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 2727bd670b35SErik Nordmark freemsg(mp); 2728bd670b35SErik Nordmark return; 2729bd670b35SErik Nordmark } 2730bd670b35SErik Nordmark } 2731bd670b35SErik Nordmark break; 2732bd670b35SErik Nordmark } 2733bd670b35SErik Nordmark 2734bd670b35SErik Nordmark /* 2735bd670b35SErik Nordmark * The above input functions may have returned the pulled up message. 2736bd670b35SErik Nordmark * So ip6h need to be reinitialized. 2737bd670b35SErik Nordmark */ 2738bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr; 2739bd670b35SErik Nordmark ira->ira_protocol = protocol; 2740bd670b35SErik Nordmark if (ipst->ips_ipcl_proto_fanout_v6[protocol].connf_head == NULL) { 2741bd670b35SErik Nordmark /* No user-level listener for these packets packets */ 2742bd670b35SErik Nordmark ip_proto_not_sup(mp, ira); 2743bd670b35SErik Nordmark return; 2744bd670b35SErik Nordmark } 2745bd670b35SErik Nordmark 2746bd670b35SErik Nordmark /* 2747bd670b35SErik Nordmark * Handle fanout to raw sockets. There 2748bd670b35SErik Nordmark * can be more than one stream bound to a particular 2749bd670b35SErik Nordmark * protocol. When this is the case, each one gets a copy 2750bd670b35SErik Nordmark * of any incoming packets. 2751bd670b35SErik Nordmark */ 2752bd670b35SErik Nordmark ASSERT(ira->ira_protocol == protocol); 2753bd670b35SErik Nordmark ip_fanout_proto_v6(mp, ip6h, ira); 2754bd670b35SErik Nordmark return; 2755bd670b35SErik Nordmark 2756bd670b35SErik Nordmark pkt_too_short: 2757bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts); 2758bd670b35SErik Nordmark ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill); 2759bd670b35SErik Nordmark freemsg(mp); 2760bd670b35SErik Nordmark return; 2761bd670b35SErik Nordmark 2762bd670b35SErik Nordmark discard: 2763bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 2764bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", mp, ill); 2765bd670b35SErik Nordmark freemsg(mp); 2766bd670b35SErik Nordmark #undef rptr 2767bd670b35SErik Nordmark } 2768