111042SErik.Nordmark@Sun.COM /* 211042SErik.Nordmark@Sun.COM * CDDL HEADER START 311042SErik.Nordmark@Sun.COM * 411042SErik.Nordmark@Sun.COM * The contents of this file are subject to the terms of the 511042SErik.Nordmark@Sun.COM * Common Development and Distribution License (the "License"). 611042SErik.Nordmark@Sun.COM * You may not use this file except in compliance with the License. 711042SErik.Nordmark@Sun.COM * 811042SErik.Nordmark@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 911042SErik.Nordmark@Sun.COM * or http://www.opensolaris.org/os/licensing. 1011042SErik.Nordmark@Sun.COM * See the License for the specific language governing permissions 1111042SErik.Nordmark@Sun.COM * and limitations under the License. 1211042SErik.Nordmark@Sun.COM * 1311042SErik.Nordmark@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1411042SErik.Nordmark@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1511042SErik.Nordmark@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1611042SErik.Nordmark@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1711042SErik.Nordmark@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1811042SErik.Nordmark@Sun.COM * 1911042SErik.Nordmark@Sun.COM * CDDL HEADER END 2011042SErik.Nordmark@Sun.COM */ 2111042SErik.Nordmark@Sun.COM 2211042SErik.Nordmark@Sun.COM /* 2311457SErik.Nordmark@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2411042SErik.Nordmark@Sun.COM * Use is subject to license terms. 2511042SErik.Nordmark@Sun.COM */ 2611042SErik.Nordmark@Sun.COM /* Copyright (c) 1990 Mentat Inc. */ 2711042SErik.Nordmark@Sun.COM 2811042SErik.Nordmark@Sun.COM #include <sys/types.h> 2911042SErik.Nordmark@Sun.COM #include <sys/stream.h> 3011042SErik.Nordmark@Sun.COM #include <sys/dlpi.h> 3111042SErik.Nordmark@Sun.COM #include <sys/stropts.h> 3211042SErik.Nordmark@Sun.COM #include <sys/sysmacros.h> 3311042SErik.Nordmark@Sun.COM #include <sys/strsubr.h> 3411042SErik.Nordmark@Sun.COM #include <sys/strlog.h> 3511042SErik.Nordmark@Sun.COM #include <sys/strsun.h> 3611042SErik.Nordmark@Sun.COM #include <sys/zone.h> 3711042SErik.Nordmark@Sun.COM #define _SUN_TPI_VERSION 2 3811042SErik.Nordmark@Sun.COM #include <sys/tihdr.h> 3911042SErik.Nordmark@Sun.COM #include <sys/xti_inet.h> 4011042SErik.Nordmark@Sun.COM #include <sys/ddi.h> 4111042SErik.Nordmark@Sun.COM #include <sys/sunddi.h> 4211042SErik.Nordmark@Sun.COM #include <sys/cmn_err.h> 4311042SErik.Nordmark@Sun.COM #include <sys/debug.h> 4411042SErik.Nordmark@Sun.COM #include <sys/kobj.h> 4511042SErik.Nordmark@Sun.COM #include <sys/modctl.h> 4611042SErik.Nordmark@Sun.COM #include <sys/atomic.h> 4711042SErik.Nordmark@Sun.COM #include <sys/policy.h> 4811042SErik.Nordmark@Sun.COM #include <sys/priv.h> 4911042SErik.Nordmark@Sun.COM 5011042SErik.Nordmark@Sun.COM #include <sys/systm.h> 5111042SErik.Nordmark@Sun.COM #include <sys/param.h> 5211042SErik.Nordmark@Sun.COM #include <sys/kmem.h> 5311042SErik.Nordmark@Sun.COM #include <sys/sdt.h> 5411042SErik.Nordmark@Sun.COM #include <sys/socket.h> 5511042SErik.Nordmark@Sun.COM #include <sys/vtrace.h> 5611042SErik.Nordmark@Sun.COM #include <sys/isa_defs.h> 5711042SErik.Nordmark@Sun.COM #include <sys/mac.h> 5811042SErik.Nordmark@Sun.COM #include <net/if.h> 5911042SErik.Nordmark@Sun.COM #include <net/if_arp.h> 6011042SErik.Nordmark@Sun.COM #include <net/route.h> 6111042SErik.Nordmark@Sun.COM #include <sys/sockio.h> 6211042SErik.Nordmark@Sun.COM #include <netinet/in.h> 6311042SErik.Nordmark@Sun.COM #include <net/if_dl.h> 6411042SErik.Nordmark@Sun.COM 6511042SErik.Nordmark@Sun.COM #include <inet/common.h> 6611042SErik.Nordmark@Sun.COM #include <inet/mi.h> 6711042SErik.Nordmark@Sun.COM #include <inet/mib2.h> 6811042SErik.Nordmark@Sun.COM #include <inet/nd.h> 6911042SErik.Nordmark@Sun.COM #include <inet/arp.h> 7011042SErik.Nordmark@Sun.COM #include <inet/snmpcom.h> 7111042SErik.Nordmark@Sun.COM #include <inet/kstatcom.h> 7211042SErik.Nordmark@Sun.COM 7311042SErik.Nordmark@Sun.COM #include <netinet/igmp_var.h> 7411042SErik.Nordmark@Sun.COM #include <netinet/ip6.h> 7511042SErik.Nordmark@Sun.COM #include <netinet/icmp6.h> 7611042SErik.Nordmark@Sun.COM #include <netinet/sctp.h> 7711042SErik.Nordmark@Sun.COM 7811042SErik.Nordmark@Sun.COM #include <inet/ip.h> 7911042SErik.Nordmark@Sun.COM #include <inet/ip_impl.h> 8011042SErik.Nordmark@Sun.COM #include <inet/ip6.h> 8111042SErik.Nordmark@Sun.COM #include <inet/ip6_asp.h> 8211042SErik.Nordmark@Sun.COM #include <inet/optcom.h> 8311042SErik.Nordmark@Sun.COM #include <inet/tcp.h> 8411042SErik.Nordmark@Sun.COM #include <inet/tcp_impl.h> 8511042SErik.Nordmark@Sun.COM #include <inet/ip_multi.h> 8611042SErik.Nordmark@Sun.COM #include <inet/ip_if.h> 8711042SErik.Nordmark@Sun.COM #include <inet/ip_ire.h> 8811042SErik.Nordmark@Sun.COM #include <inet/ip_ftable.h> 8911042SErik.Nordmark@Sun.COM #include <inet/ip_rts.h> 9011042SErik.Nordmark@Sun.COM #include <inet/ip_ndp.h> 9111042SErik.Nordmark@Sun.COM #include <inet/ip_listutils.h> 9211042SErik.Nordmark@Sun.COM #include <netinet/igmp.h> 9311042SErik.Nordmark@Sun.COM #include <netinet/ip_mroute.h> 9411042SErik.Nordmark@Sun.COM #include <inet/ipp_common.h> 9511042SErik.Nordmark@Sun.COM 9611042SErik.Nordmark@Sun.COM #include <net/pfkeyv2.h> 9711042SErik.Nordmark@Sun.COM #include <inet/sadb.h> 9811042SErik.Nordmark@Sun.COM #include <inet/ipsec_impl.h> 9911042SErik.Nordmark@Sun.COM #include <inet/ipdrop.h> 10011042SErik.Nordmark@Sun.COM #include <inet/ip_netinfo.h> 10111042SErik.Nordmark@Sun.COM #include <inet/ilb_ip.h> 10211042SErik.Nordmark@Sun.COM #include <sys/squeue_impl.h> 10311042SErik.Nordmark@Sun.COM #include <sys/squeue.h> 10411042SErik.Nordmark@Sun.COM 10511042SErik.Nordmark@Sun.COM #include <sys/ethernet.h> 10611042SErik.Nordmark@Sun.COM #include <net/if_types.h> 10711042SErik.Nordmark@Sun.COM #include <sys/cpuvar.h> 10811042SErik.Nordmark@Sun.COM 10911042SErik.Nordmark@Sun.COM #include <ipp/ipp.h> 11011042SErik.Nordmark@Sun.COM #include <ipp/ipp_impl.h> 11111042SErik.Nordmark@Sun.COM #include <ipp/ipgpc/ipgpc.h> 11211042SErik.Nordmark@Sun.COM 11311042SErik.Nordmark@Sun.COM #include <sys/pattr.h> 11411042SErik.Nordmark@Sun.COM #include <inet/ipclassifier.h> 11511042SErik.Nordmark@Sun.COM #include <inet/sctp_ip.h> 11611042SErik.Nordmark@Sun.COM #include <inet/sctp/sctp_impl.h> 11711042SErik.Nordmark@Sun.COM #include <inet/udp_impl.h> 11811042SErik.Nordmark@Sun.COM #include <sys/sunddi.h> 11911042SErik.Nordmark@Sun.COM 12011042SErik.Nordmark@Sun.COM #include <sys/tsol/label.h> 12111042SErik.Nordmark@Sun.COM #include <sys/tsol/tnet.h> 12211042SErik.Nordmark@Sun.COM 12311110SErik.Nordmark@Sun.COM #include <sys/clock_impl.h> /* For LBOLT_FASTPATH{,64} */ 12411042SErik.Nordmark@Sun.COM 12511042SErik.Nordmark@Sun.COM #ifdef DEBUG 12611042SErik.Nordmark@Sun.COM extern boolean_t skip_sctp_cksum; 12711042SErik.Nordmark@Sun.COM #endif 12811042SErik.Nordmark@Sun.COM 12911042SErik.Nordmark@Sun.COM static void ip_input_local_v4(ire_t *, mblk_t *, ipha_t *, 13011042SErik.Nordmark@Sun.COM ip_recv_attr_t *); 13111042SErik.Nordmark@Sun.COM 13211042SErik.Nordmark@Sun.COM static void ip_input_broadcast_v4(ire_t *, mblk_t *, ipha_t *, 13311042SErik.Nordmark@Sun.COM ip_recv_attr_t *); 13411042SErik.Nordmark@Sun.COM static void ip_input_multicast_v4(ire_t *, mblk_t *, ipha_t *, 13511042SErik.Nordmark@Sun.COM ip_recv_attr_t *); 13611042SErik.Nordmark@Sun.COM 13711042SErik.Nordmark@Sun.COM #pragma inline(ip_input_common_v4, ip_input_local_v4, ip_forward_xmit_v4) 13811042SErik.Nordmark@Sun.COM 13911042SErik.Nordmark@Sun.COM /* 14011042SErik.Nordmark@Sun.COM * Direct read side procedure capable of dealing with chains. GLDv3 based 14111042SErik.Nordmark@Sun.COM * drivers call this function directly with mblk chains while STREAMS 14211042SErik.Nordmark@Sun.COM * read side procedure ip_rput() calls this for single packet with ip_ring 14311042SErik.Nordmark@Sun.COM * set to NULL to process one packet at a time. 14411042SErik.Nordmark@Sun.COM * 14511042SErik.Nordmark@Sun.COM * The ill will always be valid if this function is called directly from 14611042SErik.Nordmark@Sun.COM * the driver. 14711042SErik.Nordmark@Sun.COM * 14811042SErik.Nordmark@Sun.COM * If ip_input() is called from GLDv3: 14911042SErik.Nordmark@Sun.COM * 15011042SErik.Nordmark@Sun.COM * - This must be a non-VLAN IP stream. 15111042SErik.Nordmark@Sun.COM * - 'mp' is either an untagged or a special priority-tagged packet. 15211042SErik.Nordmark@Sun.COM * - Any VLAN tag that was in the MAC header has been stripped. 15311042SErik.Nordmark@Sun.COM * 15411042SErik.Nordmark@Sun.COM * If the IP header in packet is not 32-bit aligned, every message in the 15511042SErik.Nordmark@Sun.COM * chain will be aligned before further operations. This is required on SPARC 15611042SErik.Nordmark@Sun.COM * platform. 15711042SErik.Nordmark@Sun.COM */ 15811042SErik.Nordmark@Sun.COM void 15911042SErik.Nordmark@Sun.COM ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 16011042SErik.Nordmark@Sun.COM struct mac_header_info_s *mhip) 16111042SErik.Nordmark@Sun.COM { 16211042SErik.Nordmark@Sun.COM (void) ip_input_common_v4(ill, ip_ring, mp_chain, mhip, NULL, NULL, 16311042SErik.Nordmark@Sun.COM NULL); 16411042SErik.Nordmark@Sun.COM } 16511042SErik.Nordmark@Sun.COM 16611042SErik.Nordmark@Sun.COM /* 16711042SErik.Nordmark@Sun.COM * ip_accept_tcp() - This function is called by the squeue when it retrieves 16811042SErik.Nordmark@Sun.COM * a chain of packets in the poll mode. The packets have gone through the 16911042SErik.Nordmark@Sun.COM * data link processing but not IP processing. For performance and latency 17011042SErik.Nordmark@Sun.COM * reasons, the squeue wants to process the chain in line instead of feeding 17111042SErik.Nordmark@Sun.COM * it back via ip_input path. 17211042SErik.Nordmark@Sun.COM * 17311042SErik.Nordmark@Sun.COM * We set up the ip_recv_attr_t with IRAF_TARGET_SQP to that ip_fanout_v4 17411042SErik.Nordmark@Sun.COM * will pass back any TCP packets matching the target sqp to 17511042SErik.Nordmark@Sun.COM * ip_input_common_v4 using ira_target_sqp_mp. Other packets are handled by 17611042SErik.Nordmark@Sun.COM * ip_input_v4 and ip_fanout_v4 as normal. 17711042SErik.Nordmark@Sun.COM * The TCP packets that match the target squeue are returned to the caller 17811042SErik.Nordmark@Sun.COM * as a b_next chain after each packet has been prepend with an mblk 17911042SErik.Nordmark@Sun.COM * from ip_recv_attr_to_mblk. 18011042SErik.Nordmark@Sun.COM */ 18111042SErik.Nordmark@Sun.COM mblk_t * 18211042SErik.Nordmark@Sun.COM ip_accept_tcp(ill_t *ill, ill_rx_ring_t *ip_ring, squeue_t *target_sqp, 18311042SErik.Nordmark@Sun.COM mblk_t *mp_chain, mblk_t **last, uint_t *cnt) 18411042SErik.Nordmark@Sun.COM { 18511042SErik.Nordmark@Sun.COM return (ip_input_common_v4(ill, ip_ring, mp_chain, NULL, target_sqp, 18611042SErik.Nordmark@Sun.COM last, cnt)); 18711042SErik.Nordmark@Sun.COM } 18811042SErik.Nordmark@Sun.COM 18911042SErik.Nordmark@Sun.COM /* 19011042SErik.Nordmark@Sun.COM * Used by ip_input and ip_accept_tcp 19111042SErik.Nordmark@Sun.COM * The last three arguments are only used by ip_accept_tcp, and mhip is 19211042SErik.Nordmark@Sun.COM * only used by ip_input. 19311042SErik.Nordmark@Sun.COM */ 19411042SErik.Nordmark@Sun.COM mblk_t * 19511042SErik.Nordmark@Sun.COM ip_input_common_v4(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 19611042SErik.Nordmark@Sun.COM struct mac_header_info_s *mhip, squeue_t *target_sqp, 19711042SErik.Nordmark@Sun.COM mblk_t **last, uint_t *cnt) 19811042SErik.Nordmark@Sun.COM { 19911042SErik.Nordmark@Sun.COM mblk_t *mp; 20011042SErik.Nordmark@Sun.COM ipha_t *ipha; 20111042SErik.Nordmark@Sun.COM ip_recv_attr_t iras; /* Receive attributes */ 20211042SErik.Nordmark@Sun.COM rtc_t rtc; 20311042SErik.Nordmark@Sun.COM iaflags_t chain_flags = 0; /* Fixed for chain */ 20411042SErik.Nordmark@Sun.COM mblk_t *ahead = NULL; /* Accepted head */ 20511042SErik.Nordmark@Sun.COM mblk_t *atail = NULL; /* Accepted tail */ 20611042SErik.Nordmark@Sun.COM uint_t acnt = 0; /* Accepted count */ 20711042SErik.Nordmark@Sun.COM 20811042SErik.Nordmark@Sun.COM ASSERT(mp_chain != NULL); 20911042SErik.Nordmark@Sun.COM ASSERT(ill != NULL); 21011042SErik.Nordmark@Sun.COM 21111042SErik.Nordmark@Sun.COM /* These ones do not change as we loop over packets */ 21211042SErik.Nordmark@Sun.COM iras.ira_ill = iras.ira_rill = ill; 21311042SErik.Nordmark@Sun.COM iras.ira_ruifindex = ill->ill_phyint->phyint_ifindex; 21411042SErik.Nordmark@Sun.COM iras.ira_rifindex = iras.ira_ruifindex; 21511042SErik.Nordmark@Sun.COM iras.ira_sqp = NULL; 21611042SErik.Nordmark@Sun.COM iras.ira_ring = ip_ring; 21711042SErik.Nordmark@Sun.COM /* For ECMP and outbound transmit ring selection */ 21811042SErik.Nordmark@Sun.COM iras.ira_xmit_hint = ILL_RING_TO_XMIT_HINT(ip_ring); 21911042SErik.Nordmark@Sun.COM 22011042SErik.Nordmark@Sun.COM iras.ira_target_sqp = target_sqp; 22111042SErik.Nordmark@Sun.COM iras.ira_target_sqp_mp = NULL; 22211042SErik.Nordmark@Sun.COM if (target_sqp != NULL) 22311042SErik.Nordmark@Sun.COM chain_flags |= IRAF_TARGET_SQP; 22411042SErik.Nordmark@Sun.COM 22511042SErik.Nordmark@Sun.COM /* 22611042SErik.Nordmark@Sun.COM * We try to have a mhip pointer when possible, but 22711042SErik.Nordmark@Sun.COM * it might be NULL in some cases. In those cases we 22811042SErik.Nordmark@Sun.COM * have to assume unicast. 22911042SErik.Nordmark@Sun.COM */ 23011042SErik.Nordmark@Sun.COM iras.ira_mhip = mhip; 23111042SErik.Nordmark@Sun.COM iras.ira_flags = 0; 23211042SErik.Nordmark@Sun.COM if (mhip != NULL) { 23311042SErik.Nordmark@Sun.COM switch (mhip->mhi_dsttype) { 23411042SErik.Nordmark@Sun.COM case MAC_ADDRTYPE_MULTICAST : 23511042SErik.Nordmark@Sun.COM chain_flags |= IRAF_L2DST_MULTICAST; 23611042SErik.Nordmark@Sun.COM break; 23711042SErik.Nordmark@Sun.COM case MAC_ADDRTYPE_BROADCAST : 23811042SErik.Nordmark@Sun.COM chain_flags |= IRAF_L2DST_BROADCAST; 23911042SErik.Nordmark@Sun.COM break; 24011042SErik.Nordmark@Sun.COM } 24111042SErik.Nordmark@Sun.COM } 24211042SErik.Nordmark@Sun.COM 24311042SErik.Nordmark@Sun.COM /* 24411042SErik.Nordmark@Sun.COM * Initialize the one-element route cache. 24511042SErik.Nordmark@Sun.COM * 24611042SErik.Nordmark@Sun.COM * We do ire caching from one iteration to 24711042SErik.Nordmark@Sun.COM * another. In the event the packet chain contains 24811042SErik.Nordmark@Sun.COM * all packets from the same dst, this caching saves 24911042SErik.Nordmark@Sun.COM * an ire_route_recursive for each of the succeeding 25011042SErik.Nordmark@Sun.COM * packets in a packet chain. 25111042SErik.Nordmark@Sun.COM */ 25211042SErik.Nordmark@Sun.COM rtc.rtc_ire = NULL; 25311042SErik.Nordmark@Sun.COM rtc.rtc_ipaddr = INADDR_ANY; 25411042SErik.Nordmark@Sun.COM 25511042SErik.Nordmark@Sun.COM /* Loop over b_next */ 25611042SErik.Nordmark@Sun.COM for (mp = mp_chain; mp != NULL; mp = mp_chain) { 25711042SErik.Nordmark@Sun.COM mp_chain = mp->b_next; 25811042SErik.Nordmark@Sun.COM mp->b_next = NULL; 25911042SErik.Nordmark@Sun.COM 26011042SErik.Nordmark@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 26111042SErik.Nordmark@Sun.COM 26211042SErik.Nordmark@Sun.COM 26311042SErik.Nordmark@Sun.COM /* 26411042SErik.Nordmark@Sun.COM * if db_ref > 1 then copymsg and free original. Packet 26511042SErik.Nordmark@Sun.COM * may be changed and we do not want the other entity 26611042SErik.Nordmark@Sun.COM * who has a reference to this message to trip over the 26711042SErik.Nordmark@Sun.COM * changes. This is a blind change because trying to 26811042SErik.Nordmark@Sun.COM * catch all places that might change the packet is too 26911042SErik.Nordmark@Sun.COM * difficult. 27011042SErik.Nordmark@Sun.COM * 27111042SErik.Nordmark@Sun.COM * This corresponds to the fast path case, where we have 27211042SErik.Nordmark@Sun.COM * a chain of M_DATA mblks. We check the db_ref count 27311042SErik.Nordmark@Sun.COM * of only the 1st data block in the mblk chain. There 27411042SErik.Nordmark@Sun.COM * doesn't seem to be a reason why a device driver would 27511042SErik.Nordmark@Sun.COM * send up data with varying db_ref counts in the mblk 27611042SErik.Nordmark@Sun.COM * chain. In any case the Fast path is a private 27711042SErik.Nordmark@Sun.COM * interface, and our drivers don't do such a thing. 27811042SErik.Nordmark@Sun.COM * Given the above assumption, there is no need to walk 27911042SErik.Nordmark@Sun.COM * down the entire mblk chain (which could have a 28011042SErik.Nordmark@Sun.COM * potential performance problem) 28111042SErik.Nordmark@Sun.COM * 28211042SErik.Nordmark@Sun.COM * The "(DB_REF(mp) > 1)" check was moved from ip_rput() 28311042SErik.Nordmark@Sun.COM * to here because of exclusive ip stacks and vnics. 28411042SErik.Nordmark@Sun.COM * Packets transmitted from exclusive stack over vnic 28511042SErik.Nordmark@Sun.COM * can have db_ref > 1 and when it gets looped back to 28611042SErik.Nordmark@Sun.COM * another vnic in a different zone, you have ip_input() 28711042SErik.Nordmark@Sun.COM * getting dblks with db_ref > 1. So if someone 28811042SErik.Nordmark@Sun.COM * complains of TCP performance under this scenario, 28911042SErik.Nordmark@Sun.COM * take a serious look here on the impact of copymsg(). 29011042SErik.Nordmark@Sun.COM */ 29111042SErik.Nordmark@Sun.COM if (DB_REF(mp) > 1) { 29211042SErik.Nordmark@Sun.COM if ((mp = ip_fix_dbref(mp, &iras)) == NULL) { 29311042SErik.Nordmark@Sun.COM /* mhip might point into 1st packet in chain */ 29411042SErik.Nordmark@Sun.COM iras.ira_mhip = NULL; 29511042SErik.Nordmark@Sun.COM continue; 29611042SErik.Nordmark@Sun.COM } 29711042SErik.Nordmark@Sun.COM } 29811042SErik.Nordmark@Sun.COM 29911042SErik.Nordmark@Sun.COM /* 30011042SErik.Nordmark@Sun.COM * IP header ptr not aligned? 30111042SErik.Nordmark@Sun.COM * OR IP header not complete in first mblk 30211042SErik.Nordmark@Sun.COM */ 30311042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 30411042SErik.Nordmark@Sun.COM if (!OK_32PTR(ipha) || MBLKL(mp) < IP_SIMPLE_HDR_LENGTH) { 30511042SErik.Nordmark@Sun.COM mp = ip_check_and_align_header(mp, IP_SIMPLE_HDR_LENGTH, 30611042SErik.Nordmark@Sun.COM &iras); 30711042SErik.Nordmark@Sun.COM if (mp == NULL) { 30811042SErik.Nordmark@Sun.COM /* mhip might point into 1st packet in chain */ 30911042SErik.Nordmark@Sun.COM iras.ira_mhip = NULL; 31011042SErik.Nordmark@Sun.COM continue; 31111042SErik.Nordmark@Sun.COM } 31211042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 31311042SErik.Nordmark@Sun.COM } 31411042SErik.Nordmark@Sun.COM 31511042SErik.Nordmark@Sun.COM /* Protect against a mix of Ethertypes and IP versions */ 31611042SErik.Nordmark@Sun.COM if (IPH_HDR_VERSION(ipha) != IPV4_VERSION) { 31711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInHdrErrors); 31811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInHdrErrors", mp, ill); 31911042SErik.Nordmark@Sun.COM freemsg(mp); 32011042SErik.Nordmark@Sun.COM /* mhip might point into 1st packet in the chain. */ 32111042SErik.Nordmark@Sun.COM iras.ira_mhip = NULL; 32211042SErik.Nordmark@Sun.COM continue; 32311042SErik.Nordmark@Sun.COM } 32411042SErik.Nordmark@Sun.COM 32511042SErik.Nordmark@Sun.COM /* 32611042SErik.Nordmark@Sun.COM * Check for Martian addrs; we have to explicitly 32711042SErik.Nordmark@Sun.COM * test for for zero dst since this is also used as 32811042SErik.Nordmark@Sun.COM * an indication that the rtc is not used. 32911042SErik.Nordmark@Sun.COM */ 33011042SErik.Nordmark@Sun.COM if (ipha->ipha_dst == INADDR_ANY) { 33111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 33211042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 33311042SErik.Nordmark@Sun.COM freemsg(mp); 33411042SErik.Nordmark@Sun.COM /* mhip might point into 1st packet in the chain. */ 33511042SErik.Nordmark@Sun.COM iras.ira_mhip = NULL; 33611042SErik.Nordmark@Sun.COM continue; 33711042SErik.Nordmark@Sun.COM } 33811042SErik.Nordmark@Sun.COM 33911042SErik.Nordmark@Sun.COM /* 34011042SErik.Nordmark@Sun.COM * Keep L2SRC from a previous packet in chain since mhip 34111042SErik.Nordmark@Sun.COM * might point into an earlier packet in the chain. 34211042SErik.Nordmark@Sun.COM * Keep IRAF_VERIFIED_SRC to avoid redoing broadcast 34311042SErik.Nordmark@Sun.COM * source check in forwarding path. 34411042SErik.Nordmark@Sun.COM */ 34511042SErik.Nordmark@Sun.COM chain_flags |= (iras.ira_flags & 34611042SErik.Nordmark@Sun.COM (IRAF_L2SRC_SET|IRAF_VERIFIED_SRC)); 34711042SErik.Nordmark@Sun.COM 34811042SErik.Nordmark@Sun.COM iras.ira_flags = IRAF_IS_IPV4 | IRAF_VERIFY_IP_CKSUM | 34911042SErik.Nordmark@Sun.COM IRAF_VERIFY_ULP_CKSUM | chain_flags; 35011042SErik.Nordmark@Sun.COM iras.ira_free_flags = 0; 35111042SErik.Nordmark@Sun.COM iras.ira_cred = NULL; 35211042SErik.Nordmark@Sun.COM iras.ira_cpid = NOPID; 35311042SErik.Nordmark@Sun.COM iras.ira_tsl = NULL; 35411042SErik.Nordmark@Sun.COM iras.ira_zoneid = ALL_ZONES; /* Default for forwarding */ 35511042SErik.Nordmark@Sun.COM 35611042SErik.Nordmark@Sun.COM /* 35711042SErik.Nordmark@Sun.COM * We must count all incoming packets, even if they end 35811042SErik.Nordmark@Sun.COM * up being dropped later on. Defer counting bytes until 35911042SErik.Nordmark@Sun.COM * we have the whole IP header in first mblk. 36011042SErik.Nordmark@Sun.COM */ 36111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInReceives); 36211042SErik.Nordmark@Sun.COM 36311042SErik.Nordmark@Sun.COM iras.ira_pktlen = ntohs(ipha->ipha_length); 36411042SErik.Nordmark@Sun.COM UPDATE_MIB(ill->ill_ip_mib, ipIfStatsHCInOctets, 36511042SErik.Nordmark@Sun.COM iras.ira_pktlen); 36611042SErik.Nordmark@Sun.COM 36711042SErik.Nordmark@Sun.COM /* 36811042SErik.Nordmark@Sun.COM * Call one of: 36911042SErik.Nordmark@Sun.COM * ill_input_full_v4 37011042SErik.Nordmark@Sun.COM * ill_input_short_v4 37111042SErik.Nordmark@Sun.COM * The former is used in unusual cases. See ill_set_inputfn(). 37211042SErik.Nordmark@Sun.COM */ 37311042SErik.Nordmark@Sun.COM (*ill->ill_inputfn)(mp, ipha, &ipha->ipha_dst, &iras, &rtc); 37411042SErik.Nordmark@Sun.COM 37511042SErik.Nordmark@Sun.COM /* Any references to clean up? No hold on ira_ill */ 37611042SErik.Nordmark@Sun.COM if (iras.ira_flags & (IRAF_IPSEC_SECURE|IRAF_SYSTEM_LABELED)) 37711042SErik.Nordmark@Sun.COM ira_cleanup(&iras, B_FALSE); 37811042SErik.Nordmark@Sun.COM 37911042SErik.Nordmark@Sun.COM if (iras.ira_target_sqp_mp != NULL) { 38011042SErik.Nordmark@Sun.COM /* Better be called from ip_accept_tcp */ 38111042SErik.Nordmark@Sun.COM ASSERT(target_sqp != NULL); 38211042SErik.Nordmark@Sun.COM 38311042SErik.Nordmark@Sun.COM /* Found one packet to accept */ 38411042SErik.Nordmark@Sun.COM mp = iras.ira_target_sqp_mp; 38511042SErik.Nordmark@Sun.COM iras.ira_target_sqp_mp = NULL; 38611042SErik.Nordmark@Sun.COM ASSERT(ip_recv_attr_is_mblk(mp)); 38711042SErik.Nordmark@Sun.COM 38811042SErik.Nordmark@Sun.COM if (atail != NULL) 38911042SErik.Nordmark@Sun.COM atail->b_next = mp; 39011042SErik.Nordmark@Sun.COM else 39111042SErik.Nordmark@Sun.COM ahead = mp; 39211042SErik.Nordmark@Sun.COM atail = mp; 39311042SErik.Nordmark@Sun.COM acnt++; 39411042SErik.Nordmark@Sun.COM mp = NULL; 39511042SErik.Nordmark@Sun.COM } 39611042SErik.Nordmark@Sun.COM /* mhip might point into 1st packet in the chain. */ 39711042SErik.Nordmark@Sun.COM iras.ira_mhip = NULL; 39811042SErik.Nordmark@Sun.COM } 39911042SErik.Nordmark@Sun.COM /* Any remaining references to the route cache? */ 40011042SErik.Nordmark@Sun.COM if (rtc.rtc_ire != NULL) { 40111042SErik.Nordmark@Sun.COM ASSERT(rtc.rtc_ipaddr != INADDR_ANY); 40211042SErik.Nordmark@Sun.COM ire_refrele(rtc.rtc_ire); 40311042SErik.Nordmark@Sun.COM } 40411042SErik.Nordmark@Sun.COM 40511042SErik.Nordmark@Sun.COM if (ahead != NULL) { 40611042SErik.Nordmark@Sun.COM /* Better be called from ip_accept_tcp */ 40711042SErik.Nordmark@Sun.COM ASSERT(target_sqp != NULL); 40811042SErik.Nordmark@Sun.COM *last = atail; 40911042SErik.Nordmark@Sun.COM *cnt = acnt; 41011042SErik.Nordmark@Sun.COM return (ahead); 41111042SErik.Nordmark@Sun.COM } 41211042SErik.Nordmark@Sun.COM 41311042SErik.Nordmark@Sun.COM return (NULL); 41411042SErik.Nordmark@Sun.COM } 41511042SErik.Nordmark@Sun.COM 41611042SErik.Nordmark@Sun.COM /* 41711042SErik.Nordmark@Sun.COM * This input function is used when 41811042SErik.Nordmark@Sun.COM * - is_system_labeled() 41911042SErik.Nordmark@Sun.COM * - CGTP filtering 42011042SErik.Nordmark@Sun.COM * - DHCP unicast before we have an IP address configured 42111042SErik.Nordmark@Sun.COM * - there is an listener for IPPROTO_RSVP 42211042SErik.Nordmark@Sun.COM */ 42311042SErik.Nordmark@Sun.COM void 42411042SErik.Nordmark@Sun.COM ill_input_full_v4(mblk_t *mp, void *iph_arg, void *nexthop_arg, 42511042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, rtc_t *rtc) 42611042SErik.Nordmark@Sun.COM { 42711042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 42811042SErik.Nordmark@Sun.COM ipaddr_t nexthop = *(ipaddr_t *)nexthop_arg; 42911042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 43011042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 43111042SErik.Nordmark@Sun.COM int cgtp_flt_pkt; 43211042SErik.Nordmark@Sun.COM 43311042SErik.Nordmark@Sun.COM ASSERT(ira->ira_tsl == NULL); 43411042SErik.Nordmark@Sun.COM 43511042SErik.Nordmark@Sun.COM /* 43611042SErik.Nordmark@Sun.COM * Attach any necessary label information to 43711042SErik.Nordmark@Sun.COM * this packet 43811042SErik.Nordmark@Sun.COM */ 43911042SErik.Nordmark@Sun.COM if (is_system_labeled()) { 44011042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_SYSTEM_LABELED; 44111042SErik.Nordmark@Sun.COM 44211042SErik.Nordmark@Sun.COM /* 44311042SErik.Nordmark@Sun.COM * This updates ira_cred, ira_tsl and ira_free_flags based 44411042SErik.Nordmark@Sun.COM * on the label. 44511042SErik.Nordmark@Sun.COM */ 44611042SErik.Nordmark@Sun.COM if (!tsol_get_pkt_label(mp, IPV4_VERSION, ira)) { 44711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 44811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 44911042SErik.Nordmark@Sun.COM freemsg(mp); 45011042SErik.Nordmark@Sun.COM return; 45111042SErik.Nordmark@Sun.COM } 45211042SErik.Nordmark@Sun.COM /* Note that ira_tsl can be NULL here. */ 45311042SErik.Nordmark@Sun.COM 45411042SErik.Nordmark@Sun.COM /* tsol_get_pkt_label sometimes does pullupmsg */ 45511042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 45611042SErik.Nordmark@Sun.COM } 45711042SErik.Nordmark@Sun.COM 45811042SErik.Nordmark@Sun.COM /* 45911042SErik.Nordmark@Sun.COM * Invoke the CGTP (multirouting) filtering module to process 46011042SErik.Nordmark@Sun.COM * the incoming packet. Packets identified as duplicates 46111042SErik.Nordmark@Sun.COM * must be discarded. Filtering is active only if the 46211042SErik.Nordmark@Sun.COM * the ip_cgtp_filter ndd variable is non-zero. 46311042SErik.Nordmark@Sun.COM */ 46411042SErik.Nordmark@Sun.COM cgtp_flt_pkt = CGTP_IP_PKT_NOT_CGTP; 46511042SErik.Nordmark@Sun.COM if (ipst->ips_ip_cgtp_filter && 46611042SErik.Nordmark@Sun.COM ipst->ips_ip_cgtp_filter_ops != NULL) { 46711042SErik.Nordmark@Sun.COM netstackid_t stackid; 46811042SErik.Nordmark@Sun.COM 46911042SErik.Nordmark@Sun.COM stackid = ipst->ips_netstack->netstack_stackid; 47011042SErik.Nordmark@Sun.COM /* 47111042SErik.Nordmark@Sun.COM * CGTP and IPMP are mutually exclusive so 47211042SErik.Nordmark@Sun.COM * phyint_ifindex is fine here. 47311042SErik.Nordmark@Sun.COM */ 47411042SErik.Nordmark@Sun.COM cgtp_flt_pkt = 47511042SErik.Nordmark@Sun.COM ipst->ips_ip_cgtp_filter_ops->cfo_filter(stackid, 47611042SErik.Nordmark@Sun.COM ill->ill_phyint->phyint_ifindex, mp); 47711042SErik.Nordmark@Sun.COM if (cgtp_flt_pkt == CGTP_IP_PKT_DUPLICATE) { 47811042SErik.Nordmark@Sun.COM ip_drop_input("CGTP_IP_PKT_DUPLICATE", mp, ill); 47911042SErik.Nordmark@Sun.COM freemsg(mp); 48011042SErik.Nordmark@Sun.COM return; 48111042SErik.Nordmark@Sun.COM } 48211042SErik.Nordmark@Sun.COM } 48311042SErik.Nordmark@Sun.COM 48411042SErik.Nordmark@Sun.COM /* 48511042SErik.Nordmark@Sun.COM * Brutal hack for DHCPv4 unicast: RFC2131 allows a DHCP 48611042SErik.Nordmark@Sun.COM * server to unicast DHCP packets to a DHCP client using the 48711042SErik.Nordmark@Sun.COM * IP address it is offering to the client. This can be 48811042SErik.Nordmark@Sun.COM * disabled through the "broadcast bit", but not all DHCP 48911042SErik.Nordmark@Sun.COM * servers honor that bit. Therefore, to interoperate with as 49011042SErik.Nordmark@Sun.COM * many DHCP servers as possible, the DHCP client allows the 49111042SErik.Nordmark@Sun.COM * server to unicast, but we treat those packets as broadcast 49211042SErik.Nordmark@Sun.COM * here. Note that we don't rewrite the packet itself since 49311042SErik.Nordmark@Sun.COM * (a) that would mess up the checksums and (b) the DHCP 49411042SErik.Nordmark@Sun.COM * client conn is bound to INADDR_ANY so ip_fanout_udp() will 49511042SErik.Nordmark@Sun.COM * hand it the packet regardless. 49611042SErik.Nordmark@Sun.COM */ 49711042SErik.Nordmark@Sun.COM if (ill->ill_dhcpinit != 0 && 49811042SErik.Nordmark@Sun.COM ipha->ipha_version_and_hdr_length == IP_SIMPLE_HDR_VERSION && 49911042SErik.Nordmark@Sun.COM ipha->ipha_protocol == IPPROTO_UDP) { 50011042SErik.Nordmark@Sun.COM udpha_t *udpha; 50111042SErik.Nordmark@Sun.COM 50211042SErik.Nordmark@Sun.COM ipha = ip_pullup(mp, sizeof (ipha_t) + sizeof (udpha_t), ira); 50311042SErik.Nordmark@Sun.COM if (ipha == NULL) { 50411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 50511042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards - dhcp", mp, ill); 50611042SErik.Nordmark@Sun.COM freemsg(mp); 50711042SErik.Nordmark@Sun.COM return; 50811042SErik.Nordmark@Sun.COM } 50911042SErik.Nordmark@Sun.COM /* Reload since pullupmsg() can change b_rptr. */ 51011042SErik.Nordmark@Sun.COM udpha = (udpha_t *)&ipha[1]; 51111042SErik.Nordmark@Sun.COM 51211042SErik.Nordmark@Sun.COM if (ntohs(udpha->uha_dst_port) == IPPORT_BOOTPC) { 51311042SErik.Nordmark@Sun.COM DTRACE_PROBE2(ip4__dhcpinit__pkt, ill_t *, ill, 51411042SErik.Nordmark@Sun.COM mblk_t *, mp); 51511042SErik.Nordmark@Sun.COM /* 51611042SErik.Nordmark@Sun.COM * This assumes that we deliver to all conns for 51711042SErik.Nordmark@Sun.COM * multicast and broadcast packets. 51811042SErik.Nordmark@Sun.COM */ 51911042SErik.Nordmark@Sun.COM nexthop = INADDR_BROADCAST; 52011042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_DHCP_UNICAST; 52111042SErik.Nordmark@Sun.COM } 52211042SErik.Nordmark@Sun.COM } 52311042SErik.Nordmark@Sun.COM 52411042SErik.Nordmark@Sun.COM /* 52511042SErik.Nordmark@Sun.COM * If rsvpd is running, let RSVP daemon handle its processing 52611042SErik.Nordmark@Sun.COM * and forwarding of RSVP multicast/unicast packets. 52711042SErik.Nordmark@Sun.COM * If rsvpd is not running but mrouted is running, RSVP 52811042SErik.Nordmark@Sun.COM * multicast packets are forwarded as multicast traffic 52911042SErik.Nordmark@Sun.COM * and RSVP unicast packets are forwarded by unicast router. 53011042SErik.Nordmark@Sun.COM * If neither rsvpd nor mrouted is running, RSVP multicast 53111042SErik.Nordmark@Sun.COM * packets are not forwarded, but the unicast packets are 53211042SErik.Nordmark@Sun.COM * forwarded like unicast traffic. 53311042SErik.Nordmark@Sun.COM */ 53411042SErik.Nordmark@Sun.COM if (ipha->ipha_protocol == IPPROTO_RSVP && 53511042SErik.Nordmark@Sun.COM ipst->ips_ipcl_proto_fanout_v4[IPPROTO_RSVP].connf_head != NULL) { 53611042SErik.Nordmark@Sun.COM /* RSVP packet and rsvpd running. Treat as ours */ 53711042SErik.Nordmark@Sun.COM ip2dbg(("ip_input: RSVP for us: 0x%x\n", ntohl(nexthop))); 53811042SErik.Nordmark@Sun.COM /* 53911042SErik.Nordmark@Sun.COM * We use a multicast address to get the packet to 54011042SErik.Nordmark@Sun.COM * ire_recv_multicast_v4. There will not be a membership 54111042SErik.Nordmark@Sun.COM * check since we set IRAF_RSVP 54211042SErik.Nordmark@Sun.COM */ 54311042SErik.Nordmark@Sun.COM nexthop = htonl(INADDR_UNSPEC_GROUP); 54411042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_RSVP; 54511042SErik.Nordmark@Sun.COM } 54611042SErik.Nordmark@Sun.COM 54711042SErik.Nordmark@Sun.COM ill_input_short_v4(mp, ipha, &nexthop, ira, rtc); 54811042SErik.Nordmark@Sun.COM } 54911042SErik.Nordmark@Sun.COM 55011042SErik.Nordmark@Sun.COM /* 55111042SErik.Nordmark@Sun.COM * This is the tail-end of the full receive side packet handling. 55211042SErik.Nordmark@Sun.COM * It can be used directly when the configuration is simple. 55311042SErik.Nordmark@Sun.COM */ 55411042SErik.Nordmark@Sun.COM void 55511042SErik.Nordmark@Sun.COM ill_input_short_v4(mblk_t *mp, void *iph_arg, void *nexthop_arg, 55611042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, rtc_t *rtc) 55711042SErik.Nordmark@Sun.COM { 55811042SErik.Nordmark@Sun.COM ire_t *ire; 55911042SErik.Nordmark@Sun.COM uint_t opt_len; 56011042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 56111042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 56211042SErik.Nordmark@Sun.COM uint_t pkt_len; 56311042SErik.Nordmark@Sun.COM ssize_t len; 56411042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 56511042SErik.Nordmark@Sun.COM ipaddr_t nexthop = *(ipaddr_t *)nexthop_arg; 56611042SErik.Nordmark@Sun.COM ilb_stack_t *ilbs = ipst->ips_netstack->netstack_ilb; 56711457SErik.Nordmark@Sun.COM uint_t irr_flags; 56811042SErik.Nordmark@Sun.COM #define rptr ((uchar_t *)ipha) 56911042SErik.Nordmark@Sun.COM 57011042SErik.Nordmark@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 57111042SErik.Nordmark@Sun.COM 57211042SErik.Nordmark@Sun.COM /* 57311042SErik.Nordmark@Sun.COM * The following test for loopback is faster than 57411042SErik.Nordmark@Sun.COM * IP_LOOPBACK_ADDR(), because it avoids any bitwise 57511042SErik.Nordmark@Sun.COM * operations. 57611042SErik.Nordmark@Sun.COM * Note that these addresses are always in network byte order 57711042SErik.Nordmark@Sun.COM */ 57811042SErik.Nordmark@Sun.COM if (((*(uchar_t *)&ipha->ipha_dst) == 127) || 57911042SErik.Nordmark@Sun.COM ((*(uchar_t *)&ipha->ipha_src) == 127)) { 58011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 58111042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 58211042SErik.Nordmark@Sun.COM freemsg(mp); 58311042SErik.Nordmark@Sun.COM return; 58411042SErik.Nordmark@Sun.COM } 58511042SErik.Nordmark@Sun.COM 58611042SErik.Nordmark@Sun.COM len = mp->b_wptr - rptr; 58711042SErik.Nordmark@Sun.COM pkt_len = ira->ira_pktlen; 58811042SErik.Nordmark@Sun.COM 58911042SErik.Nordmark@Sun.COM /* multiple mblk or too short */ 59011042SErik.Nordmark@Sun.COM len -= pkt_len; 59111042SErik.Nordmark@Sun.COM if (len != 0) { 59211042SErik.Nordmark@Sun.COM mp = ip_check_length(mp, rptr, len, pkt_len, 59311042SErik.Nordmark@Sun.COM IP_SIMPLE_HDR_LENGTH, ira); 59411042SErik.Nordmark@Sun.COM if (mp == NULL) 59511042SErik.Nordmark@Sun.COM return; 59611042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 59711042SErik.Nordmark@Sun.COM } 59811042SErik.Nordmark@Sun.COM 59911042SErik.Nordmark@Sun.COM DTRACE_IP7(receive, mblk_t *, mp, conn_t *, NULL, void_ip_t *, 60011042SErik.Nordmark@Sun.COM ipha, __dtrace_ipsr_ill_t *, ill, ipha_t *, ipha, ip6_t *, NULL, 60111042SErik.Nordmark@Sun.COM int, 0); 60211042SErik.Nordmark@Sun.COM 60311042SErik.Nordmark@Sun.COM /* 60411042SErik.Nordmark@Sun.COM * The event for packets being received from a 'physical' 60511042SErik.Nordmark@Sun.COM * interface is placed after validation of the source and/or 60611042SErik.Nordmark@Sun.COM * destination address as being local so that packets can be 60711042SErik.Nordmark@Sun.COM * redirected to loopback addresses using ipnat. 60811042SErik.Nordmark@Sun.COM */ 60911042SErik.Nordmark@Sun.COM DTRACE_PROBE4(ip4__physical__in__start, 61011042SErik.Nordmark@Sun.COM ill_t *, ill, ill_t *, NULL, 61111042SErik.Nordmark@Sun.COM ipha_t *, ipha, mblk_t *, mp); 61211042SErik.Nordmark@Sun.COM 61311042SErik.Nordmark@Sun.COM if (HOOKS4_INTERESTED_PHYSICAL_IN(ipst)) { 61411042SErik.Nordmark@Sun.COM int ll_multicast = 0; 61511042SErik.Nordmark@Sun.COM int error; 61611042SErik.Nordmark@Sun.COM ipaddr_t orig_dst = ipha->ipha_dst; 61711042SErik.Nordmark@Sun.COM 61811042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_L2DST_MULTICAST) 61911042SErik.Nordmark@Sun.COM ll_multicast = HPE_MULTICAST; 62011042SErik.Nordmark@Sun.COM else if (ira->ira_flags & IRAF_L2DST_BROADCAST) 62111042SErik.Nordmark@Sun.COM ll_multicast = HPE_BROADCAST; 62211042SErik.Nordmark@Sun.COM 62311042SErik.Nordmark@Sun.COM FW_HOOKS(ipst->ips_ip4_physical_in_event, 62411042SErik.Nordmark@Sun.COM ipst->ips_ipv4firewall_physical_in, 62511042SErik.Nordmark@Sun.COM ill, NULL, ipha, mp, mp, ll_multicast, ipst, error); 62611042SErik.Nordmark@Sun.COM 62711042SErik.Nordmark@Sun.COM DTRACE_PROBE1(ip4__physical__in__end, mblk_t *, mp); 62811042SErik.Nordmark@Sun.COM 62911042SErik.Nordmark@Sun.COM if (mp == NULL) 63011042SErik.Nordmark@Sun.COM return; 63111042SErik.Nordmark@Sun.COM /* The length could have changed */ 63211042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 63311042SErik.Nordmark@Sun.COM ira->ira_pktlen = ntohs(ipha->ipha_length); 63411042SErik.Nordmark@Sun.COM pkt_len = ira->ira_pktlen; 63511042SErik.Nordmark@Sun.COM 63611042SErik.Nordmark@Sun.COM /* 63711042SErik.Nordmark@Sun.COM * In case the destination changed we override any previous 63811042SErik.Nordmark@Sun.COM * change to nexthop. 63911042SErik.Nordmark@Sun.COM */ 64011042SErik.Nordmark@Sun.COM if (orig_dst != ipha->ipha_dst) 64111042SErik.Nordmark@Sun.COM nexthop = ipha->ipha_dst; 64211042SErik.Nordmark@Sun.COM if (nexthop == INADDR_ANY) { 64311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInAddrErrors); 64411042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 64511042SErik.Nordmark@Sun.COM freemsg(mp); 64611042SErik.Nordmark@Sun.COM return; 64711042SErik.Nordmark@Sun.COM } 64811042SErik.Nordmark@Sun.COM } 64911042SErik.Nordmark@Sun.COM 65011042SErik.Nordmark@Sun.COM if (ipst->ips_ip4_observe.he_interested) { 65111042SErik.Nordmark@Sun.COM zoneid_t dzone; 65211042SErik.Nordmark@Sun.COM 65311042SErik.Nordmark@Sun.COM /* 65411042SErik.Nordmark@Sun.COM * On the inbound path the src zone will be unknown as 65511042SErik.Nordmark@Sun.COM * this packet has come from the wire. 65611042SErik.Nordmark@Sun.COM */ 65711042SErik.Nordmark@Sun.COM dzone = ip_get_zoneid_v4(nexthop, mp, ira, ALL_ZONES); 65811042SErik.Nordmark@Sun.COM ipobs_hook(mp, IPOBS_HOOK_INBOUND, ALL_ZONES, dzone, ill, ipst); 65911042SErik.Nordmark@Sun.COM } 66011042SErik.Nordmark@Sun.COM 66111042SErik.Nordmark@Sun.COM /* 66211042SErik.Nordmark@Sun.COM * If there is a good HW IP header checksum we clear the need 66311042SErik.Nordmark@Sun.COM * look at the IP header checksum. 66411042SErik.Nordmark@Sun.COM */ 66511042SErik.Nordmark@Sun.COM if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) && 66611042SErik.Nordmark@Sun.COM ILL_HCKSUM_CAPABLE(ill) && dohwcksum) { 66711042SErik.Nordmark@Sun.COM /* Header checksum was ok. Clear the flag */ 66811042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) &= ~HCK_IPV4_HDRCKSUM; 66911042SErik.Nordmark@Sun.COM ira->ira_flags &= ~IRAF_VERIFY_IP_CKSUM; 67011042SErik.Nordmark@Sun.COM } 67111042SErik.Nordmark@Sun.COM 67211042SErik.Nordmark@Sun.COM /* 67311042SErik.Nordmark@Sun.COM * Here we check to see if we machine is setup as 67411042SErik.Nordmark@Sun.COM * L3 loadbalancer and if the incoming packet is for a VIP 67511042SErik.Nordmark@Sun.COM * 67611042SErik.Nordmark@Sun.COM * Check the following: 67711042SErik.Nordmark@Sun.COM * - there is at least a rule 67811042SErik.Nordmark@Sun.COM * - protocol of the packet is supported 67911042SErik.Nordmark@Sun.COM */ 68011042SErik.Nordmark@Sun.COM if (ilb_has_rules(ilbs) && ILB_SUPP_L4(ipha->ipha_protocol)) { 68111042SErik.Nordmark@Sun.COM ipaddr_t lb_dst; 68211042SErik.Nordmark@Sun.COM int lb_ret; 68311042SErik.Nordmark@Sun.COM 68411042SErik.Nordmark@Sun.COM /* For convenience, we pull up the mblk. */ 68511042SErik.Nordmark@Sun.COM if (mp->b_cont != NULL) { 68611042SErik.Nordmark@Sun.COM if (pullupmsg(mp, -1) == 0) { 68711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 68811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards - pullupmsg", 68911042SErik.Nordmark@Sun.COM mp, ill); 69011042SErik.Nordmark@Sun.COM freemsg(mp); 69111042SErik.Nordmark@Sun.COM return; 69211042SErik.Nordmark@Sun.COM } 69311042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 69411042SErik.Nordmark@Sun.COM } 69511042SErik.Nordmark@Sun.COM 69611042SErik.Nordmark@Sun.COM /* 69711042SErik.Nordmark@Sun.COM * We just drop all fragments going to any VIP, at 69811042SErik.Nordmark@Sun.COM * least for now.... 69911042SErik.Nordmark@Sun.COM */ 70011042SErik.Nordmark@Sun.COM if (ntohs(ipha->ipha_fragment_offset_and_flags) & 70111042SErik.Nordmark@Sun.COM (IPH_MF | IPH_OFFSET)) { 70211042SErik.Nordmark@Sun.COM if (!ilb_rule_match_vip_v4(ilbs, nexthop, NULL)) { 70311042SErik.Nordmark@Sun.COM goto after_ilb; 70411042SErik.Nordmark@Sun.COM } 70511042SErik.Nordmark@Sun.COM 70611042SErik.Nordmark@Sun.COM ILB_KSTAT_UPDATE(ilbs, ip_frag_in, 1); 70711042SErik.Nordmark@Sun.COM ILB_KSTAT_UPDATE(ilbs, ip_frag_dropped, 1); 70811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 70911042SErik.Nordmark@Sun.COM ip_drop_input("ILB fragment", mp, ill); 71011042SErik.Nordmark@Sun.COM freemsg(mp); 71111042SErik.Nordmark@Sun.COM return; 71211042SErik.Nordmark@Sun.COM } 71311042SErik.Nordmark@Sun.COM lb_ret = ilb_check_v4(ilbs, ill, mp, ipha, ipha->ipha_protocol, 71411042SErik.Nordmark@Sun.COM (uint8_t *)ipha + IPH_HDR_LENGTH(ipha), &lb_dst); 71511042SErik.Nordmark@Sun.COM 71611042SErik.Nordmark@Sun.COM if (lb_ret == ILB_DROPPED) { 71711042SErik.Nordmark@Sun.COM /* Is this the right counter to increase? */ 71811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 71911042SErik.Nordmark@Sun.COM ip_drop_input("ILB_DROPPED", mp, ill); 72011042SErik.Nordmark@Sun.COM freemsg(mp); 72111042SErik.Nordmark@Sun.COM return; 72211042SErik.Nordmark@Sun.COM } 72311042SErik.Nordmark@Sun.COM if (lb_ret == ILB_BALANCED) { 72411042SErik.Nordmark@Sun.COM /* Set the dst to that of the chosen server */ 72511042SErik.Nordmark@Sun.COM nexthop = lb_dst; 72611042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 72711042SErik.Nordmark@Sun.COM } 72811042SErik.Nordmark@Sun.COM } 72911042SErik.Nordmark@Sun.COM 73011042SErik.Nordmark@Sun.COM after_ilb: 73111042SErik.Nordmark@Sun.COM opt_len = ipha->ipha_version_and_hdr_length - IP_SIMPLE_HDR_VERSION; 73211042SErik.Nordmark@Sun.COM ira->ira_ip_hdr_length = IP_SIMPLE_HDR_LENGTH; 73311042SErik.Nordmark@Sun.COM if (opt_len != 0) { 73411042SErik.Nordmark@Sun.COM int error = 0; 73511042SErik.Nordmark@Sun.COM 73611042SErik.Nordmark@Sun.COM ira->ira_ip_hdr_length += (opt_len << 2); 73711042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_IPV4_OPTIONS; 73811042SErik.Nordmark@Sun.COM 73911042SErik.Nordmark@Sun.COM /* IP Options present! Validate the length. */ 74011042SErik.Nordmark@Sun.COM mp = ip_check_optlen(mp, ipha, opt_len, pkt_len, ira); 74111042SErik.Nordmark@Sun.COM if (mp == NULL) 74211042SErik.Nordmark@Sun.COM return; 74311042SErik.Nordmark@Sun.COM 74411042SErik.Nordmark@Sun.COM /* Might have changed */ 74511042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 74611042SErik.Nordmark@Sun.COM 74711042SErik.Nordmark@Sun.COM /* Verify IP header checksum before parsing the options */ 74811042SErik.Nordmark@Sun.COM if ((ira->ira_flags & IRAF_VERIFY_IP_CKSUM) && 74911042SErik.Nordmark@Sun.COM ip_csum_hdr(ipha)) { 75011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 75111042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 75211042SErik.Nordmark@Sun.COM freemsg(mp); 75311042SErik.Nordmark@Sun.COM return; 75411042SErik.Nordmark@Sun.COM } 75511042SErik.Nordmark@Sun.COM ira->ira_flags &= ~IRAF_VERIFY_IP_CKSUM; 75611042SErik.Nordmark@Sun.COM 75711042SErik.Nordmark@Sun.COM /* 75811042SErik.Nordmark@Sun.COM * Go off to ip_input_options which returns the next hop 75911042SErik.Nordmark@Sun.COM * destination address, which may have been affected 76011042SErik.Nordmark@Sun.COM * by source routing. 76111042SErik.Nordmark@Sun.COM */ 76211042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_opt); 76311042SErik.Nordmark@Sun.COM 76411042SErik.Nordmark@Sun.COM nexthop = ip_input_options(ipha, nexthop, mp, ira, &error); 76511042SErik.Nordmark@Sun.COM if (error != 0) { 76611042SErik.Nordmark@Sun.COM /* 76711042SErik.Nordmark@Sun.COM * An ICMP error has been sent and the packet has 76811042SErik.Nordmark@Sun.COM * been dropped. 76911042SErik.Nordmark@Sun.COM */ 77011042SErik.Nordmark@Sun.COM return; 77111042SErik.Nordmark@Sun.COM } 77211042SErik.Nordmark@Sun.COM } 77311457SErik.Nordmark@Sun.COM 77411457SErik.Nordmark@Sun.COM if (ill->ill_flags & ILLF_ROUTER) 77511457SErik.Nordmark@Sun.COM irr_flags = IRR_ALLOCATE; 77611457SErik.Nordmark@Sun.COM else 77711457SErik.Nordmark@Sun.COM irr_flags = IRR_NONE; 77811457SErik.Nordmark@Sun.COM 77911042SErik.Nordmark@Sun.COM /* Can not use route cache with TX since the labels can differ */ 78011042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 78111042SErik.Nordmark@Sun.COM if (CLASSD(nexthop)) { 78211042SErik.Nordmark@Sun.COM ire = ire_multicast(ill); 78311042SErik.Nordmark@Sun.COM } else { 78411042SErik.Nordmark@Sun.COM /* Match destination and label */ 78511042SErik.Nordmark@Sun.COM ire = ire_route_recursive_v4(nexthop, 0, NULL, 78611042SErik.Nordmark@Sun.COM ALL_ZONES, ira->ira_tsl, MATCH_IRE_SECATTR, 78711457SErik.Nordmark@Sun.COM irr_flags, ira->ira_xmit_hint, ipst, NULL, NULL, 78811457SErik.Nordmark@Sun.COM NULL); 78911042SErik.Nordmark@Sun.COM } 79011042SErik.Nordmark@Sun.COM /* Update the route cache so we do the ire_refrele */ 79111042SErik.Nordmark@Sun.COM ASSERT(ire != NULL); 79211042SErik.Nordmark@Sun.COM if (rtc->rtc_ire != NULL) 79311042SErik.Nordmark@Sun.COM ire_refrele(rtc->rtc_ire); 79411042SErik.Nordmark@Sun.COM rtc->rtc_ire = ire; 79511042SErik.Nordmark@Sun.COM rtc->rtc_ipaddr = nexthop; 79611042SErik.Nordmark@Sun.COM } else if (nexthop == rtc->rtc_ipaddr) { 79711042SErik.Nordmark@Sun.COM /* Use the route cache */ 79811042SErik.Nordmark@Sun.COM ASSERT(rtc->rtc_ire != NULL); 79911042SErik.Nordmark@Sun.COM ire = rtc->rtc_ire; 80011042SErik.Nordmark@Sun.COM } else { 80111042SErik.Nordmark@Sun.COM /* Update the route cache */ 80211042SErik.Nordmark@Sun.COM if (CLASSD(nexthop)) { 80311042SErik.Nordmark@Sun.COM ire = ire_multicast(ill); 80411042SErik.Nordmark@Sun.COM } else { 80511042SErik.Nordmark@Sun.COM /* Just match the destination */ 80611457SErik.Nordmark@Sun.COM ire = ire_route_recursive_dstonly_v4(nexthop, irr_flags, 80711457SErik.Nordmark@Sun.COM ira->ira_xmit_hint, ipst); 80811042SErik.Nordmark@Sun.COM } 80911042SErik.Nordmark@Sun.COM ASSERT(ire != NULL); 81011042SErik.Nordmark@Sun.COM if (rtc->rtc_ire != NULL) 81111042SErik.Nordmark@Sun.COM ire_refrele(rtc->rtc_ire); 81211042SErik.Nordmark@Sun.COM rtc->rtc_ire = ire; 81311042SErik.Nordmark@Sun.COM rtc->rtc_ipaddr = nexthop; 81411042SErik.Nordmark@Sun.COM } 81511042SErik.Nordmark@Sun.COM 81611042SErik.Nordmark@Sun.COM ire->ire_ib_pkt_count++; 81711042SErik.Nordmark@Sun.COM 81811042SErik.Nordmark@Sun.COM /* 81911042SErik.Nordmark@Sun.COM * Based on ire_type and ire_flags call one of: 82011042SErik.Nordmark@Sun.COM * ire_recv_local_v4 - for IRE_LOCAL 82111042SErik.Nordmark@Sun.COM * ire_recv_loopback_v4 - for IRE_LOOPBACK 82211042SErik.Nordmark@Sun.COM * ire_recv_multirt_v4 - if RTF_MULTIRT 82311042SErik.Nordmark@Sun.COM * ire_recv_noroute_v4 - if RTF_REJECT or RTF_BLACHOLE 82411042SErik.Nordmark@Sun.COM * ire_recv_multicast_v4 - for IRE_MULTICAST 82511042SErik.Nordmark@Sun.COM * ire_recv_broadcast_v4 - for IRE_BROADCAST 82611042SErik.Nordmark@Sun.COM * ire_recv_noaccept_v4 - for ire_noaccept ones 82711042SErik.Nordmark@Sun.COM * ire_recv_forward_v4 - for the rest. 82811042SErik.Nordmark@Sun.COM */ 82911042SErik.Nordmark@Sun.COM (*ire->ire_recvfn)(ire, mp, ipha, ira); 83011042SErik.Nordmark@Sun.COM } 83111042SErik.Nordmark@Sun.COM #undef rptr 83211042SErik.Nordmark@Sun.COM 83311042SErik.Nordmark@Sun.COM /* 83411042SErik.Nordmark@Sun.COM * ire_recvfn for IREs that need forwarding 83511042SErik.Nordmark@Sun.COM */ 83611042SErik.Nordmark@Sun.COM void 83711042SErik.Nordmark@Sun.COM ire_recv_forward_v4(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 83811042SErik.Nordmark@Sun.COM { 83911042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 84011042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 84111042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 84211042SErik.Nordmark@Sun.COM ill_t *dst_ill; 84311042SErik.Nordmark@Sun.COM nce_t *nce; 84411042SErik.Nordmark@Sun.COM ipaddr_t src = ipha->ipha_src; 84511042SErik.Nordmark@Sun.COM uint32_t added_tx_len; 84611042SErik.Nordmark@Sun.COM uint32_t mtu, iremtu; 84711042SErik.Nordmark@Sun.COM 84811042SErik.Nordmark@Sun.COM if (ira->ira_flags & (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) { 84911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 85011042SErik.Nordmark@Sun.COM ip_drop_input("l2 multicast not forwarded", mp, ill); 85111042SErik.Nordmark@Sun.COM freemsg(mp); 85211042SErik.Nordmark@Sun.COM return; 85311042SErik.Nordmark@Sun.COM } 85411042SErik.Nordmark@Sun.COM 85511042SErik.Nordmark@Sun.COM if (!(ill->ill_flags & ILLF_ROUTER) && !ip_source_routed(ipha, ipst)) { 85611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 85711042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsForwProhibits", mp, ill); 85811042SErik.Nordmark@Sun.COM freemsg(mp); 85911042SErik.Nordmark@Sun.COM return; 86011042SErik.Nordmark@Sun.COM } 86111042SErik.Nordmark@Sun.COM 86211042SErik.Nordmark@Sun.COM /* 86311042SErik.Nordmark@Sun.COM * Either ire_nce_capable or ire_dep_parent would be set for the IRE 86411042SErik.Nordmark@Sun.COM * when it is found by ire_route_recursive, but that some other thread 86511042SErik.Nordmark@Sun.COM * could have changed the routes with the effect of clearing 86611042SErik.Nordmark@Sun.COM * ire_dep_parent. In that case we'd end up dropping the packet, or 86711042SErik.Nordmark@Sun.COM * finding a new nce below. 86811042SErik.Nordmark@Sun.COM * Get, allocate, or update the nce. 86911042SErik.Nordmark@Sun.COM * We get a refhold on ire_nce_cache as a result of this to avoid races 87011042SErik.Nordmark@Sun.COM * where ire_nce_cache is deleted. 87111042SErik.Nordmark@Sun.COM * 87211042SErik.Nordmark@Sun.COM * This ensures that we don't forward if the interface is down since 87311042SErik.Nordmark@Sun.COM * ipif_down removes all the nces. 87411042SErik.Nordmark@Sun.COM */ 87511042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 87611042SErik.Nordmark@Sun.COM nce = ire->ire_nce_cache; 87711042SErik.Nordmark@Sun.COM if (nce == NULL) { 87811042SErik.Nordmark@Sun.COM /* Not yet set up - try to set one up */ 87911042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 88011042SErik.Nordmark@Sun.COM (void) ire_revalidate_nce(ire); 88111042SErik.Nordmark@Sun.COM mutex_enter(&ire->ire_lock); 88211042SErik.Nordmark@Sun.COM nce = ire->ire_nce_cache; 88311042SErik.Nordmark@Sun.COM if (nce == NULL) { 88411042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 88511042SErik.Nordmark@Sun.COM /* The ire_dep_parent chain went bad, or no memory */ 88611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 88711042SErik.Nordmark@Sun.COM ip_drop_input("No ire_dep_parent", mp, ill); 88811042SErik.Nordmark@Sun.COM freemsg(mp); 88911042SErik.Nordmark@Sun.COM return; 89011042SErik.Nordmark@Sun.COM } 89111042SErik.Nordmark@Sun.COM } 89211042SErik.Nordmark@Sun.COM nce_refhold(nce); 89311042SErik.Nordmark@Sun.COM mutex_exit(&ire->ire_lock); 89411042SErik.Nordmark@Sun.COM 89511042SErik.Nordmark@Sun.COM if (nce->nce_is_condemned) { 89611042SErik.Nordmark@Sun.COM nce_t *nce1; 89711042SErik.Nordmark@Sun.COM 89811042SErik.Nordmark@Sun.COM nce1 = ire_handle_condemned_nce(nce, ire, ipha, NULL, B_FALSE); 89911042SErik.Nordmark@Sun.COM nce_refrele(nce); 90011042SErik.Nordmark@Sun.COM if (nce1 == NULL) { 90111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 90211042SErik.Nordmark@Sun.COM ip_drop_input("No nce", mp, ill); 90311042SErik.Nordmark@Sun.COM freemsg(mp); 90411042SErik.Nordmark@Sun.COM return; 90511042SErik.Nordmark@Sun.COM } 90611042SErik.Nordmark@Sun.COM nce = nce1; 90711042SErik.Nordmark@Sun.COM } 90811042SErik.Nordmark@Sun.COM dst_ill = nce->nce_ill; 90911042SErik.Nordmark@Sun.COM 91011042SErik.Nordmark@Sun.COM /* 91111042SErik.Nordmark@Sun.COM * Unless we are forwarding, drop the packet. 91211042SErik.Nordmark@Sun.COM * We have to let source routed packets through if they go out 91311042SErik.Nordmark@Sun.COM * the same interface i.e., they are 'ping -l' packets. 91411042SErik.Nordmark@Sun.COM */ 91511042SErik.Nordmark@Sun.COM if (!(dst_ill->ill_flags & ILLF_ROUTER) && 91611042SErik.Nordmark@Sun.COM !(ip_source_routed(ipha, ipst) && dst_ill == ill)) { 91711042SErik.Nordmark@Sun.COM if (ip_source_routed(ipha, ipst)) { 91811042SErik.Nordmark@Sun.COM ip_drop_input("ICMP_SOURCE_ROUTE_FAILED", mp, ill); 91911042SErik.Nordmark@Sun.COM icmp_unreachable(mp, ICMP_SOURCE_ROUTE_FAILED, ira); 92011042SErik.Nordmark@Sun.COM nce_refrele(nce); 92111042SErik.Nordmark@Sun.COM return; 92211042SErik.Nordmark@Sun.COM } 92311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 92411042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsForwProhibits", mp, ill); 92511042SErik.Nordmark@Sun.COM freemsg(mp); 92611042SErik.Nordmark@Sun.COM nce_refrele(nce); 92711042SErik.Nordmark@Sun.COM return; 92811042SErik.Nordmark@Sun.COM } 92911042SErik.Nordmark@Sun.COM 93011042SErik.Nordmark@Sun.COM if (ire->ire_zoneid != GLOBAL_ZONEID && ire->ire_zoneid != ALL_ZONES) { 93111042SErik.Nordmark@Sun.COM ipaddr_t dst = ipha->ipha_dst; 93211042SErik.Nordmark@Sun.COM 93311042SErik.Nordmark@Sun.COM ire->ire_ib_pkt_count--; 93411042SErik.Nordmark@Sun.COM /* 93511042SErik.Nordmark@Sun.COM * Should only use IREs that are visible from the 93611042SErik.Nordmark@Sun.COM * global zone for forwarding. 93711042SErik.Nordmark@Sun.COM * Take a source route into account the same way as ip_input 93811042SErik.Nordmark@Sun.COM * did. 93911042SErik.Nordmark@Sun.COM */ 94011042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_IPV4_OPTIONS) { 94111042SErik.Nordmark@Sun.COM int error = 0; 94211042SErik.Nordmark@Sun.COM 94311042SErik.Nordmark@Sun.COM dst = ip_input_options(ipha, dst, mp, ira, &error); 94411042SErik.Nordmark@Sun.COM ASSERT(error == 0); /* ip_input checked */ 94511042SErik.Nordmark@Sun.COM } 94611042SErik.Nordmark@Sun.COM ire = ire_route_recursive_v4(dst, 0, NULL, GLOBAL_ZONEID, 94711042SErik.Nordmark@Sun.COM ira->ira_tsl, MATCH_IRE_SECATTR, 94811457SErik.Nordmark@Sun.COM (ill->ill_flags & ILLF_ROUTER) ? IRR_ALLOCATE : IRR_NONE, 94911457SErik.Nordmark@Sun.COM ira->ira_xmit_hint, ipst, NULL, NULL, NULL); 95011042SErik.Nordmark@Sun.COM ire->ire_ib_pkt_count++; 95111042SErik.Nordmark@Sun.COM (*ire->ire_recvfn)(ire, mp, ipha, ira); 95211042SErik.Nordmark@Sun.COM ire_refrele(ire); 95311042SErik.Nordmark@Sun.COM nce_refrele(nce); 95411042SErik.Nordmark@Sun.COM return; 95511042SErik.Nordmark@Sun.COM } 95611042SErik.Nordmark@Sun.COM 95711042SErik.Nordmark@Sun.COM /* 95811042SErik.Nordmark@Sun.COM * ipIfStatsHCInForwDatagrams should only be increment if there 95911042SErik.Nordmark@Sun.COM * will be an attempt to forward the packet, which is why we 96011042SErik.Nordmark@Sun.COM * increment after the above condition has been checked. 96111042SErik.Nordmark@Sun.COM */ 96211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInForwDatagrams); 96311042SErik.Nordmark@Sun.COM 96411042SErik.Nordmark@Sun.COM /* Initiate Read side IPPF processing */ 96511042SErik.Nordmark@Sun.COM if (IPP_ENABLED(IPP_FWD_IN, ipst)) { 96611042SErik.Nordmark@Sun.COM /* ip_process translates an IS_UNDER_IPMP */ 96711042SErik.Nordmark@Sun.COM mp = ip_process(IPP_FWD_IN, mp, ill, ill); 96811042SErik.Nordmark@Sun.COM if (mp == NULL) { 96911042SErik.Nordmark@Sun.COM /* ip_drop_packet and MIB done */ 97011042SErik.Nordmark@Sun.COM ip2dbg(("ire_recv_forward_v4: pkt dropped/deferred " 97111042SErik.Nordmark@Sun.COM "during IPPF processing\n")); 97211042SErik.Nordmark@Sun.COM nce_refrele(nce); 97311042SErik.Nordmark@Sun.COM return; 97411042SErik.Nordmark@Sun.COM } 97511042SErik.Nordmark@Sun.COM } 97611042SErik.Nordmark@Sun.COM 97711042SErik.Nordmark@Sun.COM DTRACE_PROBE4(ip4__forwarding__start, 97811042SErik.Nordmark@Sun.COM ill_t *, ill, ill_t *, dst_ill, ipha_t *, ipha, mblk_t *, mp); 97911042SErik.Nordmark@Sun.COM 98011042SErik.Nordmark@Sun.COM if (HOOKS4_INTERESTED_FORWARDING(ipst)) { 98111042SErik.Nordmark@Sun.COM int error; 98211042SErik.Nordmark@Sun.COM 98311042SErik.Nordmark@Sun.COM FW_HOOKS(ipst->ips_ip4_forwarding_event, 98411042SErik.Nordmark@Sun.COM ipst->ips_ipv4firewall_forwarding, 98511042SErik.Nordmark@Sun.COM ill, dst_ill, ipha, mp, mp, 0, ipst, error); 98611042SErik.Nordmark@Sun.COM 98711042SErik.Nordmark@Sun.COM DTRACE_PROBE1(ip4__forwarding__end, mblk_t *, mp); 98811042SErik.Nordmark@Sun.COM 98911042SErik.Nordmark@Sun.COM if (mp == NULL) { 99011042SErik.Nordmark@Sun.COM nce_refrele(nce); 99111042SErik.Nordmark@Sun.COM return; 99211042SErik.Nordmark@Sun.COM } 99311042SErik.Nordmark@Sun.COM /* 99411042SErik.Nordmark@Sun.COM * Even if the destination was changed by the filter we use the 99511042SErik.Nordmark@Sun.COM * forwarding decision that was made based on the address 99611042SErik.Nordmark@Sun.COM * in ip_input. 99711042SErik.Nordmark@Sun.COM */ 99811042SErik.Nordmark@Sun.COM 99911042SErik.Nordmark@Sun.COM /* Might have changed */ 100011042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 100111042SErik.Nordmark@Sun.COM ira->ira_pktlen = ntohs(ipha->ipha_length); 100211042SErik.Nordmark@Sun.COM } 100311042SErik.Nordmark@Sun.COM 100411042SErik.Nordmark@Sun.COM /* Packet is being forwarded. Turning off hwcksum flag. */ 100511042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 100611042SErik.Nordmark@Sun.COM 100711042SErik.Nordmark@Sun.COM /* 100811042SErik.Nordmark@Sun.COM * Martian Address Filtering [RFC 1812, Section 5.3.7] 100911042SErik.Nordmark@Sun.COM * The loopback address check for both src and dst has already 101011042SErik.Nordmark@Sun.COM * been checked in ip_input 101111042SErik.Nordmark@Sun.COM * In the future one can envision adding RPF checks using number 3. 101211042SErik.Nordmark@Sun.COM * If we already checked the same source address we can skip this. 101311042SErik.Nordmark@Sun.COM */ 101411042SErik.Nordmark@Sun.COM if (!(ira->ira_flags & IRAF_VERIFIED_SRC) || 101511042SErik.Nordmark@Sun.COM src != ira->ira_verified_src) { 101611042SErik.Nordmark@Sun.COM switch (ipst->ips_src_check) { 101711042SErik.Nordmark@Sun.COM case 0: 101811042SErik.Nordmark@Sun.COM break; 101911042SErik.Nordmark@Sun.COM case 2: 102011042SErik.Nordmark@Sun.COM if (ip_type_v4(src, ipst) == IRE_BROADCAST) { 102111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 102211042SErik.Nordmark@Sun.COM ipIfStatsForwProhibits); 102311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 102411042SErik.Nordmark@Sun.COM ipIfStatsInAddrErrors); 102511042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 102611042SErik.Nordmark@Sun.COM freemsg(mp); 102711042SErik.Nordmark@Sun.COM nce_refrele(nce); 102811042SErik.Nordmark@Sun.COM return; 102911042SErik.Nordmark@Sun.COM } 103011042SErik.Nordmark@Sun.COM /* FALLTHRU */ 103111042SErik.Nordmark@Sun.COM 103211042SErik.Nordmark@Sun.COM case 1: 103311042SErik.Nordmark@Sun.COM if (CLASSD(src)) { 103411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 103511042SErik.Nordmark@Sun.COM ipIfStatsForwProhibits); 103611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 103711042SErik.Nordmark@Sun.COM ipIfStatsInAddrErrors); 103811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInAddrErrors", mp, ill); 103911042SErik.Nordmark@Sun.COM freemsg(mp); 104011042SErik.Nordmark@Sun.COM nce_refrele(nce); 104111042SErik.Nordmark@Sun.COM return; 104211042SErik.Nordmark@Sun.COM } 104311042SErik.Nordmark@Sun.COM break; 104411042SErik.Nordmark@Sun.COM } 104511042SErik.Nordmark@Sun.COM /* Remember for next packet */ 104611042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_VERIFIED_SRC; 104711042SErik.Nordmark@Sun.COM ira->ira_verified_src = src; 104811042SErik.Nordmark@Sun.COM } 104911042SErik.Nordmark@Sun.COM 105011042SErik.Nordmark@Sun.COM /* 105111042SErik.Nordmark@Sun.COM * Check if packet is going out the same link on which it arrived. 105211042SErik.Nordmark@Sun.COM * Means we might need to send a redirect. 105311042SErik.Nordmark@Sun.COM */ 105411042SErik.Nordmark@Sun.COM if (IS_ON_SAME_LAN(dst_ill, ill) && ipst->ips_ip_g_send_redirects) { 105511042SErik.Nordmark@Sun.COM ip_send_potential_redirect_v4(mp, ipha, ire, ira); 105611042SErik.Nordmark@Sun.COM } 105711042SErik.Nordmark@Sun.COM 105811042SErik.Nordmark@Sun.COM added_tx_len = 0; 105911042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 106011042SErik.Nordmark@Sun.COM mblk_t *mp1; 106111042SErik.Nordmark@Sun.COM uint32_t old_pkt_len = ira->ira_pktlen; 106211042SErik.Nordmark@Sun.COM 106311362SErik.Nordmark@Sun.COM /* Verify IP header checksum before adding/removing options */ 106411362SErik.Nordmark@Sun.COM if ((ira->ira_flags & IRAF_VERIFY_IP_CKSUM) && 106511362SErik.Nordmark@Sun.COM ip_csum_hdr(ipha)) { 106611362SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 106711362SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 106811362SErik.Nordmark@Sun.COM freemsg(mp); 106911362SErik.Nordmark@Sun.COM nce_refrele(nce); 107011362SErik.Nordmark@Sun.COM return; 107111362SErik.Nordmark@Sun.COM } 107211362SErik.Nordmark@Sun.COM ira->ira_flags &= ~IRAF_VERIFY_IP_CKSUM; 107311362SErik.Nordmark@Sun.COM 107411042SErik.Nordmark@Sun.COM /* 107511042SErik.Nordmark@Sun.COM * Check if it can be forwarded and add/remove 107611042SErik.Nordmark@Sun.COM * CIPSO options as needed. 107711042SErik.Nordmark@Sun.COM */ 107811042SErik.Nordmark@Sun.COM if ((mp1 = tsol_ip_forward(ire, mp, ira)) == NULL) { 107911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 108011042SErik.Nordmark@Sun.COM ip_drop_input("tsol_ip_forward", mp, ill); 108111042SErik.Nordmark@Sun.COM freemsg(mp); 108211042SErik.Nordmark@Sun.COM nce_refrele(nce); 108311042SErik.Nordmark@Sun.COM return; 108411042SErik.Nordmark@Sun.COM } 108511042SErik.Nordmark@Sun.COM /* 108611042SErik.Nordmark@Sun.COM * Size may have changed. Remember amount added in case 108711042SErik.Nordmark@Sun.COM * IP needs to send an ICMP too big. 108811042SErik.Nordmark@Sun.COM */ 108911042SErik.Nordmark@Sun.COM mp = mp1; 109011042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 109111042SErik.Nordmark@Sun.COM ira->ira_pktlen = ntohs(ipha->ipha_length); 109211042SErik.Nordmark@Sun.COM ira->ira_ip_hdr_length = IPH_HDR_LENGTH(ipha); 109311042SErik.Nordmark@Sun.COM if (ira->ira_pktlen > old_pkt_len) 109411042SErik.Nordmark@Sun.COM added_tx_len = ira->ira_pktlen - old_pkt_len; 109511042SErik.Nordmark@Sun.COM 109611042SErik.Nordmark@Sun.COM /* Options can have been added or removed */ 109711042SErik.Nordmark@Sun.COM if (ira->ira_ip_hdr_length != IP_SIMPLE_HDR_LENGTH) 109811042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_IPV4_OPTIONS; 109911042SErik.Nordmark@Sun.COM else 110011042SErik.Nordmark@Sun.COM ira->ira_flags &= ~IRAF_IPV4_OPTIONS; 110111042SErik.Nordmark@Sun.COM } 110211042SErik.Nordmark@Sun.COM 110311042SErik.Nordmark@Sun.COM mtu = dst_ill->ill_mtu; 110411042SErik.Nordmark@Sun.COM if ((iremtu = ire->ire_metrics.iulp_mtu) != 0 && iremtu < mtu) 110511042SErik.Nordmark@Sun.COM mtu = iremtu; 110611042SErik.Nordmark@Sun.COM ip_forward_xmit_v4(nce, ill, mp, ipha, ira, mtu, added_tx_len); 110711042SErik.Nordmark@Sun.COM nce_refrele(nce); 110811042SErik.Nordmark@Sun.COM } 110911042SErik.Nordmark@Sun.COM 111011042SErik.Nordmark@Sun.COM /* 111111042SErik.Nordmark@Sun.COM * Used for sending out unicast and multicast packets that are 111211042SErik.Nordmark@Sun.COM * forwarded. 111311042SErik.Nordmark@Sun.COM */ 111411042SErik.Nordmark@Sun.COM void 111511042SErik.Nordmark@Sun.COM ip_forward_xmit_v4(nce_t *nce, ill_t *ill, mblk_t *mp, ipha_t *ipha, 111611042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira, uint32_t mtu, uint32_t added_tx_len) 111711042SErik.Nordmark@Sun.COM { 111811042SErik.Nordmark@Sun.COM ill_t *dst_ill = nce->nce_ill; 111911042SErik.Nordmark@Sun.COM uint32_t pkt_len; 112011042SErik.Nordmark@Sun.COM uint32_t sum; 112111042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 112211042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 112311042SErik.Nordmark@Sun.COM iaflags_t ixaflags; 112411042SErik.Nordmark@Sun.COM 112511042SErik.Nordmark@Sun.COM if (ipha->ipha_ttl <= 1) { 112611042SErik.Nordmark@Sun.COM /* Perhaps the checksum was bad */ 112711042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_VERIFY_IP_CKSUM) && ip_csum_hdr(ipha)) { 112811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 112911042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 113011042SErik.Nordmark@Sun.COM freemsg(mp); 113111042SErik.Nordmark@Sun.COM return; 113211042SErik.Nordmark@Sun.COM } 113311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 113411042SErik.Nordmark@Sun.COM ip_drop_input("ICMP_TTL_EXCEEDED", mp, ill); 113511042SErik.Nordmark@Sun.COM icmp_time_exceeded(mp, ICMP_TTL_EXCEEDED, ira); 113611042SErik.Nordmark@Sun.COM return; 113711042SErik.Nordmark@Sun.COM } 113811042SErik.Nordmark@Sun.COM ipha->ipha_ttl--; 113911042SErik.Nordmark@Sun.COM /* Adjust the checksum to reflect the ttl decrement. */ 114011042SErik.Nordmark@Sun.COM sum = (int)ipha->ipha_hdr_checksum + IP_HDR_CSUM_TTL_ADJUST; 114111042SErik.Nordmark@Sun.COM ipha->ipha_hdr_checksum = (uint16_t)(sum + (sum >> 16)); 114211042SErik.Nordmark@Sun.COM 114311042SErik.Nordmark@Sun.COM /* Check if there are options to update */ 114411042SErik.Nordmark@Sun.COM if (iraflags & IRAF_IPV4_OPTIONS) { 114511042SErik.Nordmark@Sun.COM ASSERT(ipha->ipha_version_and_hdr_length != 114611042SErik.Nordmark@Sun.COM IP_SIMPLE_HDR_VERSION); 114711042SErik.Nordmark@Sun.COM ASSERT(!(iraflags & IRAF_VERIFY_IP_CKSUM)); 114811042SErik.Nordmark@Sun.COM 114911042SErik.Nordmark@Sun.COM if (!ip_forward_options(mp, ipha, dst_ill, ira)) { 115011042SErik.Nordmark@Sun.COM /* ipIfStatsForwProhibits and ip_drop_input done */ 115111042SErik.Nordmark@Sun.COM return; 115211042SErik.Nordmark@Sun.COM } 115311042SErik.Nordmark@Sun.COM 115411042SErik.Nordmark@Sun.COM ipha->ipha_hdr_checksum = 0; 115511042SErik.Nordmark@Sun.COM ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 115611042SErik.Nordmark@Sun.COM } 115711042SErik.Nordmark@Sun.COM 115811042SErik.Nordmark@Sun.COM /* Initiate Write side IPPF processing before any fragmentation */ 115911042SErik.Nordmark@Sun.COM if (IPP_ENABLED(IPP_FWD_OUT, ipst)) { 116011042SErik.Nordmark@Sun.COM /* ip_process translates an IS_UNDER_IPMP */ 116111042SErik.Nordmark@Sun.COM mp = ip_process(IPP_FWD_OUT, mp, dst_ill, dst_ill); 116211042SErik.Nordmark@Sun.COM if (mp == NULL) { 116311042SErik.Nordmark@Sun.COM /* ip_drop_packet and MIB done */ 116411042SErik.Nordmark@Sun.COM ip2dbg(("ire_recv_forward_v4: pkt dropped/deferred" \ 116511042SErik.Nordmark@Sun.COM " during IPPF processing\n")); 116611042SErik.Nordmark@Sun.COM return; 116711042SErik.Nordmark@Sun.COM } 116811042SErik.Nordmark@Sun.COM } 116911042SErik.Nordmark@Sun.COM 117011042SErik.Nordmark@Sun.COM pkt_len = ira->ira_pktlen; 117111042SErik.Nordmark@Sun.COM 117211042SErik.Nordmark@Sun.COM BUMP_MIB(dst_ill->ill_ip_mib, ipIfStatsHCOutForwDatagrams); 117311042SErik.Nordmark@Sun.COM 117411042SErik.Nordmark@Sun.COM ixaflags = IXAF_IS_IPV4 | IXAF_NO_DEV_FLOW_CTL; 117511042SErik.Nordmark@Sun.COM 117611042SErik.Nordmark@Sun.COM if (pkt_len > mtu) { 117711042SErik.Nordmark@Sun.COM /* 117811042SErik.Nordmark@Sun.COM * It needs fragging on its way out. If we haven't 117911042SErik.Nordmark@Sun.COM * verified the header checksum yet we do it now since 118011042SErik.Nordmark@Sun.COM * are going to put a surely good checksum in the 118111042SErik.Nordmark@Sun.COM * outgoing header, we have to make sure that it 118211042SErik.Nordmark@Sun.COM * was good coming in. 118311042SErik.Nordmark@Sun.COM */ 118411042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_VERIFY_IP_CKSUM) && ip_csum_hdr(ipha)) { 118511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 118611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 118711042SErik.Nordmark@Sun.COM freemsg(mp); 118811042SErik.Nordmark@Sun.COM return; 118911042SErik.Nordmark@Sun.COM } 119011042SErik.Nordmark@Sun.COM if (ipha->ipha_fragment_offset_and_flags & IPH_DF_HTONS) { 119111042SErik.Nordmark@Sun.COM BUMP_MIB(dst_ill->ill_ip_mib, ipIfStatsOutFragFails); 119211042SErik.Nordmark@Sun.COM ip_drop_output("ipIfStatsOutFragFails", mp, dst_ill); 119311042SErik.Nordmark@Sun.COM if (iraflags & IRAF_SYSTEM_LABELED) { 119411042SErik.Nordmark@Sun.COM /* 119511042SErik.Nordmark@Sun.COM * Remove any CIPSO option added by 119611042SErik.Nordmark@Sun.COM * tsol_ip_forward, and make sure we report 119711042SErik.Nordmark@Sun.COM * a path MTU so that there 119811042SErik.Nordmark@Sun.COM * is room to add such a CIPSO option for future 119911042SErik.Nordmark@Sun.COM * packets. 120011042SErik.Nordmark@Sun.COM */ 120111042SErik.Nordmark@Sun.COM mtu = tsol_pmtu_adjust(mp, mtu, added_tx_len, 120211042SErik.Nordmark@Sun.COM AF_INET); 120311042SErik.Nordmark@Sun.COM } 120411042SErik.Nordmark@Sun.COM 120511042SErik.Nordmark@Sun.COM icmp_frag_needed(mp, mtu, ira); 120611042SErik.Nordmark@Sun.COM return; 120711042SErik.Nordmark@Sun.COM } 120811042SErik.Nordmark@Sun.COM 120911042SErik.Nordmark@Sun.COM (void) ip_fragment_v4(mp, nce, ixaflags, pkt_len, mtu, 121011042SErik.Nordmark@Sun.COM ira->ira_xmit_hint, GLOBAL_ZONEID, 0, ip_xmit, NULL); 121111042SErik.Nordmark@Sun.COM return; 121211042SErik.Nordmark@Sun.COM } 121311042SErik.Nordmark@Sun.COM 121411042SErik.Nordmark@Sun.COM ASSERT(pkt_len == ntohs(((ipha_t *)mp->b_rptr)->ipha_length)); 121511042SErik.Nordmark@Sun.COM if (iraflags & IRAF_LOOPBACK_COPY) { 121611042SErik.Nordmark@Sun.COM /* 121711042SErik.Nordmark@Sun.COM * IXAF_NO_LOOP_ZONEID is not set hence 7th arg 121811042SErik.Nordmark@Sun.COM * is don't care 121911042SErik.Nordmark@Sun.COM */ 122011042SErik.Nordmark@Sun.COM (void) ip_postfrag_loopcheck(mp, nce, 122111042SErik.Nordmark@Sun.COM ixaflags | IXAF_LOOPBACK_COPY, 122211042SErik.Nordmark@Sun.COM pkt_len, ira->ira_xmit_hint, GLOBAL_ZONEID, 0, NULL); 122311042SErik.Nordmark@Sun.COM } else { 122411042SErik.Nordmark@Sun.COM (void) ip_xmit(mp, nce, ixaflags, pkt_len, ira->ira_xmit_hint, 122511042SErik.Nordmark@Sun.COM GLOBAL_ZONEID, 0, NULL); 122611042SErik.Nordmark@Sun.COM } 122711042SErik.Nordmark@Sun.COM } 122811042SErik.Nordmark@Sun.COM 122911042SErik.Nordmark@Sun.COM /* 123011042SErik.Nordmark@Sun.COM * ire_recvfn for RTF_REJECT and RTF_BLACKHOLE routes, including IRE_NOROUTE, 123111042SErik.Nordmark@Sun.COM * which is what ire_route_recursive returns when there is no matching ire. 123211042SErik.Nordmark@Sun.COM * Send ICMP unreachable unless blackhole. 123311042SErik.Nordmark@Sun.COM */ 123411042SErik.Nordmark@Sun.COM void 123511042SErik.Nordmark@Sun.COM ire_recv_noroute_v4(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 123611042SErik.Nordmark@Sun.COM { 123711042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 123811042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 123911042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 124011042SErik.Nordmark@Sun.COM 124111042SErik.Nordmark@Sun.COM /* Would we have forwarded this packet if we had a route? */ 124211042SErik.Nordmark@Sun.COM if (ira->ira_flags & (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST)) { 124311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 124411042SErik.Nordmark@Sun.COM ip_drop_input("l2 multicast not forwarded", mp, ill); 124511042SErik.Nordmark@Sun.COM freemsg(mp); 124611042SErik.Nordmark@Sun.COM return; 124711042SErik.Nordmark@Sun.COM } 124811042SErik.Nordmark@Sun.COM 124911042SErik.Nordmark@Sun.COM if (!(ill->ill_flags & ILLF_ROUTER)) { 125011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 125111042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsForwProhibits", mp, ill); 125211042SErik.Nordmark@Sun.COM freemsg(mp); 125311042SErik.Nordmark@Sun.COM return; 125411042SErik.Nordmark@Sun.COM } 125511042SErik.Nordmark@Sun.COM /* 125611042SErik.Nordmark@Sun.COM * If we had a route this could have been forwarded. Count as such. 125711042SErik.Nordmark@Sun.COM * 125811042SErik.Nordmark@Sun.COM * ipIfStatsHCInForwDatagrams should only be increment if there 125911042SErik.Nordmark@Sun.COM * will be an attempt to forward the packet, which is why we 126011042SErik.Nordmark@Sun.COM * increment after the above condition has been checked. 126111042SErik.Nordmark@Sun.COM */ 126211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInForwDatagrams); 126311042SErik.Nordmark@Sun.COM 126411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInNoRoutes); 126511042SErik.Nordmark@Sun.COM 126611042SErik.Nordmark@Sun.COM ip_rts_change(RTM_MISS, ipha->ipha_dst, 0, 0, 0, 0, 0, 0, RTA_DST, 126711042SErik.Nordmark@Sun.COM ipst); 126811042SErik.Nordmark@Sun.COM 126911042SErik.Nordmark@Sun.COM if (ire->ire_flags & RTF_BLACKHOLE) { 127011042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInNoRoutes RTF_BLACKHOLE", mp, ill); 127111042SErik.Nordmark@Sun.COM freemsg(mp); 127211042SErik.Nordmark@Sun.COM } else { 127311042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInNoRoutes RTF_REJECT", mp, ill); 127411042SErik.Nordmark@Sun.COM 127511042SErik.Nordmark@Sun.COM if (ip_source_routed(ipha, ipst)) { 127611042SErik.Nordmark@Sun.COM icmp_unreachable(mp, ICMP_SOURCE_ROUTE_FAILED, ira); 127711042SErik.Nordmark@Sun.COM } else { 127811042SErik.Nordmark@Sun.COM icmp_unreachable(mp, ICMP_HOST_UNREACHABLE, ira); 127911042SErik.Nordmark@Sun.COM } 128011042SErik.Nordmark@Sun.COM } 128111042SErik.Nordmark@Sun.COM } 128211042SErik.Nordmark@Sun.COM 128311042SErik.Nordmark@Sun.COM /* 128411042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_LOCALs marked with ire_noaccept. Such IREs are used for 128511042SErik.Nordmark@Sun.COM * VRRP when in noaccept mode. 128611042SErik.Nordmark@Sun.COM * We silently drop the packet. ARP handles packets even if noaccept is set. 128711042SErik.Nordmark@Sun.COM */ 128811042SErik.Nordmark@Sun.COM /* ARGSUSED */ 128911042SErik.Nordmark@Sun.COM void 129011042SErik.Nordmark@Sun.COM ire_recv_noaccept_v4(ire_t *ire, mblk_t *mp, void *iph_arg, 129111042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira) 129211042SErik.Nordmark@Sun.COM { 129311042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 129411042SErik.Nordmark@Sun.COM 129511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 129611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards - noaccept", mp, ill); 129711042SErik.Nordmark@Sun.COM freemsg(mp); 129811042SErik.Nordmark@Sun.COM } 129911042SErik.Nordmark@Sun.COM 130011042SErik.Nordmark@Sun.COM /* 130111042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_BROADCAST. 130211042SErik.Nordmark@Sun.COM */ 130311042SErik.Nordmark@Sun.COM void 130411042SErik.Nordmark@Sun.COM ire_recv_broadcast_v4(ire_t *ire, mblk_t *mp, void *iph_arg, 130511042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira) 130611042SErik.Nordmark@Sun.COM { 130711042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 130811042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 130911042SErik.Nordmark@Sun.COM ill_t *dst_ill = ire->ire_ill; 131011042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 131111042SErik.Nordmark@Sun.COM ire_t *alt_ire; 131211042SErik.Nordmark@Sun.COM nce_t *nce; 131311042SErik.Nordmark@Sun.COM ipaddr_t ipha_dst; 131411042SErik.Nordmark@Sun.COM 131511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInBcastPkts); 131611042SErik.Nordmark@Sun.COM 131711042SErik.Nordmark@Sun.COM /* Tag for higher-level protocols */ 131811042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_BROADCAST; 131911042SErik.Nordmark@Sun.COM 132011042SErik.Nordmark@Sun.COM /* 132111042SErik.Nordmark@Sun.COM * Whether local or directed broadcast forwarding: don't allow 132211042SErik.Nordmark@Sun.COM * for TCP. 132311042SErik.Nordmark@Sun.COM */ 132411042SErik.Nordmark@Sun.COM if (ipha->ipha_protocol == IPPROTO_TCP) { 132511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 132611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 132711042SErik.Nordmark@Sun.COM freemsg(mp); 132811042SErik.Nordmark@Sun.COM return; 132911042SErik.Nordmark@Sun.COM } 133011042SErik.Nordmark@Sun.COM 133111042SErik.Nordmark@Sun.COM /* 133211042SErik.Nordmark@Sun.COM * So that we don't end up with dups, only one ill an IPMP group is 133311042SErik.Nordmark@Sun.COM * nominated to receive broadcast traffic. 133411042SErik.Nordmark@Sun.COM * If we have no cast_ill we are liberal and accept everything. 133511042SErik.Nordmark@Sun.COM */ 133611042SErik.Nordmark@Sun.COM if (IS_UNDER_IPMP(ill)) { 133711042SErik.Nordmark@Sun.COM /* For an under ill_grp can change under lock */ 133811042SErik.Nordmark@Sun.COM rw_enter(&ipst->ips_ill_g_lock, RW_READER); 133911042SErik.Nordmark@Sun.COM if (!ill->ill_nom_cast && ill->ill_grp != NULL && 134011042SErik.Nordmark@Sun.COM ill->ill_grp->ig_cast_ill != NULL) { 134111042SErik.Nordmark@Sun.COM rw_exit(&ipst->ips_ill_g_lock); 134211042SErik.Nordmark@Sun.COM /* No MIB since this is normal operation */ 134311042SErik.Nordmark@Sun.COM ip_drop_input("not nom_cast", mp, ill); 134411042SErik.Nordmark@Sun.COM freemsg(mp); 134511042SErik.Nordmark@Sun.COM return; 134611042SErik.Nordmark@Sun.COM } 134711042SErik.Nordmark@Sun.COM rw_exit(&ipst->ips_ill_g_lock); 134811042SErik.Nordmark@Sun.COM 134911042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill_get_upper_ifindex(ill); 135011042SErik.Nordmark@Sun.COM } 135111042SErik.Nordmark@Sun.COM 135211042SErik.Nordmark@Sun.COM /* 135311042SErik.Nordmark@Sun.COM * After reassembly and IPsec we will need to duplicate the 135411042SErik.Nordmark@Sun.COM * broadcast packet for all matching zones on the ill. 135511042SErik.Nordmark@Sun.COM */ 135611042SErik.Nordmark@Sun.COM ira->ira_zoneid = ALL_ZONES; 135711042SErik.Nordmark@Sun.COM 135811042SErik.Nordmark@Sun.COM /* 135911042SErik.Nordmark@Sun.COM * Check for directed broadcast i.e. ire->ire_ill is different than 136011042SErik.Nordmark@Sun.COM * the incoming ill. 136111042SErik.Nordmark@Sun.COM * The same broadcast address can be assigned to multiple interfaces 136211042SErik.Nordmark@Sun.COM * so have to check explicitly for that case by looking up the alt_ire 136311042SErik.Nordmark@Sun.COM */ 136411042SErik.Nordmark@Sun.COM if (dst_ill == ill && !(ire->ire_flags & RTF_MULTIRT)) { 136511042SErik.Nordmark@Sun.COM /* Reassemble on the ill on which the packet arrived */ 136611042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 136711042SErik.Nordmark@Sun.COM /* Restore */ 136811042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 136911042SErik.Nordmark@Sun.COM return; 137011042SErik.Nordmark@Sun.COM } 137111042SErik.Nordmark@Sun.COM 137211042SErik.Nordmark@Sun.COM /* Is there an IRE_BROADCAST on the incoming ill? */ 137311042SErik.Nordmark@Sun.COM ipha_dst = ((ira->ira_flags & IRAF_DHCP_UNICAST) ? INADDR_BROADCAST : 137411042SErik.Nordmark@Sun.COM ipha->ipha_dst); 137511042SErik.Nordmark@Sun.COM alt_ire = ire_ftable_lookup_v4(ipha_dst, 0, 0, IRE_BROADCAST, ill, 137611042SErik.Nordmark@Sun.COM ALL_ZONES, ira->ira_tsl, 137711042SErik.Nordmark@Sun.COM MATCH_IRE_TYPE|MATCH_IRE_ILL|MATCH_IRE_SECATTR, 0, ipst, NULL); 137811042SErik.Nordmark@Sun.COM if (alt_ire != NULL) { 137911042SErik.Nordmark@Sun.COM /* Not a directed broadcast */ 138011042SErik.Nordmark@Sun.COM /* 138111042SErik.Nordmark@Sun.COM * In the special case of multirouted broadcast 138211042SErik.Nordmark@Sun.COM * packets, we unconditionally need to "gateway" 138311042SErik.Nordmark@Sun.COM * them to the appropriate interface here so that reassembly 138411042SErik.Nordmark@Sun.COM * works. We know that the IRE_BROADCAST on cgtp0 doesn't 138511042SErik.Nordmark@Sun.COM * have RTF_MULTIRT set so we look for such an IRE in the 138611042SErik.Nordmark@Sun.COM * bucket. 138711042SErik.Nordmark@Sun.COM */ 138811042SErik.Nordmark@Sun.COM if (alt_ire->ire_flags & RTF_MULTIRT) { 138911042SErik.Nordmark@Sun.COM irb_t *irb; 139011042SErik.Nordmark@Sun.COM ire_t *ire1; 139111042SErik.Nordmark@Sun.COM 139211042SErik.Nordmark@Sun.COM irb = ire->ire_bucket; 139311042SErik.Nordmark@Sun.COM irb_refhold(irb); 139411042SErik.Nordmark@Sun.COM for (ire1 = irb->irb_ire; ire1 != NULL; 139511042SErik.Nordmark@Sun.COM ire1 = ire1->ire_next) { 139611042SErik.Nordmark@Sun.COM if (IRE_IS_CONDEMNED(ire1)) 139711042SErik.Nordmark@Sun.COM continue; 139811042SErik.Nordmark@Sun.COM if (!(ire1->ire_type & IRE_BROADCAST) || 139911042SErik.Nordmark@Sun.COM (ire1->ire_flags & RTF_MULTIRT)) 140011042SErik.Nordmark@Sun.COM continue; 140111042SErik.Nordmark@Sun.COM ill = ire1->ire_ill; 140211042SErik.Nordmark@Sun.COM ill_refhold(ill); 140311042SErik.Nordmark@Sun.COM break; 140411042SErik.Nordmark@Sun.COM } 140511042SErik.Nordmark@Sun.COM irb_refrele(irb); 140611042SErik.Nordmark@Sun.COM if (ire1 != NULL) { 140711042SErik.Nordmark@Sun.COM ill_t *orig_ill = ira->ira_ill; 140811042SErik.Nordmark@Sun.COM 140911042SErik.Nordmark@Sun.COM ire_refrele(alt_ire); 141011042SErik.Nordmark@Sun.COM /* Reassemble on the new ill */ 141111042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 141211042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 141311042SErik.Nordmark@Sun.COM ill_refrele(ill); 141411042SErik.Nordmark@Sun.COM /* Restore */ 141511042SErik.Nordmark@Sun.COM ira->ira_ill = orig_ill; 141611042SErik.Nordmark@Sun.COM ira->ira_ruifindex = 141711042SErik.Nordmark@Sun.COM orig_ill->ill_phyint->phyint_ifindex; 141811042SErik.Nordmark@Sun.COM return; 141911042SErik.Nordmark@Sun.COM } 142011042SErik.Nordmark@Sun.COM } 142111042SErik.Nordmark@Sun.COM ire_refrele(alt_ire); 142211042SErik.Nordmark@Sun.COM /* Reassemble on the ill on which the packet arrived */ 142311042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 142411042SErik.Nordmark@Sun.COM goto done; 142511042SErik.Nordmark@Sun.COM } 142611042SErik.Nordmark@Sun.COM 142711042SErik.Nordmark@Sun.COM /* 142811042SErik.Nordmark@Sun.COM * This is a directed broadcast 142911042SErik.Nordmark@Sun.COM * 143011042SErik.Nordmark@Sun.COM * If directed broadcast is allowed, then forward the packet out 143111042SErik.Nordmark@Sun.COM * the destination interface with IXAF_LOOPBACK_COPY set. That will 143211042SErik.Nordmark@Sun.COM * result in ip_input() receiving a copy of the packet on the 143311042SErik.Nordmark@Sun.COM * appropriate ill. (We could optimize this to avoid the extra trip 143411042SErik.Nordmark@Sun.COM * via ip_input(), but since directed broadcasts are normally disabled 143511042SErik.Nordmark@Sun.COM * it doesn't make sense to optimize it.) 143611042SErik.Nordmark@Sun.COM */ 143711042SErik.Nordmark@Sun.COM if (!ipst->ips_ip_g_forward_directed_bcast || 143811042SErik.Nordmark@Sun.COM (ira->ira_flags & (IRAF_L2DST_MULTICAST|IRAF_L2DST_BROADCAST))) { 143911042SErik.Nordmark@Sun.COM ip_drop_input("directed broadcast not allowed", mp, ill); 144011042SErik.Nordmark@Sun.COM freemsg(mp); 144111042SErik.Nordmark@Sun.COM goto done; 144211042SErik.Nordmark@Sun.COM } 144311042SErik.Nordmark@Sun.COM if ((ira->ira_flags & IRAF_VERIFY_IP_CKSUM) && ip_csum_hdr(ipha)) { 144411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 144511042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 144611042SErik.Nordmark@Sun.COM freemsg(mp); 144711042SErik.Nordmark@Sun.COM goto done; 144811042SErik.Nordmark@Sun.COM } 144911042SErik.Nordmark@Sun.COM 145011042SErik.Nordmark@Sun.COM /* 145111042SErik.Nordmark@Sun.COM * Clear the indication that this may have hardware 145211042SErik.Nordmark@Sun.COM * checksum as we are not using it for forwarding. 145311042SErik.Nordmark@Sun.COM */ 145411042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 145511042SErik.Nordmark@Sun.COM 145611042SErik.Nordmark@Sun.COM /* 145711042SErik.Nordmark@Sun.COM * Adjust ttl to 2 (1+1 - the forward engine will decrement it by one. 145811042SErik.Nordmark@Sun.COM */ 145911042SErik.Nordmark@Sun.COM ipha->ipha_ttl = ipst->ips_ip_broadcast_ttl + 1; 146011042SErik.Nordmark@Sun.COM ipha->ipha_hdr_checksum = 0; 146111042SErik.Nordmark@Sun.COM ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 146211042SErik.Nordmark@Sun.COM 146311042SErik.Nordmark@Sun.COM /* 146411042SErik.Nordmark@Sun.COM * We use ip_forward_xmit to do any fragmentation. 146511042SErik.Nordmark@Sun.COM * and loopback copy on the outbound interface. 146611042SErik.Nordmark@Sun.COM * 146711042SErik.Nordmark@Sun.COM * Make it so that IXAF_LOOPBACK_COPY to be set on transmit side. 146811042SErik.Nordmark@Sun.COM */ 146911042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_LOOPBACK_COPY; 147011042SErik.Nordmark@Sun.COM 147111042SErik.Nordmark@Sun.COM nce = arp_nce_init(dst_ill, ipha->ipha_dst, IRE_BROADCAST); 147211042SErik.Nordmark@Sun.COM if (nce == NULL) { 147311042SErik.Nordmark@Sun.COM BUMP_MIB(dst_ill->ill_ip_mib, ipIfStatsOutDiscards); 147411042SErik.Nordmark@Sun.COM ip_drop_output("No nce", mp, dst_ill); 147511042SErik.Nordmark@Sun.COM freemsg(mp); 147611042SErik.Nordmark@Sun.COM goto done; 147711042SErik.Nordmark@Sun.COM } 147811042SErik.Nordmark@Sun.COM 147911042SErik.Nordmark@Sun.COM ip_forward_xmit_v4(nce, ill, mp, ipha, ira, dst_ill->ill_mtu, 0); 148011042SErik.Nordmark@Sun.COM nce_refrele(nce); 148111042SErik.Nordmark@Sun.COM done: 148211042SErik.Nordmark@Sun.COM /* Restore */ 148311042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 148411042SErik.Nordmark@Sun.COM } 148511042SErik.Nordmark@Sun.COM 148611042SErik.Nordmark@Sun.COM /* 148711042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_MULTICAST. 148811042SErik.Nordmark@Sun.COM */ 148911042SErik.Nordmark@Sun.COM void 149011042SErik.Nordmark@Sun.COM ire_recv_multicast_v4(ire_t *ire, mblk_t *mp, void *iph_arg, 149111042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira) 149211042SErik.Nordmark@Sun.COM { 149311042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 149411042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 149511042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 149611042SErik.Nordmark@Sun.COM 149711042SErik.Nordmark@Sun.COM ASSERT(ire->ire_ill == ira->ira_ill); 149811042SErik.Nordmark@Sun.COM 149911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInMcastPkts); 150011042SErik.Nordmark@Sun.COM UPDATE_MIB(ill->ill_ip_mib, ipIfStatsHCInMcastOctets, ira->ira_pktlen); 150111042SErik.Nordmark@Sun.COM 150211042SErik.Nordmark@Sun.COM /* RSVP hook */ 150311042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_RSVP) 150411042SErik.Nordmark@Sun.COM goto forus; 150511042SErik.Nordmark@Sun.COM 150611042SErik.Nordmark@Sun.COM /* Tag for higher-level protocols */ 150711042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_MULTICAST; 150811042SErik.Nordmark@Sun.COM 150911042SErik.Nordmark@Sun.COM /* 151011042SErik.Nordmark@Sun.COM * So that we don't end up with dups, only one ill an IPMP group is 151111042SErik.Nordmark@Sun.COM * nominated to receive multicast traffic. 151211042SErik.Nordmark@Sun.COM * If we have no cast_ill we are liberal and accept everything. 151311042SErik.Nordmark@Sun.COM */ 151411042SErik.Nordmark@Sun.COM if (IS_UNDER_IPMP(ill)) { 151511042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 151611042SErik.Nordmark@Sun.COM 151711042SErik.Nordmark@Sun.COM /* For an under ill_grp can change under lock */ 151811042SErik.Nordmark@Sun.COM rw_enter(&ipst->ips_ill_g_lock, RW_READER); 151911042SErik.Nordmark@Sun.COM if (!ill->ill_nom_cast && ill->ill_grp != NULL && 152011042SErik.Nordmark@Sun.COM ill->ill_grp->ig_cast_ill != NULL) { 152111042SErik.Nordmark@Sun.COM rw_exit(&ipst->ips_ill_g_lock); 152211042SErik.Nordmark@Sun.COM ip_drop_input("not on cast ill", mp, ill); 152311042SErik.Nordmark@Sun.COM freemsg(mp); 152411042SErik.Nordmark@Sun.COM return; 152511042SErik.Nordmark@Sun.COM } 152611042SErik.Nordmark@Sun.COM rw_exit(&ipst->ips_ill_g_lock); 152711042SErik.Nordmark@Sun.COM /* 152811042SErik.Nordmark@Sun.COM * We switch to the upper ill so that mrouter and hasmembers 152911042SErik.Nordmark@Sun.COM * can operate on upper here and in ip_input_multicast. 153011042SErik.Nordmark@Sun.COM */ 153111042SErik.Nordmark@Sun.COM ill = ipmp_ill_hold_ipmp_ill(ill); 153211042SErik.Nordmark@Sun.COM if (ill != NULL) { 153311042SErik.Nordmark@Sun.COM ASSERT(ill != ira->ira_ill); 153411042SErik.Nordmark@Sun.COM ASSERT(ire->ire_ill == ira->ira_ill); 153511042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 153611042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 153711042SErik.Nordmark@Sun.COM } else { 153811042SErik.Nordmark@Sun.COM ill = ira->ira_ill; 153911042SErik.Nordmark@Sun.COM } 154011042SErik.Nordmark@Sun.COM } 154111042SErik.Nordmark@Sun.COM 154211042SErik.Nordmark@Sun.COM /* 154311042SErik.Nordmark@Sun.COM * Check if we are a multicast router - send ip_mforward a copy of 154411042SErik.Nordmark@Sun.COM * the packet. 154511042SErik.Nordmark@Sun.COM * Due to mroute_decap tunnels we consider forwarding packets even if 154611042SErik.Nordmark@Sun.COM * mrouted has not joined the allmulti group on this interface. 154711042SErik.Nordmark@Sun.COM */ 154811042SErik.Nordmark@Sun.COM if (ipst->ips_ip_g_mrouter) { 154911042SErik.Nordmark@Sun.COM int retval; 155011042SErik.Nordmark@Sun.COM 155111042SErik.Nordmark@Sun.COM /* 155211042SErik.Nordmark@Sun.COM * Clear the indication that this may have hardware 155311042SErik.Nordmark@Sun.COM * checksum as we are not using it for forwarding. 155411042SErik.Nordmark@Sun.COM */ 155511042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 155611042SErik.Nordmark@Sun.COM 155711042SErik.Nordmark@Sun.COM /* 155811042SErik.Nordmark@Sun.COM * ip_mforward helps us make these distinctions: If received 155911042SErik.Nordmark@Sun.COM * on tunnel and not IGMP, then drop. 156011042SErik.Nordmark@Sun.COM * If IGMP packet, then don't check membership 156111042SErik.Nordmark@Sun.COM * If received on a phyint and IGMP or PIM, then 156211042SErik.Nordmark@Sun.COM * don't check membership 156311042SErik.Nordmark@Sun.COM */ 156411042SErik.Nordmark@Sun.COM retval = ip_mforward(mp, ira); 156511042SErik.Nordmark@Sun.COM /* ip_mforward updates mib variables if needed */ 156611042SErik.Nordmark@Sun.COM 156711042SErik.Nordmark@Sun.COM switch (retval) { 156811042SErik.Nordmark@Sun.COM case 0: 156911042SErik.Nordmark@Sun.COM /* 157011042SErik.Nordmark@Sun.COM * pkt is okay and arrived on phyint. 157111042SErik.Nordmark@Sun.COM * 157211042SErik.Nordmark@Sun.COM * If we are running as a multicast router 157311042SErik.Nordmark@Sun.COM * we need to see all IGMP and/or PIM packets. 157411042SErik.Nordmark@Sun.COM */ 157511042SErik.Nordmark@Sun.COM if ((ipha->ipha_protocol == IPPROTO_IGMP) || 157611042SErik.Nordmark@Sun.COM (ipha->ipha_protocol == IPPROTO_PIM)) { 157711042SErik.Nordmark@Sun.COM goto forus; 157811042SErik.Nordmark@Sun.COM } 157911042SErik.Nordmark@Sun.COM break; 158011042SErik.Nordmark@Sun.COM case -1: 158111042SErik.Nordmark@Sun.COM /* pkt is mal-formed, toss it */ 158211042SErik.Nordmark@Sun.COM freemsg(mp); 158311042SErik.Nordmark@Sun.COM goto done; 158411042SErik.Nordmark@Sun.COM case 1: 158511042SErik.Nordmark@Sun.COM /* 158611042SErik.Nordmark@Sun.COM * pkt is okay and arrived on a tunnel 158711042SErik.Nordmark@Sun.COM * 158811042SErik.Nordmark@Sun.COM * If we are running a multicast router 158911042SErik.Nordmark@Sun.COM * we need to see all igmp packets. 159011042SErik.Nordmark@Sun.COM */ 159111042SErik.Nordmark@Sun.COM if (ipha->ipha_protocol == IPPROTO_IGMP) { 159211042SErik.Nordmark@Sun.COM goto forus; 159311042SErik.Nordmark@Sun.COM } 159411042SErik.Nordmark@Sun.COM ip_drop_input("Multicast on tunnel ignored", mp, ill); 159511042SErik.Nordmark@Sun.COM freemsg(mp); 159611042SErik.Nordmark@Sun.COM goto done; 159711042SErik.Nordmark@Sun.COM } 159811042SErik.Nordmark@Sun.COM } 159911042SErik.Nordmark@Sun.COM 160011042SErik.Nordmark@Sun.COM /* 160111042SErik.Nordmark@Sun.COM * Check if we have members on this ill. This is not necessary for 160211042SErik.Nordmark@Sun.COM * correctness because even if the NIC/GLD had a leaky filter, we 160311042SErik.Nordmark@Sun.COM * filter before passing to each conn_t. 160411042SErik.Nordmark@Sun.COM */ 160511042SErik.Nordmark@Sun.COM if (!ill_hasmembers_v4(ill, ipha->ipha_dst)) { 160611042SErik.Nordmark@Sun.COM /* 160711042SErik.Nordmark@Sun.COM * Nobody interested 160811042SErik.Nordmark@Sun.COM * 160911042SErik.Nordmark@Sun.COM * This might just be caused by the fact that 161011042SErik.Nordmark@Sun.COM * multiple IP Multicast addresses map to the same 161111042SErik.Nordmark@Sun.COM * link layer multicast - no need to increment counter! 161211042SErik.Nordmark@Sun.COM */ 161311042SErik.Nordmark@Sun.COM ip_drop_input("Multicast with no members", mp, ill); 161411042SErik.Nordmark@Sun.COM freemsg(mp); 161511042SErik.Nordmark@Sun.COM goto done; 161611042SErik.Nordmark@Sun.COM } 161711042SErik.Nordmark@Sun.COM forus: 161811042SErik.Nordmark@Sun.COM ip2dbg(("ire_recv_multicast_v4: multicast for us: 0x%x\n", 161911042SErik.Nordmark@Sun.COM ntohl(ipha->ipha_dst))); 162011042SErik.Nordmark@Sun.COM 162111042SErik.Nordmark@Sun.COM /* 162211042SErik.Nordmark@Sun.COM * After reassembly and IPsec we will need to duplicate the 162311042SErik.Nordmark@Sun.COM * multicast packet for all matching zones on the ill. 162411042SErik.Nordmark@Sun.COM */ 162511042SErik.Nordmark@Sun.COM ira->ira_zoneid = ALL_ZONES; 162611042SErik.Nordmark@Sun.COM 162711042SErik.Nordmark@Sun.COM /* Reassemble on the ill on which the packet arrived */ 162811042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 162911042SErik.Nordmark@Sun.COM done: 163011042SErik.Nordmark@Sun.COM if (ill != ire->ire_ill) { 163111042SErik.Nordmark@Sun.COM ill_refrele(ill); 163211042SErik.Nordmark@Sun.COM ira->ira_ill = ire->ire_ill; 163311042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ira->ira_ill->ill_phyint->phyint_ifindex; 163411042SErik.Nordmark@Sun.COM } 163511042SErik.Nordmark@Sun.COM } 163611042SErik.Nordmark@Sun.COM 163711042SErik.Nordmark@Sun.COM /* 163811042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_OFFLINK with RTF_MULTIRT. 163911042SErik.Nordmark@Sun.COM * Drop packets since we don't forward out multirt routes. 164011042SErik.Nordmark@Sun.COM */ 164111042SErik.Nordmark@Sun.COM /* ARGSUSED */ 164211042SErik.Nordmark@Sun.COM void 164311042SErik.Nordmark@Sun.COM ire_recv_multirt_v4(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 164411042SErik.Nordmark@Sun.COM { 164511042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 164611042SErik.Nordmark@Sun.COM 164711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInNoRoutes); 164811042SErik.Nordmark@Sun.COM ip_drop_input("Not forwarding out MULTIRT", mp, ill); 164911042SErik.Nordmark@Sun.COM freemsg(mp); 165011042SErik.Nordmark@Sun.COM } 165111042SErik.Nordmark@Sun.COM 165211042SErik.Nordmark@Sun.COM /* 165311042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_LOOPBACK. This is only used when a FW_HOOK 165411042SErik.Nordmark@Sun.COM * has rewritten the packet to have a loopback destination address (We 165511042SErik.Nordmark@Sun.COM * filter out packet with a loopback destination from arriving over the wire). 165611042SErik.Nordmark@Sun.COM * We don't know what zone to use, thus we always use the GLOBAL_ZONEID. 165711042SErik.Nordmark@Sun.COM */ 165811042SErik.Nordmark@Sun.COM void 165911042SErik.Nordmark@Sun.COM ire_recv_loopback_v4(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 166011042SErik.Nordmark@Sun.COM { 166111042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 166211042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 166311042SErik.Nordmark@Sun.COM ill_t *ire_ill = ire->ire_ill; 166411042SErik.Nordmark@Sun.COM 166511042SErik.Nordmark@Sun.COM ira->ira_zoneid = GLOBAL_ZONEID; 166611042SErik.Nordmark@Sun.COM 166711042SErik.Nordmark@Sun.COM /* Switch to the lo0 ill for further processing */ 166811042SErik.Nordmark@Sun.COM if (ire_ill != ill) { 166911042SErik.Nordmark@Sun.COM /* 167011042SErik.Nordmark@Sun.COM * Update ira_ill to be the ILL on which the IP address 167111042SErik.Nordmark@Sun.COM * is hosted. 167211042SErik.Nordmark@Sun.COM * No need to hold the ill since we have a hold on the ire 167311042SErik.Nordmark@Sun.COM */ 167411042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ill == ira->ira_rill); 167511042SErik.Nordmark@Sun.COM ira->ira_ill = ire_ill; 167611042SErik.Nordmark@Sun.COM 167711042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 167811042SErik.Nordmark@Sun.COM 167911042SErik.Nordmark@Sun.COM /* Restore */ 168011042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ill == ire_ill); 168111042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 168211042SErik.Nordmark@Sun.COM return; 168311042SErik.Nordmark@Sun.COM 168411042SErik.Nordmark@Sun.COM } 168511042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 168611042SErik.Nordmark@Sun.COM } 168711042SErik.Nordmark@Sun.COM 168811042SErik.Nordmark@Sun.COM /* 168911042SErik.Nordmark@Sun.COM * ire_recvfn for IRE_LOCAL. 169011042SErik.Nordmark@Sun.COM */ 169111042SErik.Nordmark@Sun.COM void 169211042SErik.Nordmark@Sun.COM ire_recv_local_v4(ire_t *ire, mblk_t *mp, void *iph_arg, ip_recv_attr_t *ira) 169311042SErik.Nordmark@Sun.COM { 169411042SErik.Nordmark@Sun.COM ipha_t *ipha = (ipha_t *)iph_arg; 169511042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 169611042SErik.Nordmark@Sun.COM ill_t *ire_ill = ire->ire_ill; 169711042SErik.Nordmark@Sun.COM 169811042SErik.Nordmark@Sun.COM /* Make a note for DAD that this address is in use */ 169911110SErik.Nordmark@Sun.COM ire->ire_last_used_time = LBOLT_FASTPATH; 170011042SErik.Nordmark@Sun.COM 170111042SErik.Nordmark@Sun.COM /* Only target the IRE_LOCAL with the right zoneid. */ 170211042SErik.Nordmark@Sun.COM ira->ira_zoneid = ire->ire_zoneid; 170311042SErik.Nordmark@Sun.COM 170411042SErik.Nordmark@Sun.COM /* 170511042SErik.Nordmark@Sun.COM * If the packet arrived on the wrong ill, we check that 170611042SErik.Nordmark@Sun.COM * this is ok. 170711042SErik.Nordmark@Sun.COM * If it is, then we ensure that we do the reassembly on 170811042SErik.Nordmark@Sun.COM * the ill on which the address is hosted. We keep ira_rill as 170911042SErik.Nordmark@Sun.COM * the one on which the packet arrived, so that IP_PKTINFO and 171011042SErik.Nordmark@Sun.COM * friends can report this. 171111042SErik.Nordmark@Sun.COM */ 171211042SErik.Nordmark@Sun.COM if (ire_ill != ill) { 171311042SErik.Nordmark@Sun.COM ire_t *new_ire; 171411042SErik.Nordmark@Sun.COM 171511042SErik.Nordmark@Sun.COM new_ire = ip_check_multihome(&ipha->ipha_dst, ire, ill); 171611042SErik.Nordmark@Sun.COM if (new_ire == NULL) { 171711042SErik.Nordmark@Sun.COM /* Drop packet */ 171811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsForwProhibits); 171911042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInForwProhibits", mp, ill); 172011042SErik.Nordmark@Sun.COM freemsg(mp); 172111042SErik.Nordmark@Sun.COM return; 172211042SErik.Nordmark@Sun.COM } 172311042SErik.Nordmark@Sun.COM /* 172411042SErik.Nordmark@Sun.COM * Update ira_ill to be the ILL on which the IP address 172511042SErik.Nordmark@Sun.COM * is hosted. No need to hold the ill since we have a 172611042SErik.Nordmark@Sun.COM * hold on the ire. Note that we do the switch even if 172711042SErik.Nordmark@Sun.COM * new_ire == ire (for IPMP, ire would be the one corresponding 172811042SErik.Nordmark@Sun.COM * to the IPMP ill). 172911042SErik.Nordmark@Sun.COM */ 173011042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ill == ira->ira_rill); 173111042SErik.Nordmark@Sun.COM ira->ira_ill = new_ire->ire_ill; 173211042SErik.Nordmark@Sun.COM 173311042SErik.Nordmark@Sun.COM /* ira_ruifindex tracks the upper for ira_rill */ 173411042SErik.Nordmark@Sun.COM if (IS_UNDER_IPMP(ill)) 173511042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill_get_upper_ifindex(ill); 173611042SErik.Nordmark@Sun.COM 173711042SErik.Nordmark@Sun.COM ip_input_local_v4(new_ire, mp, ipha, ira); 173811042SErik.Nordmark@Sun.COM 173911042SErik.Nordmark@Sun.COM /* Restore */ 174011042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ill == new_ire->ire_ill); 174111042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 174211042SErik.Nordmark@Sun.COM ira->ira_ruifindex = ill->ill_phyint->phyint_ifindex; 174311042SErik.Nordmark@Sun.COM 174411042SErik.Nordmark@Sun.COM if (new_ire != ire) 174511042SErik.Nordmark@Sun.COM ire_refrele(new_ire); 174611042SErik.Nordmark@Sun.COM return; 174711042SErik.Nordmark@Sun.COM } 174811042SErik.Nordmark@Sun.COM 174911042SErik.Nordmark@Sun.COM ip_input_local_v4(ire, mp, ipha, ira); 175011042SErik.Nordmark@Sun.COM } 175111042SErik.Nordmark@Sun.COM 175211042SErik.Nordmark@Sun.COM /* 175311042SErik.Nordmark@Sun.COM * Common function for packets arriving for the host. Handles 175411042SErik.Nordmark@Sun.COM * checksum verification, reassembly checks, etc. 175511042SErik.Nordmark@Sun.COM */ 175611042SErik.Nordmark@Sun.COM static void 175711042SErik.Nordmark@Sun.COM ip_input_local_v4(ire_t *ire, mblk_t *mp, ipha_t *ipha, ip_recv_attr_t *ira) 175811042SErik.Nordmark@Sun.COM { 175911042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 176011042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 176111042SErik.Nordmark@Sun.COM 176211042SErik.Nordmark@Sun.COM /* 176311042SErik.Nordmark@Sun.COM * Verify IP header checksum. If the packet was AH or ESP then 176411042SErik.Nordmark@Sun.COM * this flag has already been cleared. Likewise if the packet 176511042SErik.Nordmark@Sun.COM * had a hardware checksum. 176611042SErik.Nordmark@Sun.COM */ 176711042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_VERIFY_IP_CKSUM) && ip_csum_hdr(ipha)) { 176811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInCksumErrs); 176911042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInCksumErrs", mp, ill); 177011042SErik.Nordmark@Sun.COM freemsg(mp); 177111042SErik.Nordmark@Sun.COM return; 177211042SErik.Nordmark@Sun.COM } 177311042SErik.Nordmark@Sun.COM 177411042SErik.Nordmark@Sun.COM if (iraflags & IRAF_IPV4_OPTIONS) { 177511042SErik.Nordmark@Sun.COM if (!ip_input_local_options(mp, ipha, ira)) { 177611042SErik.Nordmark@Sun.COM /* Error has been sent and mp consumed */ 177711042SErik.Nordmark@Sun.COM return; 177811042SErik.Nordmark@Sun.COM } 177911145SRoamer@Sun.COM /* 178011145SRoamer@Sun.COM * Some old hardware does partial checksum by including the 178111145SRoamer@Sun.COM * whole IP header, so the partial checksum value might have 178211145SRoamer@Sun.COM * become invalid if any option in the packet have been 178311145SRoamer@Sun.COM * updated. Always clear partial checksum flag here. 178411145SRoamer@Sun.COM */ 178511145SRoamer@Sun.COM DB_CKSUMFLAGS(mp) &= ~HCK_PARTIALCKSUM; 178611042SErik.Nordmark@Sun.COM } 178711042SErik.Nordmark@Sun.COM 178811042SErik.Nordmark@Sun.COM /* 178911042SErik.Nordmark@Sun.COM * Is packet part of fragmented IP packet? 179011042SErik.Nordmark@Sun.COM * We compare against defined values in network byte order 179111042SErik.Nordmark@Sun.COM */ 179211042SErik.Nordmark@Sun.COM if (ipha->ipha_fragment_offset_and_flags & 179311042SErik.Nordmark@Sun.COM (IPH_MF_HTONS | IPH_OFFSET_HTONS)) { 179411042SErik.Nordmark@Sun.COM /* 179511042SErik.Nordmark@Sun.COM * Make sure we have ira_l2src before we loose the original 179611042SErik.Nordmark@Sun.COM * mblk 179711042SErik.Nordmark@Sun.COM */ 179811042SErik.Nordmark@Sun.COM if (!(ira->ira_flags & IRAF_L2SRC_SET)) 179911042SErik.Nordmark@Sun.COM ip_setl2src(mp, ira, ira->ira_rill); 180011042SErik.Nordmark@Sun.COM 180111042SErik.Nordmark@Sun.COM mp = ip_input_fragment(mp, ipha, ira); 180211042SErik.Nordmark@Sun.COM if (mp == NULL) 180311042SErik.Nordmark@Sun.COM return; 180411042SErik.Nordmark@Sun.COM /* Completed reassembly */ 180511042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 180611042SErik.Nordmark@Sun.COM } 180711042SErik.Nordmark@Sun.COM 180811042SErik.Nordmark@Sun.COM /* 180911042SErik.Nordmark@Sun.COM * For broadcast and multicast we need some extra work before 181011042SErik.Nordmark@Sun.COM * we call ip_fanout_v4(), since in the case of shared-IP zones 181111042SErik.Nordmark@Sun.COM * we need to pretend that a packet arrived for each zoneid. 181211042SErik.Nordmark@Sun.COM */ 181311042SErik.Nordmark@Sun.COM if (iraflags & IRAF_MULTIBROADCAST) { 181411042SErik.Nordmark@Sun.COM if (iraflags & IRAF_BROADCAST) 181511042SErik.Nordmark@Sun.COM ip_input_broadcast_v4(ire, mp, ipha, ira); 181611042SErik.Nordmark@Sun.COM else 181711042SErik.Nordmark@Sun.COM ip_input_multicast_v4(ire, mp, ipha, ira); 181811042SErik.Nordmark@Sun.COM return; 181911042SErik.Nordmark@Sun.COM } 182011042SErik.Nordmark@Sun.COM ip_fanout_v4(mp, ipha, ira); 182111042SErik.Nordmark@Sun.COM } 182211042SErik.Nordmark@Sun.COM 182311042SErik.Nordmark@Sun.COM 182411042SErik.Nordmark@Sun.COM /* 182511042SErik.Nordmark@Sun.COM * Handle multiple zones which match the same broadcast address 182611042SErik.Nordmark@Sun.COM * and ill by delivering a packet to each of them. 182711042SErik.Nordmark@Sun.COM * Walk the bucket and look for different ire_zoneid but otherwise 182811042SErik.Nordmark@Sun.COM * the same IRE (same ill/addr/mask/type). 182911042SErik.Nordmark@Sun.COM * Note that ire_add() tracks IREs that are identical in all 183011042SErik.Nordmark@Sun.COM * fields (addr/mask/type/gw/ill/zoneid) within a single IRE by 183111042SErik.Nordmark@Sun.COM * increasing ire_identical_cnt. Thus we don't need to be concerned 183211042SErik.Nordmark@Sun.COM * about those. 183311042SErik.Nordmark@Sun.COM */ 183411042SErik.Nordmark@Sun.COM static void 183511042SErik.Nordmark@Sun.COM ip_input_broadcast_v4(ire_t *ire, mblk_t *mp, ipha_t *ipha, ip_recv_attr_t *ira) 183611042SErik.Nordmark@Sun.COM { 183711042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 183811042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 183911042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack; 184011042SErik.Nordmark@Sun.COM irb_t *irb; 184111042SErik.Nordmark@Sun.COM ire_t *ire1; 184211042SErik.Nordmark@Sun.COM mblk_t *mp1; 184311042SErik.Nordmark@Sun.COM ipha_t *ipha1; 1844*11681SSowmini.Varadhan@Sun.COM uint_t ira_pktlen = ira->ira_pktlen; 1845*11681SSowmini.Varadhan@Sun.COM uint16_t ira_ip_hdr_length = ira->ira_ip_hdr_length; 184611042SErik.Nordmark@Sun.COM 184711042SErik.Nordmark@Sun.COM irb = ire->ire_bucket; 184811042SErik.Nordmark@Sun.COM 184911042SErik.Nordmark@Sun.COM /* 185011042SErik.Nordmark@Sun.COM * If we don't have more than one shared-IP zone, or if 185111042SErik.Nordmark@Sun.COM * there can't be more than one IRE_BROADCAST for this 185211042SErik.Nordmark@Sun.COM * IP address, then just set the zoneid and proceed. 185311042SErik.Nordmark@Sun.COM */ 185411042SErik.Nordmark@Sun.COM if (ns->netstack_numzones == 1 || irb->irb_ire_cnt == 1) { 185511042SErik.Nordmark@Sun.COM ira->ira_zoneid = ire->ire_zoneid; 185611042SErik.Nordmark@Sun.COM 185711042SErik.Nordmark@Sun.COM ip_fanout_v4(mp, ipha, ira); 185811042SErik.Nordmark@Sun.COM return; 185911042SErik.Nordmark@Sun.COM } 186011042SErik.Nordmark@Sun.COM irb_refhold(irb); 186111042SErik.Nordmark@Sun.COM for (ire1 = irb->irb_ire; ire1 != NULL; ire1 = ire1->ire_next) { 186211042SErik.Nordmark@Sun.COM /* We do the main IRE after the end of the loop */ 186311042SErik.Nordmark@Sun.COM if (ire1 == ire) 186411042SErik.Nordmark@Sun.COM continue; 186511042SErik.Nordmark@Sun.COM 186611042SErik.Nordmark@Sun.COM /* 186711042SErik.Nordmark@Sun.COM * Only IREs for the same IP address should be in the same 186811042SErik.Nordmark@Sun.COM * bucket. 186911042SErik.Nordmark@Sun.COM * But could have IRE_HOSTs in the case of CGTP. 187011042SErik.Nordmark@Sun.COM */ 187111042SErik.Nordmark@Sun.COM ASSERT(ire1->ire_addr == ire->ire_addr); 187211042SErik.Nordmark@Sun.COM if (!(ire1->ire_type & IRE_BROADCAST)) 187311042SErik.Nordmark@Sun.COM continue; 187411042SErik.Nordmark@Sun.COM 187511042SErik.Nordmark@Sun.COM if (IRE_IS_CONDEMNED(ire1)) 187611042SErik.Nordmark@Sun.COM continue; 187711042SErik.Nordmark@Sun.COM 187811042SErik.Nordmark@Sun.COM mp1 = copymsg(mp); 187911042SErik.Nordmark@Sun.COM if (mp1 == NULL) { 188011042SErik.Nordmark@Sun.COM /* Failed to deliver to one zone */ 188111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 188211042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 188311042SErik.Nordmark@Sun.COM continue; 188411042SErik.Nordmark@Sun.COM } 188511042SErik.Nordmark@Sun.COM ira->ira_zoneid = ire1->ire_zoneid; 188611042SErik.Nordmark@Sun.COM ipha1 = (ipha_t *)mp1->b_rptr; 188711042SErik.Nordmark@Sun.COM ip_fanout_v4(mp1, ipha1, ira); 1888*11681SSowmini.Varadhan@Sun.COM /* 1889*11681SSowmini.Varadhan@Sun.COM * IPsec might have modified ira_pktlen and ira_ip_hdr_length 1890*11681SSowmini.Varadhan@Sun.COM * so we restore them for a potential next iteration 1891*11681SSowmini.Varadhan@Sun.COM */ 1892*11681SSowmini.Varadhan@Sun.COM ira->ira_pktlen = ira_pktlen; 1893*11681SSowmini.Varadhan@Sun.COM ira->ira_ip_hdr_length = ira_ip_hdr_length; 189411042SErik.Nordmark@Sun.COM } 189511042SErik.Nordmark@Sun.COM irb_refrele(irb); 189611042SErik.Nordmark@Sun.COM /* Do the main ire */ 189711042SErik.Nordmark@Sun.COM ira->ira_zoneid = ire->ire_zoneid; 189811042SErik.Nordmark@Sun.COM ip_fanout_v4(mp, ipha, ira); 189911042SErik.Nordmark@Sun.COM } 190011042SErik.Nordmark@Sun.COM 190111042SErik.Nordmark@Sun.COM /* 190211042SErik.Nordmark@Sun.COM * Handle multiple zones which want to receive the same multicast packets 190311042SErik.Nordmark@Sun.COM * on this ill by delivering a packet to each of them. 190411042SErik.Nordmark@Sun.COM * 190511042SErik.Nordmark@Sun.COM * Note that for packets delivered to transports we could instead do this 190611042SErik.Nordmark@Sun.COM * as part of the fanout code, but since we need to handle icmp_inbound 190711042SErik.Nordmark@Sun.COM * it is simpler to have multicast work the same as broadcast. 190811042SErik.Nordmark@Sun.COM * 190911042SErik.Nordmark@Sun.COM * The ip_fanout matching for multicast matches based on ilm independent of 191011042SErik.Nordmark@Sun.COM * zoneid since the zoneid restriction is applied when joining a multicast 191111042SErik.Nordmark@Sun.COM * group. 191211042SErik.Nordmark@Sun.COM */ 191311042SErik.Nordmark@Sun.COM /* ARGSUSED */ 191411042SErik.Nordmark@Sun.COM static void 191511042SErik.Nordmark@Sun.COM ip_input_multicast_v4(ire_t *ire, mblk_t *mp, ipha_t *ipha, ip_recv_attr_t *ira) 191611042SErik.Nordmark@Sun.COM { 191711042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 191811042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 191911042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 192011042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack; 192111042SErik.Nordmark@Sun.COM zoneid_t zoneid; 192211042SErik.Nordmark@Sun.COM mblk_t *mp1; 192311042SErik.Nordmark@Sun.COM ipha_t *ipha1; 1924*11681SSowmini.Varadhan@Sun.COM uint_t ira_pktlen = ira->ira_pktlen; 1925*11681SSowmini.Varadhan@Sun.COM uint16_t ira_ip_hdr_length = ira->ira_ip_hdr_length; 192611042SErik.Nordmark@Sun.COM 192711042SErik.Nordmark@Sun.COM /* ire_recv_multicast has switched to the upper ill for IPMP */ 192811042SErik.Nordmark@Sun.COM ASSERT(!IS_UNDER_IPMP(ill)); 192911042SErik.Nordmark@Sun.COM 193011042SErik.Nordmark@Sun.COM /* 193111042SErik.Nordmark@Sun.COM * If we don't have more than one shared-IP zone, or if 193211042SErik.Nordmark@Sun.COM * there are no members in anything but the global zone, 193311042SErik.Nordmark@Sun.COM * then just set the zoneid and proceed. 193411042SErik.Nordmark@Sun.COM */ 193511042SErik.Nordmark@Sun.COM if (ns->netstack_numzones == 1 || 193611042SErik.Nordmark@Sun.COM !ill_hasmembers_otherzones_v4(ill, ipha->ipha_dst, 193711042SErik.Nordmark@Sun.COM GLOBAL_ZONEID)) { 193811042SErik.Nordmark@Sun.COM ira->ira_zoneid = GLOBAL_ZONEID; 193911042SErik.Nordmark@Sun.COM 194011042SErik.Nordmark@Sun.COM /* If sender didn't want this zone to receive it, drop */ 194111042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 194211042SErik.Nordmark@Sun.COM ira->ira_no_loop_zoneid == ira->ira_zoneid) { 194311042SErik.Nordmark@Sun.COM ip_drop_input("Multicast but wrong zoneid", mp, ill); 194411042SErik.Nordmark@Sun.COM freemsg(mp); 194511042SErik.Nordmark@Sun.COM return; 194611042SErik.Nordmark@Sun.COM } 194711042SErik.Nordmark@Sun.COM ip_fanout_v4(mp, ipha, ira); 194811042SErik.Nordmark@Sun.COM return; 194911042SErik.Nordmark@Sun.COM } 195011042SErik.Nordmark@Sun.COM 195111042SErik.Nordmark@Sun.COM /* 195211042SErik.Nordmark@Sun.COM * Here we loop over all zoneids that have members in the group 195311042SErik.Nordmark@Sun.COM * and deliver a packet to ip_fanout for each zoneid. 195411042SErik.Nordmark@Sun.COM * 195511042SErik.Nordmark@Sun.COM * First find any members in the lowest numeric zoneid by looking for 195611042SErik.Nordmark@Sun.COM * first zoneid larger than -1 (ALL_ZONES). 195711042SErik.Nordmark@Sun.COM * We terminate the loop when we receive -1 (ALL_ZONES). 195811042SErik.Nordmark@Sun.COM */ 195911042SErik.Nordmark@Sun.COM zoneid = ill_hasmembers_nextzone_v4(ill, ipha->ipha_dst, ALL_ZONES); 196011042SErik.Nordmark@Sun.COM for (; zoneid != ALL_ZONES; 196111042SErik.Nordmark@Sun.COM zoneid = ill_hasmembers_nextzone_v4(ill, ipha->ipha_dst, zoneid)) { 196211042SErik.Nordmark@Sun.COM /* 196311042SErik.Nordmark@Sun.COM * Avoid an extra copymsg/freemsg by skipping global zone here 196411042SErik.Nordmark@Sun.COM * and doing that at the end. 196511042SErik.Nordmark@Sun.COM */ 196611042SErik.Nordmark@Sun.COM if (zoneid == GLOBAL_ZONEID) 196711042SErik.Nordmark@Sun.COM continue; 196811042SErik.Nordmark@Sun.COM 196911042SErik.Nordmark@Sun.COM ira->ira_zoneid = zoneid; 197011042SErik.Nordmark@Sun.COM 197111042SErik.Nordmark@Sun.COM /* If sender didn't want this zone to receive it, skip */ 197211042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 197311042SErik.Nordmark@Sun.COM ira->ira_no_loop_zoneid == ira->ira_zoneid) 197411042SErik.Nordmark@Sun.COM continue; 197511042SErik.Nordmark@Sun.COM 197611042SErik.Nordmark@Sun.COM mp1 = copymsg(mp); 197711042SErik.Nordmark@Sun.COM if (mp1 == NULL) { 197811042SErik.Nordmark@Sun.COM /* Failed to deliver to one zone */ 197911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 198011042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 198111042SErik.Nordmark@Sun.COM continue; 198211042SErik.Nordmark@Sun.COM } 198311042SErik.Nordmark@Sun.COM ipha1 = (ipha_t *)mp1->b_rptr; 198411042SErik.Nordmark@Sun.COM ip_fanout_v4(mp1, ipha1, ira); 1985*11681SSowmini.Varadhan@Sun.COM /* 1986*11681SSowmini.Varadhan@Sun.COM * IPsec might have modified ira_pktlen and ira_ip_hdr_length 1987*11681SSowmini.Varadhan@Sun.COM * so we restore them for a potential next iteration 1988*11681SSowmini.Varadhan@Sun.COM */ 1989*11681SSowmini.Varadhan@Sun.COM ira->ira_pktlen = ira_pktlen; 1990*11681SSowmini.Varadhan@Sun.COM ira->ira_ip_hdr_length = ira_ip_hdr_length; 199111042SErik.Nordmark@Sun.COM } 199211042SErik.Nordmark@Sun.COM 199311042SErik.Nordmark@Sun.COM /* Do the main ire */ 199411042SErik.Nordmark@Sun.COM ira->ira_zoneid = GLOBAL_ZONEID; 199511042SErik.Nordmark@Sun.COM /* If sender didn't want this zone to receive it, drop */ 199611042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_NO_LOOP_ZONEID_SET) && 199711042SErik.Nordmark@Sun.COM ira->ira_no_loop_zoneid == ira->ira_zoneid) { 199811042SErik.Nordmark@Sun.COM ip_drop_input("Multicast but wrong zoneid", mp, ill); 199911042SErik.Nordmark@Sun.COM freemsg(mp); 200011042SErik.Nordmark@Sun.COM } else { 200111042SErik.Nordmark@Sun.COM ip_fanout_v4(mp, ipha, ira); 200211042SErik.Nordmark@Sun.COM } 200311042SErik.Nordmark@Sun.COM } 200411042SErik.Nordmark@Sun.COM 200511042SErik.Nordmark@Sun.COM 200611042SErik.Nordmark@Sun.COM /* 200711042SErik.Nordmark@Sun.COM * Determine the zoneid and IRAF_TX_* flags if trusted extensions 200811042SErik.Nordmark@Sun.COM * is in use. Updates ira_zoneid and ira_flags as a result. 200911042SErik.Nordmark@Sun.COM */ 201011042SErik.Nordmark@Sun.COM static void 201111042SErik.Nordmark@Sun.COM ip_fanout_tx_v4(mblk_t *mp, ipha_t *ipha, uint8_t protocol, 201211042SErik.Nordmark@Sun.COM uint_t ip_hdr_length, ip_recv_attr_t *ira) 201311042SErik.Nordmark@Sun.COM { 201411042SErik.Nordmark@Sun.COM uint16_t *up; 201511042SErik.Nordmark@Sun.COM uint16_t lport; 201611042SErik.Nordmark@Sun.COM zoneid_t zoneid; 201711042SErik.Nordmark@Sun.COM 201811042SErik.Nordmark@Sun.COM ASSERT(ira->ira_flags & IRAF_SYSTEM_LABELED); 201911042SErik.Nordmark@Sun.COM 202011042SErik.Nordmark@Sun.COM /* 202111042SErik.Nordmark@Sun.COM * If the packet is unlabeled we might allow read-down 202211042SErik.Nordmark@Sun.COM * for MAC_EXEMPT. Below we clear this if it is a multi-level 202311042SErik.Nordmark@Sun.COM * port (MLP). 202411042SErik.Nordmark@Sun.COM * Note that ira_tsl can be NULL here. 202511042SErik.Nordmark@Sun.COM */ 202611042SErik.Nordmark@Sun.COM if (ira->ira_tsl != NULL && ira->ira_tsl->tsl_flags & TSLF_UNLABELED) 202711042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_TX_MAC_EXEMPTABLE; 202811042SErik.Nordmark@Sun.COM 202911042SErik.Nordmark@Sun.COM if (ira->ira_zoneid != ALL_ZONES) 203011042SErik.Nordmark@Sun.COM return; 203111042SErik.Nordmark@Sun.COM 203211042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_TX_SHARED_ADDR; 203311042SErik.Nordmark@Sun.COM 203411042SErik.Nordmark@Sun.COM up = (uint16_t *)((uchar_t *)ipha + ip_hdr_length); 203511042SErik.Nordmark@Sun.COM switch (protocol) { 203611042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 203711042SErik.Nordmark@Sun.COM case IPPROTO_SCTP: 203811042SErik.Nordmark@Sun.COM case IPPROTO_UDP: 203911042SErik.Nordmark@Sun.COM /* Caller ensures this */ 204011042SErik.Nordmark@Sun.COM ASSERT(((uchar_t *)ipha) + ip_hdr_length +4 <= mp->b_wptr); 204111042SErik.Nordmark@Sun.COM 204211042SErik.Nordmark@Sun.COM /* 204311042SErik.Nordmark@Sun.COM * Only these transports support MLP. 204411042SErik.Nordmark@Sun.COM * We know their destination port numbers is in 204511042SErik.Nordmark@Sun.COM * the same place in the header. 204611042SErik.Nordmark@Sun.COM */ 204711042SErik.Nordmark@Sun.COM lport = up[1]; 204811042SErik.Nordmark@Sun.COM 204911042SErik.Nordmark@Sun.COM /* 205011042SErik.Nordmark@Sun.COM * No need to handle exclusive-stack zones 205111042SErik.Nordmark@Sun.COM * since ALL_ZONES only applies to the shared IP instance. 205211042SErik.Nordmark@Sun.COM */ 205311042SErik.Nordmark@Sun.COM zoneid = tsol_mlp_findzone(protocol, lport); 205411042SErik.Nordmark@Sun.COM /* 205511042SErik.Nordmark@Sun.COM * If no shared MLP is found, tsol_mlp_findzone returns 205611042SErik.Nordmark@Sun.COM * ALL_ZONES. In that case, we assume it's SLP, and 205711042SErik.Nordmark@Sun.COM * search for the zone based on the packet label. 205811042SErik.Nordmark@Sun.COM * 205911042SErik.Nordmark@Sun.COM * If there is such a zone, we prefer to find a 206011042SErik.Nordmark@Sun.COM * connection in it. Otherwise, we look for a 206111042SErik.Nordmark@Sun.COM * MAC-exempt connection in any zone whose label 206211042SErik.Nordmark@Sun.COM * dominates the default label on the packet. 206311042SErik.Nordmark@Sun.COM */ 206411042SErik.Nordmark@Sun.COM if (zoneid == ALL_ZONES) 206511042SErik.Nordmark@Sun.COM zoneid = tsol_attr_to_zoneid(ira); 206611042SErik.Nordmark@Sun.COM else 206711042SErik.Nordmark@Sun.COM ira->ira_flags &= ~IRAF_TX_MAC_EXEMPTABLE; 206811042SErik.Nordmark@Sun.COM break; 206911042SErik.Nordmark@Sun.COM default: 207011042SErik.Nordmark@Sun.COM /* Handle shared address for other protocols */ 207111042SErik.Nordmark@Sun.COM zoneid = tsol_attr_to_zoneid(ira); 207211042SErik.Nordmark@Sun.COM break; 207311042SErik.Nordmark@Sun.COM } 207411042SErik.Nordmark@Sun.COM ira->ira_zoneid = zoneid; 207511042SErik.Nordmark@Sun.COM } 207611042SErik.Nordmark@Sun.COM 207711042SErik.Nordmark@Sun.COM /* 207811042SErik.Nordmark@Sun.COM * Increment checksum failure statistics 207911042SErik.Nordmark@Sun.COM */ 208011042SErik.Nordmark@Sun.COM static void 208111042SErik.Nordmark@Sun.COM ip_input_cksum_err_v4(uint8_t protocol, uint16_t hck_flags, ill_t *ill) 208211042SErik.Nordmark@Sun.COM { 208311042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 208411042SErik.Nordmark@Sun.COM 208511042SErik.Nordmark@Sun.COM switch (protocol) { 208611042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 208711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, tcpIfStatsInErrs); 208811042SErik.Nordmark@Sun.COM 208911042SErik.Nordmark@Sun.COM if (hck_flags & HCK_FULLCKSUM) 209011042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_tcp_in_full_hw_cksum_err); 209111042SErik.Nordmark@Sun.COM else if (hck_flags & HCK_PARTIALCKSUM) 209211042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_tcp_in_part_hw_cksum_err); 209311042SErik.Nordmark@Sun.COM else 209411042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_tcp_in_sw_cksum_err); 209511042SErik.Nordmark@Sun.COM break; 209611042SErik.Nordmark@Sun.COM case IPPROTO_UDP: 209711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, udpIfStatsInCksumErrs); 209811042SErik.Nordmark@Sun.COM if (hck_flags & HCK_FULLCKSUM) 209911042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_udp_in_full_hw_cksum_err); 210011042SErik.Nordmark@Sun.COM else if (hck_flags & HCK_PARTIALCKSUM) 210111042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_udp_in_part_hw_cksum_err); 210211042SErik.Nordmark@Sun.COM else 210311042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_udp_in_sw_cksum_err); 210411042SErik.Nordmark@Sun.COM break; 210511042SErik.Nordmark@Sun.COM case IPPROTO_ICMP: 210611042SErik.Nordmark@Sun.COM BUMP_MIB(&ipst->ips_icmp_mib, icmpInCksumErrs); 210711042SErik.Nordmark@Sun.COM break; 210811042SErik.Nordmark@Sun.COM default: 210911042SErik.Nordmark@Sun.COM ASSERT(0); 211011042SErik.Nordmark@Sun.COM break; 211111042SErik.Nordmark@Sun.COM } 211211042SErik.Nordmark@Sun.COM } 211311042SErik.Nordmark@Sun.COM 211411042SErik.Nordmark@Sun.COM /* Calculate the IPv4 pseudo-header checksum */ 211511042SErik.Nordmark@Sun.COM uint32_t 211611042SErik.Nordmark@Sun.COM ip_input_cksum_pseudo_v4(ipha_t *ipha, ip_recv_attr_t *ira) 211711042SErik.Nordmark@Sun.COM { 211811042SErik.Nordmark@Sun.COM uint_t ulp_len; 211911042SErik.Nordmark@Sun.COM uint32_t cksum; 212011042SErik.Nordmark@Sun.COM uint8_t protocol = ira->ira_protocol; 212111042SErik.Nordmark@Sun.COM uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 212211042SErik.Nordmark@Sun.COM 212311042SErik.Nordmark@Sun.COM #define iphs ((uint16_t *)ipha) 212411042SErik.Nordmark@Sun.COM 212511042SErik.Nordmark@Sun.COM switch (protocol) { 212611042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 212711042SErik.Nordmark@Sun.COM ulp_len = ira->ira_pktlen - ip_hdr_length; 212811042SErik.Nordmark@Sun.COM 212911042SErik.Nordmark@Sun.COM /* Protocol and length */ 213011042SErik.Nordmark@Sun.COM cksum = htons(ulp_len) + IP_TCP_CSUM_COMP; 213111042SErik.Nordmark@Sun.COM /* IP addresses */ 213211042SErik.Nordmark@Sun.COM cksum += iphs[6] + iphs[7] + iphs[8] + iphs[9]; 213311042SErik.Nordmark@Sun.COM break; 213411042SErik.Nordmark@Sun.COM 213511042SErik.Nordmark@Sun.COM case IPPROTO_UDP: { 213611042SErik.Nordmark@Sun.COM udpha_t *udpha; 213711042SErik.Nordmark@Sun.COM 213811042SErik.Nordmark@Sun.COM udpha = (udpha_t *)((uchar_t *)ipha + ip_hdr_length); 213911042SErik.Nordmark@Sun.COM 214011042SErik.Nordmark@Sun.COM /* Protocol and length */ 214111042SErik.Nordmark@Sun.COM cksum = udpha->uha_length + IP_UDP_CSUM_COMP; 214211042SErik.Nordmark@Sun.COM /* IP addresses */ 214311042SErik.Nordmark@Sun.COM cksum += iphs[6] + iphs[7] + iphs[8] + iphs[9]; 214411042SErik.Nordmark@Sun.COM break; 214511042SErik.Nordmark@Sun.COM } 214611042SErik.Nordmark@Sun.COM 214711042SErik.Nordmark@Sun.COM default: 214811042SErik.Nordmark@Sun.COM cksum = 0; 214911042SErik.Nordmark@Sun.COM break; 215011042SErik.Nordmark@Sun.COM } 215111042SErik.Nordmark@Sun.COM #undef iphs 215211042SErik.Nordmark@Sun.COM return (cksum); 215311042SErik.Nordmark@Sun.COM } 215411042SErik.Nordmark@Sun.COM 215511042SErik.Nordmark@Sun.COM 215611042SErik.Nordmark@Sun.COM /* 215711042SErik.Nordmark@Sun.COM * Software verification of the ULP checksums. 215811042SErik.Nordmark@Sun.COM * Returns B_TRUE if ok. 215911042SErik.Nordmark@Sun.COM * Increments statistics of failed. 216011042SErik.Nordmark@Sun.COM */ 216111042SErik.Nordmark@Sun.COM static boolean_t 216211042SErik.Nordmark@Sun.COM ip_input_sw_cksum_v4(mblk_t *mp, ipha_t *ipha, ip_recv_attr_t *ira) 216311042SErik.Nordmark@Sun.COM { 216411042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ira->ira_ill->ill_ipst; 216511042SErik.Nordmark@Sun.COM uint32_t cksum; 216611042SErik.Nordmark@Sun.COM uint8_t protocol = ira->ira_protocol; 216711042SErik.Nordmark@Sun.COM uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 216811042SErik.Nordmark@Sun.COM 216911042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_in_sw_cksum); 217011042SErik.Nordmark@Sun.COM 217111042SErik.Nordmark@Sun.COM ASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP); 217211042SErik.Nordmark@Sun.COM 217311042SErik.Nordmark@Sun.COM cksum = ip_input_cksum_pseudo_v4(ipha, ira); 217411042SErik.Nordmark@Sun.COM cksum = IP_CSUM(mp, ip_hdr_length, cksum); 217511042SErik.Nordmark@Sun.COM if (cksum == 0) 217611042SErik.Nordmark@Sun.COM return (B_TRUE); 217711042SErik.Nordmark@Sun.COM 217811042SErik.Nordmark@Sun.COM ip_input_cksum_err_v4(protocol, 0, ira->ira_ill); 217911042SErik.Nordmark@Sun.COM return (B_FALSE); 218011042SErik.Nordmark@Sun.COM } 218111042SErik.Nordmark@Sun.COM 218211042SErik.Nordmark@Sun.COM /* 218311042SErik.Nordmark@Sun.COM * Verify the ULP checksums. 218411042SErik.Nordmark@Sun.COM * Returns B_TRUE if ok, or if the ULP doesn't have a well-defined checksum 218511042SErik.Nordmark@Sun.COM * algorithm. 218611042SErik.Nordmark@Sun.COM * Increments statistics if failed. 218711042SErik.Nordmark@Sun.COM */ 218811042SErik.Nordmark@Sun.COM static boolean_t 218911042SErik.Nordmark@Sun.COM ip_input_cksum_v4(iaflags_t iraflags, mblk_t *mp, ipha_t *ipha, 219011042SErik.Nordmark@Sun.COM ip_recv_attr_t *ira) 219111042SErik.Nordmark@Sun.COM { 219211042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_rill; 219311042SErik.Nordmark@Sun.COM uint16_t hck_flags; 219411042SErik.Nordmark@Sun.COM uint32_t cksum; 219511042SErik.Nordmark@Sun.COM mblk_t *mp1; 219611042SErik.Nordmark@Sun.COM int32_t len; 219711042SErik.Nordmark@Sun.COM uint8_t protocol = ira->ira_protocol; 219811042SErik.Nordmark@Sun.COM uint16_t ip_hdr_length = ira->ira_ip_hdr_length; 219911042SErik.Nordmark@Sun.COM 220011042SErik.Nordmark@Sun.COM 220111042SErik.Nordmark@Sun.COM switch (protocol) { 220211042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 220311042SErik.Nordmark@Sun.COM break; 220411042SErik.Nordmark@Sun.COM 220511042SErik.Nordmark@Sun.COM case IPPROTO_UDP: { 220611042SErik.Nordmark@Sun.COM udpha_t *udpha; 220711042SErik.Nordmark@Sun.COM 220811042SErik.Nordmark@Sun.COM udpha = (udpha_t *)((uchar_t *)ipha + ip_hdr_length); 220911042SErik.Nordmark@Sun.COM if (udpha->uha_checksum == 0) { 221011042SErik.Nordmark@Sun.COM /* Packet doesn't have a UDP checksum */ 221111042SErik.Nordmark@Sun.COM return (B_TRUE); 221211042SErik.Nordmark@Sun.COM } 221311042SErik.Nordmark@Sun.COM break; 221411042SErik.Nordmark@Sun.COM } 221511042SErik.Nordmark@Sun.COM case IPPROTO_SCTP: { 221611042SErik.Nordmark@Sun.COM sctp_hdr_t *sctph; 221711042SErik.Nordmark@Sun.COM uint32_t pktsum; 221811042SErik.Nordmark@Sun.COM 221911042SErik.Nordmark@Sun.COM sctph = (sctp_hdr_t *)((uchar_t *)ipha + ip_hdr_length); 222011042SErik.Nordmark@Sun.COM #ifdef DEBUG 222111042SErik.Nordmark@Sun.COM if (skip_sctp_cksum) 222211042SErik.Nordmark@Sun.COM return (B_TRUE); 222311042SErik.Nordmark@Sun.COM #endif 222411042SErik.Nordmark@Sun.COM pktsum = sctph->sh_chksum; 222511042SErik.Nordmark@Sun.COM sctph->sh_chksum = 0; 222611042SErik.Nordmark@Sun.COM cksum = sctp_cksum(mp, ip_hdr_length); 222711042SErik.Nordmark@Sun.COM sctph->sh_chksum = pktsum; 222811042SErik.Nordmark@Sun.COM if (cksum == pktsum) 222911042SErik.Nordmark@Sun.COM return (B_TRUE); 223011042SErik.Nordmark@Sun.COM 223111042SErik.Nordmark@Sun.COM /* 223211042SErik.Nordmark@Sun.COM * Defer until later whether a bad checksum is ok 223311042SErik.Nordmark@Sun.COM * in order to allow RAW sockets to use Adler checksum 223411042SErik.Nordmark@Sun.COM * with SCTP. 223511042SErik.Nordmark@Sun.COM */ 223611042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_SCTP_CSUM_ERR; 223711042SErik.Nordmark@Sun.COM return (B_TRUE); 223811042SErik.Nordmark@Sun.COM } 223911042SErik.Nordmark@Sun.COM 224011042SErik.Nordmark@Sun.COM default: 224111042SErik.Nordmark@Sun.COM /* No ULP checksum to verify. */ 224211042SErik.Nordmark@Sun.COM return (B_TRUE); 224311042SErik.Nordmark@Sun.COM } 224411042SErik.Nordmark@Sun.COM /* 224511042SErik.Nordmark@Sun.COM * Revert to software checksum calculation if the interface 224611042SErik.Nordmark@Sun.COM * isn't capable of checksum offload. 224711042SErik.Nordmark@Sun.COM * We clear DB_CKSUMFLAGS when going through IPsec in ip_fanout. 224811042SErik.Nordmark@Sun.COM * Note: IRAF_NO_HW_CKSUM is not currently used. 224911042SErik.Nordmark@Sun.COM */ 225011042SErik.Nordmark@Sun.COM ASSERT(!IS_IPMP(ill)); 225111042SErik.Nordmark@Sun.COM if ((iraflags & IRAF_NO_HW_CKSUM) || !ILL_HCKSUM_CAPABLE(ill) || 225211042SErik.Nordmark@Sun.COM !dohwcksum) { 225311042SErik.Nordmark@Sun.COM return (ip_input_sw_cksum_v4(mp, ipha, ira)); 225411042SErik.Nordmark@Sun.COM } 225511042SErik.Nordmark@Sun.COM 225611042SErik.Nordmark@Sun.COM /* 225711042SErik.Nordmark@Sun.COM * We apply this for all ULP protocols. Does the HW know to 225811042SErik.Nordmark@Sun.COM * not set the flags for SCTP and other protocols. 225911042SErik.Nordmark@Sun.COM */ 226011042SErik.Nordmark@Sun.COM 226111042SErik.Nordmark@Sun.COM hck_flags = DB_CKSUMFLAGS(mp); 226211042SErik.Nordmark@Sun.COM 226311042SErik.Nordmark@Sun.COM if (hck_flags & HCK_FULLCKSUM) { 226411042SErik.Nordmark@Sun.COM /* 226511042SErik.Nordmark@Sun.COM * Full checksum has been computed by the hardware 226611042SErik.Nordmark@Sun.COM * and has been attached. If the driver wants us to 226711042SErik.Nordmark@Sun.COM * verify the correctness of the attached value, in 226811042SErik.Nordmark@Sun.COM * order to protect against faulty hardware, compare 226911042SErik.Nordmark@Sun.COM * it against -0 (0xFFFF) to see if it's valid. 227011042SErik.Nordmark@Sun.COM */ 227111042SErik.Nordmark@Sun.COM if (hck_flags & HCK_FULLCKSUM_OK) 227211042SErik.Nordmark@Sun.COM return (B_TRUE); 227311042SErik.Nordmark@Sun.COM 227411042SErik.Nordmark@Sun.COM cksum = DB_CKSUM16(mp); 227511042SErik.Nordmark@Sun.COM if (cksum == 0xFFFF) 227611042SErik.Nordmark@Sun.COM return (B_TRUE); 227711042SErik.Nordmark@Sun.COM ip_input_cksum_err_v4(protocol, hck_flags, ira->ira_ill); 227811042SErik.Nordmark@Sun.COM return (B_FALSE); 227911042SErik.Nordmark@Sun.COM } 228011042SErik.Nordmark@Sun.COM 228111042SErik.Nordmark@Sun.COM mp1 = mp->b_cont; 228211042SErik.Nordmark@Sun.COM if ((hck_flags & HCK_PARTIALCKSUM) && 228311042SErik.Nordmark@Sun.COM (mp1 == NULL || mp1->b_cont == NULL) && 228411042SErik.Nordmark@Sun.COM ip_hdr_length >= DB_CKSUMSTART(mp) && 228511042SErik.Nordmark@Sun.COM ((len = ip_hdr_length - DB_CKSUMSTART(mp)) & 1) == 0) { 228611042SErik.Nordmark@Sun.COM uint32_t adj; 228711042SErik.Nordmark@Sun.COM uchar_t *cksum_start; 228811042SErik.Nordmark@Sun.COM 228911042SErik.Nordmark@Sun.COM cksum = ip_input_cksum_pseudo_v4(ipha, ira); 229011042SErik.Nordmark@Sun.COM 229111042SErik.Nordmark@Sun.COM cksum_start = ((uchar_t *)ipha + DB_CKSUMSTART(mp)); 229211042SErik.Nordmark@Sun.COM 229311042SErik.Nordmark@Sun.COM /* 229411042SErik.Nordmark@Sun.COM * Partial checksum has been calculated by hardware 229511042SErik.Nordmark@Sun.COM * and attached to the packet; in addition, any 229611042SErik.Nordmark@Sun.COM * prepended extraneous data is even byte aligned, 229711042SErik.Nordmark@Sun.COM * and there are at most two mblks associated with 229811042SErik.Nordmark@Sun.COM * the packet. If any such data exists, we adjust 229911042SErik.Nordmark@Sun.COM * the checksum; also take care any postpended data. 230011042SErik.Nordmark@Sun.COM */ 230111042SErik.Nordmark@Sun.COM IP_ADJCKSUM_PARTIAL(cksum_start, mp, mp1, len, adj); 230211042SErik.Nordmark@Sun.COM /* 230311042SErik.Nordmark@Sun.COM * One's complement subtract extraneous checksum 230411042SErik.Nordmark@Sun.COM */ 230511042SErik.Nordmark@Sun.COM cksum += DB_CKSUM16(mp); 230611042SErik.Nordmark@Sun.COM if (adj >= cksum) 230711042SErik.Nordmark@Sun.COM cksum = ~(adj - cksum) & 0xFFFF; 230811042SErik.Nordmark@Sun.COM else 230911042SErik.Nordmark@Sun.COM cksum -= adj; 231011042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + ((int)cksum >> 16); 231111042SErik.Nordmark@Sun.COM cksum = (cksum & 0xFFFF) + ((int)cksum >> 16); 231211042SErik.Nordmark@Sun.COM if (!(~cksum & 0xFFFF)) 231311042SErik.Nordmark@Sun.COM return (B_TRUE); 231411042SErik.Nordmark@Sun.COM 231511042SErik.Nordmark@Sun.COM ip_input_cksum_err_v4(protocol, hck_flags, ira->ira_ill); 231611042SErik.Nordmark@Sun.COM return (B_FALSE); 231711042SErik.Nordmark@Sun.COM } 231811042SErik.Nordmark@Sun.COM return (ip_input_sw_cksum_v4(mp, ipha, ira)); 231911042SErik.Nordmark@Sun.COM } 232011042SErik.Nordmark@Sun.COM 232111042SErik.Nordmark@Sun.COM 232211042SErik.Nordmark@Sun.COM /* 232311042SErik.Nordmark@Sun.COM * Handle fanout of received packets. 232411042SErik.Nordmark@Sun.COM * Unicast packets that are looped back (from ire_send_local_v4) and packets 232511042SErik.Nordmark@Sun.COM * from the wire are differentiated by checking IRAF_VERIFY_ULP_CKSUM. 232611042SErik.Nordmark@Sun.COM * 232711042SErik.Nordmark@Sun.COM * IPQoS Notes 232811042SErik.Nordmark@Sun.COM * Before sending it to the client, invoke IPPF processing. Policy processing 232911042SErik.Nordmark@Sun.COM * takes place only if the callout_position, IPP_LOCAL_IN, is enabled. 233011042SErik.Nordmark@Sun.COM */ 233111042SErik.Nordmark@Sun.COM void 233211042SErik.Nordmark@Sun.COM ip_fanout_v4(mblk_t *mp, ipha_t *ipha, ip_recv_attr_t *ira) 233311042SErik.Nordmark@Sun.COM { 233411042SErik.Nordmark@Sun.COM ill_t *ill = ira->ira_ill; 233511042SErik.Nordmark@Sun.COM iaflags_t iraflags = ira->ira_flags; 233611042SErik.Nordmark@Sun.COM ip_stack_t *ipst = ill->ill_ipst; 233711042SErik.Nordmark@Sun.COM uint8_t protocol = ipha->ipha_protocol; 233811042SErik.Nordmark@Sun.COM conn_t *connp; 233911042SErik.Nordmark@Sun.COM #define rptr ((uchar_t *)ipha) 234011042SErik.Nordmark@Sun.COM uint_t ip_hdr_length; 234111042SErik.Nordmark@Sun.COM uint_t min_ulp_header_length; 234211042SErik.Nordmark@Sun.COM int offset; 234311042SErik.Nordmark@Sun.COM ssize_t len; 234411042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack; 234511042SErik.Nordmark@Sun.COM ipsec_stack_t *ipss = ns->netstack_ipsec; 234611042SErik.Nordmark@Sun.COM ill_t *rill = ira->ira_rill; 234711042SErik.Nordmark@Sun.COM 234811042SErik.Nordmark@Sun.COM ASSERT(ira->ira_pktlen == ntohs(ipha->ipha_length)); 234911042SErik.Nordmark@Sun.COM 235011042SErik.Nordmark@Sun.COM ip_hdr_length = ira->ira_ip_hdr_length; 235111042SErik.Nordmark@Sun.COM ira->ira_protocol = protocol; 235211042SErik.Nordmark@Sun.COM 235311042SErik.Nordmark@Sun.COM /* 235411042SErik.Nordmark@Sun.COM * Time for IPP once we've done reassembly and IPsec. 235511042SErik.Nordmark@Sun.COM * We skip this for loopback packets since we don't do IPQoS 235611042SErik.Nordmark@Sun.COM * on loopback. 235711042SErik.Nordmark@Sun.COM */ 235811042SErik.Nordmark@Sun.COM if (IPP_ENABLED(IPP_LOCAL_IN, ipst) && 235911042SErik.Nordmark@Sun.COM !(iraflags & IRAF_LOOPBACK) && 236011042SErik.Nordmark@Sun.COM (protocol != IPPROTO_ESP || protocol != IPPROTO_AH)) { 236111042SErik.Nordmark@Sun.COM /* 236211042SErik.Nordmark@Sun.COM * Use the interface on which the packet arrived - not where 236311042SErik.Nordmark@Sun.COM * the IP address is hosted. 236411042SErik.Nordmark@Sun.COM */ 236511042SErik.Nordmark@Sun.COM /* ip_process translates an IS_UNDER_IPMP */ 236611042SErik.Nordmark@Sun.COM mp = ip_process(IPP_LOCAL_IN, mp, rill, ill); 236711042SErik.Nordmark@Sun.COM if (mp == NULL) { 236811042SErik.Nordmark@Sun.COM /* ip_drop_packet and MIB done */ 236911042SErik.Nordmark@Sun.COM return; 237011042SErik.Nordmark@Sun.COM } 237111042SErik.Nordmark@Sun.COM } 237211042SErik.Nordmark@Sun.COM 237311042SErik.Nordmark@Sun.COM /* Determine the minimum required size of the upper-layer header */ 237411042SErik.Nordmark@Sun.COM /* Need to do this for at least the set of ULPs that TX handles. */ 237511042SErik.Nordmark@Sun.COM switch (protocol) { 237611042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 237711042SErik.Nordmark@Sun.COM min_ulp_header_length = TCP_MIN_HEADER_LENGTH; 237811042SErik.Nordmark@Sun.COM break; 237911042SErik.Nordmark@Sun.COM case IPPROTO_SCTP: 238011042SErik.Nordmark@Sun.COM min_ulp_header_length = SCTP_COMMON_HDR_LENGTH; 238111042SErik.Nordmark@Sun.COM break; 238211042SErik.Nordmark@Sun.COM case IPPROTO_UDP: 238311042SErik.Nordmark@Sun.COM min_ulp_header_length = UDPH_SIZE; 238411042SErik.Nordmark@Sun.COM break; 238511042SErik.Nordmark@Sun.COM case IPPROTO_ICMP: 238611042SErik.Nordmark@Sun.COM min_ulp_header_length = ICMPH_SIZE; 238711042SErik.Nordmark@Sun.COM break; 238811042SErik.Nordmark@Sun.COM default: 238911042SErik.Nordmark@Sun.COM min_ulp_header_length = 0; 239011042SErik.Nordmark@Sun.COM break; 239111042SErik.Nordmark@Sun.COM } 239211042SErik.Nordmark@Sun.COM /* Make sure we have the min ULP header length */ 239311042SErik.Nordmark@Sun.COM len = mp->b_wptr - rptr; 239411042SErik.Nordmark@Sun.COM if (len < ip_hdr_length + min_ulp_header_length) { 239511042SErik.Nordmark@Sun.COM if (ira->ira_pktlen < ip_hdr_length + min_ulp_header_length) { 239611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInTruncatedPkts); 239711042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInTruncatedPkts", mp, ill); 239811042SErik.Nordmark@Sun.COM freemsg(mp); 239911042SErik.Nordmark@Sun.COM return; 240011042SErik.Nordmark@Sun.COM } 240111042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_recv_pullup); 240211042SErik.Nordmark@Sun.COM ipha = ip_pullup(mp, ip_hdr_length + min_ulp_header_length, 240311042SErik.Nordmark@Sun.COM ira); 240411042SErik.Nordmark@Sun.COM if (ipha == NULL) 240511042SErik.Nordmark@Sun.COM goto discard; 240611042SErik.Nordmark@Sun.COM len = mp->b_wptr - rptr; 240711042SErik.Nordmark@Sun.COM } 240811042SErik.Nordmark@Sun.COM 240911042SErik.Nordmark@Sun.COM /* 241011042SErik.Nordmark@Sun.COM * If trusted extensions then determine the zoneid and TX specific 241111042SErik.Nordmark@Sun.COM * ira_flags. 241211042SErik.Nordmark@Sun.COM */ 241311042SErik.Nordmark@Sun.COM if (iraflags & IRAF_SYSTEM_LABELED) { 241411042SErik.Nordmark@Sun.COM /* This can update ira->ira_flags and ira->ira_zoneid */ 241511042SErik.Nordmark@Sun.COM ip_fanout_tx_v4(mp, ipha, protocol, ip_hdr_length, ira); 241611042SErik.Nordmark@Sun.COM iraflags = ira->ira_flags; 241711042SErik.Nordmark@Sun.COM } 241811042SErik.Nordmark@Sun.COM 241911042SErik.Nordmark@Sun.COM 242011042SErik.Nordmark@Sun.COM /* Verify ULP checksum. Handles TCP, UDP, and SCTP */ 242111042SErik.Nordmark@Sun.COM if (iraflags & IRAF_VERIFY_ULP_CKSUM) { 242211042SErik.Nordmark@Sun.COM if (!ip_input_cksum_v4(iraflags, mp, ipha, ira)) { 242311042SErik.Nordmark@Sun.COM /* Bad checksum. Stats are already incremented */ 242411042SErik.Nordmark@Sun.COM ip_drop_input("Bad ULP checksum", mp, ill); 242511042SErik.Nordmark@Sun.COM freemsg(mp); 242611042SErik.Nordmark@Sun.COM return; 242711042SErik.Nordmark@Sun.COM } 242811042SErik.Nordmark@Sun.COM /* IRAF_SCTP_CSUM_ERR could have been set */ 242911042SErik.Nordmark@Sun.COM iraflags = ira->ira_flags; 243011042SErik.Nordmark@Sun.COM } 243111042SErik.Nordmark@Sun.COM switch (protocol) { 243211042SErik.Nordmark@Sun.COM case IPPROTO_TCP: 243311042SErik.Nordmark@Sun.COM /* For TCP, discard broadcast and multicast packets. */ 243411042SErik.Nordmark@Sun.COM if (iraflags & IRAF_MULTIBROADCAST) 243511042SErik.Nordmark@Sun.COM goto discard; 243611042SErik.Nordmark@Sun.COM 243711042SErik.Nordmark@Sun.COM /* First mblk contains IP+TCP headers per above check */ 243811042SErik.Nordmark@Sun.COM ASSERT(len >= ip_hdr_length + TCP_MIN_HEADER_LENGTH); 243911042SErik.Nordmark@Sun.COM 244011042SErik.Nordmark@Sun.COM /* TCP options present? */ 244111042SErik.Nordmark@Sun.COM offset = ((uchar_t *)ipha)[ip_hdr_length + 12] >> 4; 244211042SErik.Nordmark@Sun.COM if (offset != 5) { 244311042SErik.Nordmark@Sun.COM if (offset < 5) 244411042SErik.Nordmark@Sun.COM goto discard; 244511042SErik.Nordmark@Sun.COM 244611042SErik.Nordmark@Sun.COM /* 244711042SErik.Nordmark@Sun.COM * There must be TCP options. 244811042SErik.Nordmark@Sun.COM * Make sure we can grab them. 244911042SErik.Nordmark@Sun.COM */ 245011042SErik.Nordmark@Sun.COM offset <<= 2; 245111042SErik.Nordmark@Sun.COM offset += ip_hdr_length; 245211042SErik.Nordmark@Sun.COM if (len < offset) { 245311042SErik.Nordmark@Sun.COM if (ira->ira_pktlen < offset) { 245411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 245511042SErik.Nordmark@Sun.COM ipIfStatsInTruncatedPkts); 245611042SErik.Nordmark@Sun.COM ip_drop_input( 245711042SErik.Nordmark@Sun.COM "ipIfStatsInTruncatedPkts", 245811042SErik.Nordmark@Sun.COM mp, ill); 245911042SErik.Nordmark@Sun.COM freemsg(mp); 246011042SErik.Nordmark@Sun.COM return; 246111042SErik.Nordmark@Sun.COM } 246211042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_recv_pullup); 246311042SErik.Nordmark@Sun.COM ipha = ip_pullup(mp, offset, ira); 246411042SErik.Nordmark@Sun.COM if (ipha == NULL) 246511042SErik.Nordmark@Sun.COM goto discard; 246611042SErik.Nordmark@Sun.COM len = mp->b_wptr - rptr; 246711042SErik.Nordmark@Sun.COM } 246811042SErik.Nordmark@Sun.COM } 246911042SErik.Nordmark@Sun.COM 247011042SErik.Nordmark@Sun.COM /* 247111042SErik.Nordmark@Sun.COM * Pass up a squeue hint to tcp. 247211042SErik.Nordmark@Sun.COM * If ira_sqp is already set (this is loopback) we leave it 247311042SErik.Nordmark@Sun.COM * alone. 247411042SErik.Nordmark@Sun.COM */ 247511042SErik.Nordmark@Sun.COM if (ira->ira_sqp == NULL) { 247611042SErik.Nordmark@Sun.COM ira->ira_sqp = ip_squeue_get(ira->ira_ring); 247711042SErik.Nordmark@Sun.COM } 247811042SErik.Nordmark@Sun.COM 247911042SErik.Nordmark@Sun.COM /* Look for AF_INET or AF_INET6 that matches */ 248011042SErik.Nordmark@Sun.COM connp = ipcl_classify_v4(mp, IPPROTO_TCP, ip_hdr_length, 248111042SErik.Nordmark@Sun.COM ira, ipst); 248211042SErik.Nordmark@Sun.COM if (connp == NULL) { 248311042SErik.Nordmark@Sun.COM /* Send the TH_RST */ 248411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 248511042SErik.Nordmark@Sun.COM tcp_xmit_listeners_reset(mp, ira, ipst, NULL); 248611042SErik.Nordmark@Sun.COM return; 248711042SErik.Nordmark@Sun.COM } 248811042SErik.Nordmark@Sun.COM if (connp->conn_incoming_ifindex != 0 && 248911042SErik.Nordmark@Sun.COM connp->conn_incoming_ifindex != ira->ira_ruifindex) { 249011042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 249111042SErik.Nordmark@Sun.COM 249211042SErik.Nordmark@Sun.COM /* Send the TH_RST */ 249311042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 249411042SErik.Nordmark@Sun.COM tcp_xmit_listeners_reset(mp, ira, ipst, NULL); 249511042SErik.Nordmark@Sun.COM return; 249611042SErik.Nordmark@Sun.COM } 249711042SErik.Nordmark@Sun.COM if (CONN_INBOUND_POLICY_PRESENT(connp, ipss) || 249811042SErik.Nordmark@Sun.COM (iraflags & IRAF_IPSEC_SECURE)) { 249911042SErik.Nordmark@Sun.COM mp = ipsec_check_inbound_policy(mp, connp, 250011042SErik.Nordmark@Sun.COM ipha, NULL, ira); 250111042SErik.Nordmark@Sun.COM if (mp == NULL) { 250211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 250311042SErik.Nordmark@Sun.COM /* Note that mp is NULL */ 250411042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 250511042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 250611042SErik.Nordmark@Sun.COM return; 250711042SErik.Nordmark@Sun.COM } 250811042SErik.Nordmark@Sun.COM } 250911042SErik.Nordmark@Sun.COM /* Found a client; up it goes */ 251011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 251111042SErik.Nordmark@Sun.COM ira->ira_ill = ira->ira_rill = NULL; 251211042SErik.Nordmark@Sun.COM if (!IPCL_IS_TCP(connp)) { 251311042SErik.Nordmark@Sun.COM /* Not TCP; must be SOCK_RAW, IPPROTO_TCP */ 251411042SErik.Nordmark@Sun.COM (connp->conn_recv)(connp, mp, NULL, ira); 251511042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 251611042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 251711042SErik.Nordmark@Sun.COM ira->ira_rill = rill; 251811042SErik.Nordmark@Sun.COM return; 251911042SErik.Nordmark@Sun.COM } 252011042SErik.Nordmark@Sun.COM 252111042SErik.Nordmark@Sun.COM /* 252211042SErik.Nordmark@Sun.COM * We do different processing whether called from 252311042SErik.Nordmark@Sun.COM * ip_accept_tcp and we match the target, don't match 252411042SErik.Nordmark@Sun.COM * the target, and when we are called by ip_input. 252511042SErik.Nordmark@Sun.COM */ 252611042SErik.Nordmark@Sun.COM if (iraflags & IRAF_TARGET_SQP) { 252711042SErik.Nordmark@Sun.COM if (ira->ira_target_sqp == connp->conn_sqp) { 252811042SErik.Nordmark@Sun.COM mblk_t *attrmp; 252911042SErik.Nordmark@Sun.COM 253011042SErik.Nordmark@Sun.COM attrmp = ip_recv_attr_to_mblk(ira); 253111042SErik.Nordmark@Sun.COM if (attrmp == NULL) { 253211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 253311042SErik.Nordmark@Sun.COM ipIfStatsInDiscards); 253411042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", 253511042SErik.Nordmark@Sun.COM mp, ill); 253611042SErik.Nordmark@Sun.COM freemsg(mp); 253711042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 253811042SErik.Nordmark@Sun.COM } else { 253911042SErik.Nordmark@Sun.COM SET_SQUEUE(attrmp, connp->conn_recv, 254011042SErik.Nordmark@Sun.COM connp); 254111042SErik.Nordmark@Sun.COM attrmp->b_cont = mp; 254211042SErik.Nordmark@Sun.COM ASSERT(ira->ira_target_sqp_mp == NULL); 254311042SErik.Nordmark@Sun.COM ira->ira_target_sqp_mp = attrmp; 254411042SErik.Nordmark@Sun.COM /* 254511042SErik.Nordmark@Sun.COM * Conn ref release when drained from 254611042SErik.Nordmark@Sun.COM * the squeue. 254711042SErik.Nordmark@Sun.COM */ 254811042SErik.Nordmark@Sun.COM } 254911042SErik.Nordmark@Sun.COM } else { 255011042SErik.Nordmark@Sun.COM SQUEUE_ENTER_ONE(connp->conn_sqp, mp, 255111042SErik.Nordmark@Sun.COM connp->conn_recv, connp, ira, SQ_FILL, 255211042SErik.Nordmark@Sun.COM SQTAG_IP_TCP_INPUT); 255311042SErik.Nordmark@Sun.COM } 255411042SErik.Nordmark@Sun.COM } else { 255511042SErik.Nordmark@Sun.COM SQUEUE_ENTER_ONE(connp->conn_sqp, mp, connp->conn_recv, 255611042SErik.Nordmark@Sun.COM connp, ira, ip_squeue_flag, SQTAG_IP_TCP_INPUT); 255711042SErik.Nordmark@Sun.COM } 255811042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 255911042SErik.Nordmark@Sun.COM ira->ira_rill = rill; 256011042SErik.Nordmark@Sun.COM return; 256111042SErik.Nordmark@Sun.COM 256211042SErik.Nordmark@Sun.COM case IPPROTO_SCTP: { 256311042SErik.Nordmark@Sun.COM sctp_hdr_t *sctph; 256411042SErik.Nordmark@Sun.COM in6_addr_t map_src, map_dst; 256511042SErik.Nordmark@Sun.COM uint32_t ports; /* Source and destination ports */ 256611042SErik.Nordmark@Sun.COM sctp_stack_t *sctps = ipst->ips_netstack->netstack_sctp; 256711042SErik.Nordmark@Sun.COM 256811042SErik.Nordmark@Sun.COM /* For SCTP, discard broadcast and multicast packets. */ 256911042SErik.Nordmark@Sun.COM if (iraflags & IRAF_MULTIBROADCAST) 257011042SErik.Nordmark@Sun.COM goto discard; 257111042SErik.Nordmark@Sun.COM 257211042SErik.Nordmark@Sun.COM /* 257311042SErik.Nordmark@Sun.COM * Since there is no SCTP h/w cksum support yet, just 257411042SErik.Nordmark@Sun.COM * clear the flag. 257511042SErik.Nordmark@Sun.COM */ 257611042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 257711042SErik.Nordmark@Sun.COM 257811042SErik.Nordmark@Sun.COM /* Length ensured above */ 257911042SErik.Nordmark@Sun.COM ASSERT(MBLKL(mp) >= ip_hdr_length + SCTP_COMMON_HDR_LENGTH); 258011042SErik.Nordmark@Sun.COM sctph = (sctp_hdr_t *)(rptr + ip_hdr_length); 258111042SErik.Nordmark@Sun.COM 258211042SErik.Nordmark@Sun.COM /* get the ports */ 258311042SErik.Nordmark@Sun.COM ports = *(uint32_t *)&sctph->sh_sport; 258411042SErik.Nordmark@Sun.COM 258511042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &map_dst); 258611042SErik.Nordmark@Sun.COM IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &map_src); 258711042SErik.Nordmark@Sun.COM if (iraflags & IRAF_SCTP_CSUM_ERR) { 258811042SErik.Nordmark@Sun.COM /* 258911042SErik.Nordmark@Sun.COM * No potential sctp checksum errors go to the Sun 259011042SErik.Nordmark@Sun.COM * sctp stack however they might be Adler-32 summed 259111042SErik.Nordmark@Sun.COM * packets a userland stack bound to a raw IP socket 259211042SErik.Nordmark@Sun.COM * could reasonably use. Note though that Adler-32 is 259311042SErik.Nordmark@Sun.COM * a long deprecated algorithm and customer sctp 259411042SErik.Nordmark@Sun.COM * networks should eventually migrate to CRC-32 at 259511042SErik.Nordmark@Sun.COM * which time this facility should be removed. 259611042SErik.Nordmark@Sun.COM */ 259711042SErik.Nordmark@Sun.COM ip_fanout_sctp_raw(mp, ipha, NULL, ports, ira); 259811042SErik.Nordmark@Sun.COM return; 259911042SErik.Nordmark@Sun.COM } 260011042SErik.Nordmark@Sun.COM connp = sctp_fanout(&map_src, &map_dst, ports, ira, mp, sctps); 260111042SErik.Nordmark@Sun.COM if (connp == NULL) { 260211042SErik.Nordmark@Sun.COM /* Check for raw socket or OOTB handling */ 260311042SErik.Nordmark@Sun.COM ip_fanout_sctp_raw(mp, ipha, NULL, ports, ira); 260411042SErik.Nordmark@Sun.COM return; 260511042SErik.Nordmark@Sun.COM } 260611042SErik.Nordmark@Sun.COM if (connp->conn_incoming_ifindex != 0 && 260711042SErik.Nordmark@Sun.COM connp->conn_incoming_ifindex != ira->ira_ruifindex) { 260811042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 260911042SErik.Nordmark@Sun.COM /* Check for raw socket or OOTB handling */ 261011042SErik.Nordmark@Sun.COM ip_fanout_sctp_raw(mp, ipha, NULL, ports, ira); 261111042SErik.Nordmark@Sun.COM return; 261211042SErik.Nordmark@Sun.COM } 261311042SErik.Nordmark@Sun.COM 261411042SErik.Nordmark@Sun.COM /* Found a client; up it goes */ 261511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 261611042SErik.Nordmark@Sun.COM sctp_input(connp, ipha, NULL, mp, ira); 261711042SErik.Nordmark@Sun.COM /* sctp_input does a rele of the sctp_t */ 261811042SErik.Nordmark@Sun.COM return; 261911042SErik.Nordmark@Sun.COM } 262011042SErik.Nordmark@Sun.COM 262111042SErik.Nordmark@Sun.COM case IPPROTO_UDP: 262211042SErik.Nordmark@Sun.COM /* First mblk contains IP+UDP headers as checked above */ 262311042SErik.Nordmark@Sun.COM ASSERT(MBLKL(mp) >= ip_hdr_length + UDPH_SIZE); 262411042SErik.Nordmark@Sun.COM 262511042SErik.Nordmark@Sun.COM if (iraflags & IRAF_MULTIBROADCAST) { 262611042SErik.Nordmark@Sun.COM uint16_t *up; /* Pointer to ports in ULP header */ 262711042SErik.Nordmark@Sun.COM 262811042SErik.Nordmark@Sun.COM up = (uint16_t *)((uchar_t *)ipha + ip_hdr_length); 262911042SErik.Nordmark@Sun.COM ip_fanout_udp_multi_v4(mp, ipha, up[1], up[0], ira); 263011042SErik.Nordmark@Sun.COM return; 263111042SErik.Nordmark@Sun.COM } 263211042SErik.Nordmark@Sun.COM 263311042SErik.Nordmark@Sun.COM /* Look for AF_INET or AF_INET6 that matches */ 263411042SErik.Nordmark@Sun.COM connp = ipcl_classify_v4(mp, IPPROTO_UDP, ip_hdr_length, 263511042SErik.Nordmark@Sun.COM ira, ipst); 263611042SErik.Nordmark@Sun.COM if (connp == NULL) { 263711042SErik.Nordmark@Sun.COM no_udp_match: 263811042SErik.Nordmark@Sun.COM if (ipst->ips_ipcl_proto_fanout_v4[IPPROTO_UDP]. 263911042SErik.Nordmark@Sun.COM connf_head != NULL) { 264011042SErik.Nordmark@Sun.COM ASSERT(ira->ira_protocol == IPPROTO_UDP); 264111042SErik.Nordmark@Sun.COM ip_fanout_proto_v4(mp, ipha, ira); 264211042SErik.Nordmark@Sun.COM } else { 264311042SErik.Nordmark@Sun.COM ip_fanout_send_icmp_v4(mp, 264411042SErik.Nordmark@Sun.COM ICMP_DEST_UNREACHABLE, 264511042SErik.Nordmark@Sun.COM ICMP_PORT_UNREACHABLE, ira); 264611042SErik.Nordmark@Sun.COM } 264711042SErik.Nordmark@Sun.COM return; 264811042SErik.Nordmark@Sun.COM 264911042SErik.Nordmark@Sun.COM } 265011042SErik.Nordmark@Sun.COM if (connp->conn_incoming_ifindex != 0 && 265111042SErik.Nordmark@Sun.COM connp->conn_incoming_ifindex != ira->ira_ruifindex) { 265211042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 265311042SErik.Nordmark@Sun.COM goto no_udp_match; 265411042SErik.Nordmark@Sun.COM } 265511042SErik.Nordmark@Sun.COM if (IPCL_IS_NONSTR(connp) ? connp->conn_flow_cntrld : 265611042SErik.Nordmark@Sun.COM !canputnext(connp->conn_rq)) { 265711042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 265811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, udpIfStatsInOverflows); 265911042SErik.Nordmark@Sun.COM ip_drop_input("udpIfStatsInOverflows", mp, ill); 266011042SErik.Nordmark@Sun.COM freemsg(mp); 266111042SErik.Nordmark@Sun.COM return; 266211042SErik.Nordmark@Sun.COM } 266311042SErik.Nordmark@Sun.COM if (CONN_INBOUND_POLICY_PRESENT(connp, ipss) || 266411042SErik.Nordmark@Sun.COM (iraflags & IRAF_IPSEC_SECURE)) { 266511042SErik.Nordmark@Sun.COM mp = ipsec_check_inbound_policy(mp, connp, 266611042SErik.Nordmark@Sun.COM ipha, NULL, ira); 266711042SErik.Nordmark@Sun.COM if (mp == NULL) { 266811042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 266911042SErik.Nordmark@Sun.COM /* Note that mp is NULL */ 267011042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 267111042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 267211042SErik.Nordmark@Sun.COM return; 267311042SErik.Nordmark@Sun.COM } 267411042SErik.Nordmark@Sun.COM } 267511042SErik.Nordmark@Sun.COM /* 267611042SErik.Nordmark@Sun.COM * Remove 0-spi if it's 0, or move everything behind 267711042SErik.Nordmark@Sun.COM * the UDP header over it and forward to ESP via 267811042SErik.Nordmark@Sun.COM * ip_fanout_v4(). 267911042SErik.Nordmark@Sun.COM */ 268011042SErik.Nordmark@Sun.COM if (connp->conn_udp->udp_nat_t_endpoint) { 268111042SErik.Nordmark@Sun.COM if (iraflags & IRAF_IPSEC_SECURE) { 268211042SErik.Nordmark@Sun.COM ip_drop_packet(mp, B_TRUE, ira->ira_ill, 268311042SErik.Nordmark@Sun.COM DROPPER(ipss, ipds_esp_nat_t_ipsec), 268411042SErik.Nordmark@Sun.COM &ipss->ipsec_dropper); 268511042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 268611042SErik.Nordmark@Sun.COM return; 268711042SErik.Nordmark@Sun.COM } 268811042SErik.Nordmark@Sun.COM 268911042SErik.Nordmark@Sun.COM mp = zero_spi_check(mp, ira); 269011042SErik.Nordmark@Sun.COM if (mp == NULL) { 269111042SErik.Nordmark@Sun.COM /* 269211042SErik.Nordmark@Sun.COM * Packet was consumed - probably sent to 269311042SErik.Nordmark@Sun.COM * ip_fanout_v4. 269411042SErik.Nordmark@Sun.COM */ 269511042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 269611042SErik.Nordmark@Sun.COM return; 269711042SErik.Nordmark@Sun.COM } 269811042SErik.Nordmark@Sun.COM /* Else continue like a normal UDP packet. */ 269911042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 270011042SErik.Nordmark@Sun.COM protocol = ipha->ipha_protocol; 270111042SErik.Nordmark@Sun.COM ira->ira_protocol = protocol; 270211042SErik.Nordmark@Sun.COM } 270311042SErik.Nordmark@Sun.COM /* Found a client; up it goes */ 270411042SErik.Nordmark@Sun.COM IP_STAT(ipst, ip_udp_fannorm); 270511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 270611042SErik.Nordmark@Sun.COM ira->ira_ill = ira->ira_rill = NULL; 270711042SErik.Nordmark@Sun.COM (connp->conn_recv)(connp, mp, NULL, ira); 270811042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 270911042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 271011042SErik.Nordmark@Sun.COM ira->ira_rill = rill; 271111042SErik.Nordmark@Sun.COM return; 271211042SErik.Nordmark@Sun.COM default: 271311042SErik.Nordmark@Sun.COM break; 271411042SErik.Nordmark@Sun.COM } 271511042SErik.Nordmark@Sun.COM 271611042SErik.Nordmark@Sun.COM /* 271711042SErik.Nordmark@Sun.COM * Clear hardware checksumming flag as it is currently only 271811042SErik.Nordmark@Sun.COM * used by TCP and UDP. 271911042SErik.Nordmark@Sun.COM */ 272011042SErik.Nordmark@Sun.COM DB_CKSUMFLAGS(mp) = 0; 272111042SErik.Nordmark@Sun.COM 272211042SErik.Nordmark@Sun.COM switch (protocol) { 272311042SErik.Nordmark@Sun.COM case IPPROTO_ICMP: 272411042SErik.Nordmark@Sun.COM /* 272511042SErik.Nordmark@Sun.COM * We need to accomodate icmp messages coming in clear 272611042SErik.Nordmark@Sun.COM * until we get everything secure from the wire. If 272711042SErik.Nordmark@Sun.COM * icmp_accept_clear_messages is zero we check with 272811042SErik.Nordmark@Sun.COM * the global policy and act accordingly. If it is 272911042SErik.Nordmark@Sun.COM * non-zero, we accept the message without any checks. 273011042SErik.Nordmark@Sun.COM * But *this does not mean* that this will be delivered 273111042SErik.Nordmark@Sun.COM * to RAW socket clients. By accepting we might send 273211042SErik.Nordmark@Sun.COM * replies back, change our MTU value etc., 273311042SErik.Nordmark@Sun.COM * but delivery to the ULP/clients depends on their 273411042SErik.Nordmark@Sun.COM * policy dispositions. 273511042SErik.Nordmark@Sun.COM */ 273611042SErik.Nordmark@Sun.COM if (ipst->ips_icmp_accept_clear_messages == 0) { 273711042SErik.Nordmark@Sun.COM mp = ipsec_check_global_policy(mp, NULL, 273811042SErik.Nordmark@Sun.COM ipha, NULL, ira, ns); 273911042SErik.Nordmark@Sun.COM if (mp == NULL) 274011042SErik.Nordmark@Sun.COM return; 274111042SErik.Nordmark@Sun.COM } 274211042SErik.Nordmark@Sun.COM 274311042SErik.Nordmark@Sun.COM /* 274411042SErik.Nordmark@Sun.COM * On a labeled system, we have to check whether the zone 274511042SErik.Nordmark@Sun.COM * itself is permitted to receive raw traffic. 274611042SErik.Nordmark@Sun.COM */ 274711042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 274811042SErik.Nordmark@Sun.COM if (!tsol_can_accept_raw(mp, ira, B_FALSE)) { 274911042SErik.Nordmark@Sun.COM BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors); 275011042SErik.Nordmark@Sun.COM ip_drop_input("tsol_can_accept_raw", mp, ill); 275111042SErik.Nordmark@Sun.COM freemsg(mp); 275211042SErik.Nordmark@Sun.COM return; 275311042SErik.Nordmark@Sun.COM } 275411042SErik.Nordmark@Sun.COM } 275511042SErik.Nordmark@Sun.COM 275611042SErik.Nordmark@Sun.COM /* 275711042SErik.Nordmark@Sun.COM * ICMP header checksum, including checksum field, 275811042SErik.Nordmark@Sun.COM * should be zero. 275911042SErik.Nordmark@Sun.COM */ 276011042SErik.Nordmark@Sun.COM if (IP_CSUM(mp, ip_hdr_length, 0)) { 276111042SErik.Nordmark@Sun.COM BUMP_MIB(&ipst->ips_icmp_mib, icmpInCksumErrs); 276211042SErik.Nordmark@Sun.COM ip_drop_input("icmpInCksumErrs", mp, ill); 276311042SErik.Nordmark@Sun.COM freemsg(mp); 276411042SErik.Nordmark@Sun.COM return; 276511042SErik.Nordmark@Sun.COM } 276611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 276711042SErik.Nordmark@Sun.COM mp = icmp_inbound_v4(mp, ira); 276811042SErik.Nordmark@Sun.COM if (mp == NULL) { 276911042SErik.Nordmark@Sun.COM /* No need to pass to RAW sockets */ 277011042SErik.Nordmark@Sun.COM return; 277111042SErik.Nordmark@Sun.COM } 277211042SErik.Nordmark@Sun.COM break; 277311042SErik.Nordmark@Sun.COM 277411042SErik.Nordmark@Sun.COM case IPPROTO_IGMP: 277511042SErik.Nordmark@Sun.COM /* 277611042SErik.Nordmark@Sun.COM * If we are not willing to accept IGMP packets in clear, 277711042SErik.Nordmark@Sun.COM * then check with global policy. 277811042SErik.Nordmark@Sun.COM */ 277911042SErik.Nordmark@Sun.COM if (ipst->ips_igmp_accept_clear_messages == 0) { 278011042SErik.Nordmark@Sun.COM mp = ipsec_check_global_policy(mp, NULL, 278111042SErik.Nordmark@Sun.COM ipha, NULL, ira, ns); 278211042SErik.Nordmark@Sun.COM if (mp == NULL) 278311042SErik.Nordmark@Sun.COM return; 278411042SErik.Nordmark@Sun.COM } 278511042SErik.Nordmark@Sun.COM if ((ira->ira_flags & IRAF_SYSTEM_LABELED) && 278611042SErik.Nordmark@Sun.COM !tsol_can_accept_raw(mp, ira, B_TRUE)) { 278711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 278811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 278911042SErik.Nordmark@Sun.COM freemsg(mp); 279011042SErik.Nordmark@Sun.COM return; 279111042SErik.Nordmark@Sun.COM } 279211042SErik.Nordmark@Sun.COM /* 279311042SErik.Nordmark@Sun.COM * Validate checksum 279411042SErik.Nordmark@Sun.COM */ 279511042SErik.Nordmark@Sun.COM if (IP_CSUM(mp, ip_hdr_length, 0)) { 279611042SErik.Nordmark@Sun.COM ++ipst->ips_igmpstat.igps_rcv_badsum; 279711042SErik.Nordmark@Sun.COM ip_drop_input("igps_rcv_badsum", mp, ill); 279811042SErik.Nordmark@Sun.COM freemsg(mp); 279911042SErik.Nordmark@Sun.COM return; 280011042SErik.Nordmark@Sun.COM } 280111042SErik.Nordmark@Sun.COM 280211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 280311042SErik.Nordmark@Sun.COM mp = igmp_input(mp, ira); 280411042SErik.Nordmark@Sun.COM if (mp == NULL) { 280511042SErik.Nordmark@Sun.COM /* Bad packet - discarded by igmp_input */ 280611042SErik.Nordmark@Sun.COM return; 280711042SErik.Nordmark@Sun.COM } 280811042SErik.Nordmark@Sun.COM break; 280911042SErik.Nordmark@Sun.COM case IPPROTO_PIM: 281011042SErik.Nordmark@Sun.COM /* 281111042SErik.Nordmark@Sun.COM * If we are not willing to accept PIM packets in clear, 281211042SErik.Nordmark@Sun.COM * then check with global policy. 281311042SErik.Nordmark@Sun.COM */ 281411042SErik.Nordmark@Sun.COM if (ipst->ips_pim_accept_clear_messages == 0) { 281511042SErik.Nordmark@Sun.COM mp = ipsec_check_global_policy(mp, NULL, 281611042SErik.Nordmark@Sun.COM ipha, NULL, ira, ns); 281711042SErik.Nordmark@Sun.COM if (mp == NULL) 281811042SErik.Nordmark@Sun.COM return; 281911042SErik.Nordmark@Sun.COM } 282011042SErik.Nordmark@Sun.COM if ((ira->ira_flags & IRAF_SYSTEM_LABELED) && 282111042SErik.Nordmark@Sun.COM !tsol_can_accept_raw(mp, ira, B_TRUE)) { 282211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 282311042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 282411042SErik.Nordmark@Sun.COM freemsg(mp); 282511042SErik.Nordmark@Sun.COM return; 282611042SErik.Nordmark@Sun.COM } 282711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 282811042SErik.Nordmark@Sun.COM 282911042SErik.Nordmark@Sun.COM /* Checksum is verified in pim_input */ 283011042SErik.Nordmark@Sun.COM mp = pim_input(mp, ira); 283111042SErik.Nordmark@Sun.COM if (mp == NULL) { 283211042SErik.Nordmark@Sun.COM /* Bad packet - discarded by pim_input */ 283311042SErik.Nordmark@Sun.COM return; 283411042SErik.Nordmark@Sun.COM } 283511042SErik.Nordmark@Sun.COM break; 283611042SErik.Nordmark@Sun.COM case IPPROTO_AH: 283711042SErik.Nordmark@Sun.COM case IPPROTO_ESP: { 283811042SErik.Nordmark@Sun.COM /* 283911042SErik.Nordmark@Sun.COM * Fast path for AH/ESP. 284011042SErik.Nordmark@Sun.COM */ 284111042SErik.Nordmark@Sun.COM netstack_t *ns = ipst->ips_netstack; 284211042SErik.Nordmark@Sun.COM ipsec_stack_t *ipss = ns->netstack_ipsec; 284311042SErik.Nordmark@Sun.COM 284411042SErik.Nordmark@Sun.COM IP_STAT(ipst, ipsec_proto_ahesp); 284511042SErik.Nordmark@Sun.COM 284611042SErik.Nordmark@Sun.COM if (!ipsec_loaded(ipss)) { 284711042SErik.Nordmark@Sun.COM ip_proto_not_sup(mp, ira); 284811042SErik.Nordmark@Sun.COM return; 284911042SErik.Nordmark@Sun.COM } 285011042SErik.Nordmark@Sun.COM 285111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 285211042SErik.Nordmark@Sun.COM /* select inbound SA and have IPsec process the pkt */ 285311042SErik.Nordmark@Sun.COM if (protocol == IPPROTO_ESP) { 285411042SErik.Nordmark@Sun.COM esph_t *esph; 285511042SErik.Nordmark@Sun.COM boolean_t esp_in_udp_sa; 285611042SErik.Nordmark@Sun.COM boolean_t esp_in_udp_packet; 285711042SErik.Nordmark@Sun.COM 285811042SErik.Nordmark@Sun.COM mp = ipsec_inbound_esp_sa(mp, ira, &esph); 285911042SErik.Nordmark@Sun.COM if (mp == NULL) 286011042SErik.Nordmark@Sun.COM return; 286111042SErik.Nordmark@Sun.COM 286211042SErik.Nordmark@Sun.COM ASSERT(esph != NULL); 286311042SErik.Nordmark@Sun.COM ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 286411042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ipsec_esp_sa != NULL); 286511042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ipsec_esp_sa->ipsa_input_func != NULL); 286611042SErik.Nordmark@Sun.COM 286711042SErik.Nordmark@Sun.COM esp_in_udp_sa = ((ira->ira_ipsec_esp_sa->ipsa_flags & 286811042SErik.Nordmark@Sun.COM IPSA_F_NATT) != 0); 286911042SErik.Nordmark@Sun.COM esp_in_udp_packet = 287011042SErik.Nordmark@Sun.COM (ira->ira_flags & IRAF_ESP_UDP_PORTS) != 0; 287111042SErik.Nordmark@Sun.COM 287211042SErik.Nordmark@Sun.COM /* 287311042SErik.Nordmark@Sun.COM * The following is a fancy, but quick, way of saying: 287411042SErik.Nordmark@Sun.COM * ESP-in-UDP SA and Raw ESP packet --> drop 287511042SErik.Nordmark@Sun.COM * OR 287611042SErik.Nordmark@Sun.COM * ESP SA and ESP-in-UDP packet --> drop 287711042SErik.Nordmark@Sun.COM */ 287811042SErik.Nordmark@Sun.COM if (esp_in_udp_sa != esp_in_udp_packet) { 287911042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 288011042SErik.Nordmark@Sun.COM ip_drop_packet(mp, B_TRUE, ira->ira_ill, 288111042SErik.Nordmark@Sun.COM DROPPER(ipss, ipds_esp_no_sa), 288211042SErik.Nordmark@Sun.COM &ipss->ipsec_dropper); 288311042SErik.Nordmark@Sun.COM return; 288411042SErik.Nordmark@Sun.COM } 288511042SErik.Nordmark@Sun.COM mp = ira->ira_ipsec_esp_sa->ipsa_input_func(mp, esph, 288611042SErik.Nordmark@Sun.COM ira); 288711042SErik.Nordmark@Sun.COM } else { 288811042SErik.Nordmark@Sun.COM ah_t *ah; 288911042SErik.Nordmark@Sun.COM 289011042SErik.Nordmark@Sun.COM mp = ipsec_inbound_ah_sa(mp, ira, &ah); 289111042SErik.Nordmark@Sun.COM if (mp == NULL) 289211042SErik.Nordmark@Sun.COM return; 289311042SErik.Nordmark@Sun.COM 289411042SErik.Nordmark@Sun.COM ASSERT(ah != NULL); 289511042SErik.Nordmark@Sun.COM ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 289611042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ipsec_ah_sa != NULL); 289711042SErik.Nordmark@Sun.COM ASSERT(ira->ira_ipsec_ah_sa->ipsa_input_func != NULL); 289811042SErik.Nordmark@Sun.COM mp = ira->ira_ipsec_ah_sa->ipsa_input_func(mp, ah, 289911042SErik.Nordmark@Sun.COM ira); 290011042SErik.Nordmark@Sun.COM } 290111042SErik.Nordmark@Sun.COM 290211042SErik.Nordmark@Sun.COM if (mp == NULL) { 290311042SErik.Nordmark@Sun.COM /* 290411042SErik.Nordmark@Sun.COM * Either it failed or is pending. In the former case 290511042SErik.Nordmark@Sun.COM * ipIfStatsInDiscards was increased. 290611042SErik.Nordmark@Sun.COM */ 290711042SErik.Nordmark@Sun.COM return; 290811042SErik.Nordmark@Sun.COM } 290911042SErik.Nordmark@Sun.COM /* we're done with IPsec processing, send it up */ 291011042SErik.Nordmark@Sun.COM ip_input_post_ipsec(mp, ira); 291111042SErik.Nordmark@Sun.COM return; 291211042SErik.Nordmark@Sun.COM } 291311042SErik.Nordmark@Sun.COM case IPPROTO_ENCAP: { 291411042SErik.Nordmark@Sun.COM ipha_t *inner_ipha; 291511042SErik.Nordmark@Sun.COM 291611042SErik.Nordmark@Sun.COM /* 291711042SErik.Nordmark@Sun.COM * Handle self-encapsulated packets (IP-in-IP where 291811042SErik.Nordmark@Sun.COM * the inner addresses == the outer addresses). 291911042SErik.Nordmark@Sun.COM */ 292011042SErik.Nordmark@Sun.COM if ((uchar_t *)ipha + ip_hdr_length + sizeof (ipha_t) > 292111042SErik.Nordmark@Sun.COM mp->b_wptr) { 292211042SErik.Nordmark@Sun.COM if (ira->ira_pktlen < 292311042SErik.Nordmark@Sun.COM ip_hdr_length + sizeof (ipha_t)) { 292411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 292511042SErik.Nordmark@Sun.COM ipIfStatsInTruncatedPkts); 292611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInTruncatedPkts", 292711042SErik.Nordmark@Sun.COM mp, ill); 292811042SErik.Nordmark@Sun.COM freemsg(mp); 292911042SErik.Nordmark@Sun.COM return; 293011042SErik.Nordmark@Sun.COM } 293111042SErik.Nordmark@Sun.COM ipha = ip_pullup(mp, (uchar_t *)ipha + ip_hdr_length + 293211042SErik.Nordmark@Sun.COM sizeof (ipha_t) - mp->b_rptr, ira); 293311042SErik.Nordmark@Sun.COM if (ipha == NULL) { 293411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 293511042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 293611042SErik.Nordmark@Sun.COM freemsg(mp); 293711042SErik.Nordmark@Sun.COM return; 293811042SErik.Nordmark@Sun.COM } 293911042SErik.Nordmark@Sun.COM } 294011042SErik.Nordmark@Sun.COM inner_ipha = (ipha_t *)((uchar_t *)ipha + ip_hdr_length); 294111042SErik.Nordmark@Sun.COM /* 294211042SErik.Nordmark@Sun.COM * Check the sanity of the inner IP header. 294311042SErik.Nordmark@Sun.COM */ 294411042SErik.Nordmark@Sun.COM if ((IPH_HDR_VERSION(inner_ipha) != IPV4_VERSION)) { 294511042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 294611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 294711042SErik.Nordmark@Sun.COM freemsg(mp); 294811042SErik.Nordmark@Sun.COM return; 294911042SErik.Nordmark@Sun.COM } 295011042SErik.Nordmark@Sun.COM if (IPH_HDR_LENGTH(inner_ipha) < sizeof (ipha_t)) { 295111042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 295211042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 295311042SErik.Nordmark@Sun.COM freemsg(mp); 295411042SErik.Nordmark@Sun.COM return; 295511042SErik.Nordmark@Sun.COM } 295611042SErik.Nordmark@Sun.COM if (inner_ipha->ipha_src != ipha->ipha_src || 295711042SErik.Nordmark@Sun.COM inner_ipha->ipha_dst != ipha->ipha_dst) { 295811042SErik.Nordmark@Sun.COM /* We fallthru to iptun fanout below */ 295911042SErik.Nordmark@Sun.COM goto iptun; 296011042SErik.Nordmark@Sun.COM } 296111042SErik.Nordmark@Sun.COM 296211042SErik.Nordmark@Sun.COM /* 296311042SErik.Nordmark@Sun.COM * Self-encapsulated tunnel packet. Remove 296411042SErik.Nordmark@Sun.COM * the outer IP header and fanout again. 296511042SErik.Nordmark@Sun.COM * We also need to make sure that the inner 296611042SErik.Nordmark@Sun.COM * header is pulled up until options. 296711042SErik.Nordmark@Sun.COM */ 296811042SErik.Nordmark@Sun.COM mp->b_rptr = (uchar_t *)inner_ipha; 296911042SErik.Nordmark@Sun.COM ipha = inner_ipha; 297011042SErik.Nordmark@Sun.COM ip_hdr_length = IPH_HDR_LENGTH(ipha); 297111042SErik.Nordmark@Sun.COM if ((uchar_t *)ipha + ip_hdr_length > mp->b_wptr) { 297211042SErik.Nordmark@Sun.COM if (ira->ira_pktlen < 297311042SErik.Nordmark@Sun.COM (uchar_t *)ipha + ip_hdr_length - mp->b_rptr) { 297411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, 297511042SErik.Nordmark@Sun.COM ipIfStatsInTruncatedPkts); 297611042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInTruncatedPkts", 297711042SErik.Nordmark@Sun.COM mp, ill); 297811042SErik.Nordmark@Sun.COM freemsg(mp); 297911042SErik.Nordmark@Sun.COM return; 298011042SErik.Nordmark@Sun.COM } 298111042SErik.Nordmark@Sun.COM ipha = ip_pullup(mp, 298211042SErik.Nordmark@Sun.COM (uchar_t *)ipha + ip_hdr_length - mp->b_rptr, ira); 298311042SErik.Nordmark@Sun.COM if (ipha == NULL) { 298411042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 298511042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 298611042SErik.Nordmark@Sun.COM freemsg(mp); 298711042SErik.Nordmark@Sun.COM return; 298811042SErik.Nordmark@Sun.COM } 298911042SErik.Nordmark@Sun.COM } 299011042SErik.Nordmark@Sun.COM if (ip_hdr_length > sizeof (ipha_t)) { 299111042SErik.Nordmark@Sun.COM /* We got options on the inner packet. */ 299211042SErik.Nordmark@Sun.COM ipaddr_t dst = ipha->ipha_dst; 299311042SErik.Nordmark@Sun.COM int error = 0; 299411042SErik.Nordmark@Sun.COM 299511042SErik.Nordmark@Sun.COM dst = ip_input_options(ipha, dst, mp, ira, &error); 299611042SErik.Nordmark@Sun.COM if (error != 0) { 299711042SErik.Nordmark@Sun.COM /* 299811042SErik.Nordmark@Sun.COM * An ICMP error has been sent and the packet 299911042SErik.Nordmark@Sun.COM * has been dropped. 300011042SErik.Nordmark@Sun.COM */ 300111042SErik.Nordmark@Sun.COM return; 300211042SErik.Nordmark@Sun.COM } 300311042SErik.Nordmark@Sun.COM if (dst != ipha->ipha_dst) { 300411042SErik.Nordmark@Sun.COM /* 300511042SErik.Nordmark@Sun.COM * Someone put a source-route in 300611042SErik.Nordmark@Sun.COM * the inside header of a self- 300711042SErik.Nordmark@Sun.COM * encapsulated packet. Drop it 300811042SErik.Nordmark@Sun.COM * with extreme prejudice and let 300911042SErik.Nordmark@Sun.COM * the sender know. 301011042SErik.Nordmark@Sun.COM */ 301111042SErik.Nordmark@Sun.COM ip_drop_input("ICMP_SOURCE_ROUTE_FAILED", 301211042SErik.Nordmark@Sun.COM mp, ill); 301311042SErik.Nordmark@Sun.COM icmp_unreachable(mp, ICMP_SOURCE_ROUTE_FAILED, 301411042SErik.Nordmark@Sun.COM ira); 301511042SErik.Nordmark@Sun.COM return; 301611042SErik.Nordmark@Sun.COM } 301711042SErik.Nordmark@Sun.COM } 301811042SErik.Nordmark@Sun.COM if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) { 301911042SErik.Nordmark@Sun.COM /* 302011042SErik.Nordmark@Sun.COM * This means that somebody is sending 302111042SErik.Nordmark@Sun.COM * Self-encapsualted packets without AH/ESP. 302211042SErik.Nordmark@Sun.COM * 302311042SErik.Nordmark@Sun.COM * Send this packet to find a tunnel endpoint. 302411042SErik.Nordmark@Sun.COM * if I can't find one, an ICMP 302511042SErik.Nordmark@Sun.COM * PROTOCOL_UNREACHABLE will get sent. 302611042SErik.Nordmark@Sun.COM */ 302711042SErik.Nordmark@Sun.COM protocol = ipha->ipha_protocol; 302811042SErik.Nordmark@Sun.COM ira->ira_protocol = protocol; 302911042SErik.Nordmark@Sun.COM goto iptun; 303011042SErik.Nordmark@Sun.COM } 303111042SErik.Nordmark@Sun.COM 303211042SErik.Nordmark@Sun.COM /* Update based on removed IP header */ 303311042SErik.Nordmark@Sun.COM ira->ira_ip_hdr_length = ip_hdr_length; 303411042SErik.Nordmark@Sun.COM ira->ira_pktlen = ntohs(ipha->ipha_length); 303511042SErik.Nordmark@Sun.COM 303611042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_IPSEC_DECAPS) { 303711042SErik.Nordmark@Sun.COM /* 303811042SErik.Nordmark@Sun.COM * This packet is self-encapsulated multiple 303911042SErik.Nordmark@Sun.COM * times. We don't want to recurse infinitely. 304011042SErik.Nordmark@Sun.COM * To keep it simple, drop the packet. 304111042SErik.Nordmark@Sun.COM */ 304211042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 304311042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 304411042SErik.Nordmark@Sun.COM freemsg(mp); 304511042SErik.Nordmark@Sun.COM return; 304611042SErik.Nordmark@Sun.COM } 304711042SErik.Nordmark@Sun.COM ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 304811042SErik.Nordmark@Sun.COM ira->ira_flags |= IRAF_IPSEC_DECAPS; 304911042SErik.Nordmark@Sun.COM 305011042SErik.Nordmark@Sun.COM ip_input_post_ipsec(mp, ira); 305111042SErik.Nordmark@Sun.COM return; 305211042SErik.Nordmark@Sun.COM } 305311042SErik.Nordmark@Sun.COM 305411042SErik.Nordmark@Sun.COM iptun: /* IPPROTO_ENCAPS that is not self-encapsulated */ 305511042SErik.Nordmark@Sun.COM case IPPROTO_IPV6: 305611042SErik.Nordmark@Sun.COM /* iptun will verify trusted label */ 305711042SErik.Nordmark@Sun.COM connp = ipcl_classify_v4(mp, protocol, ip_hdr_length, 305811042SErik.Nordmark@Sun.COM ira, ipst); 305911042SErik.Nordmark@Sun.COM if (connp != NULL) { 306011042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsHCInDelivers); 306111042SErik.Nordmark@Sun.COM ira->ira_ill = ira->ira_rill = NULL; 306211042SErik.Nordmark@Sun.COM (connp->conn_recv)(connp, mp, NULL, ira); 306311042SErik.Nordmark@Sun.COM CONN_DEC_REF(connp); 306411042SErik.Nordmark@Sun.COM ira->ira_ill = ill; 306511042SErik.Nordmark@Sun.COM ira->ira_rill = rill; 306611042SErik.Nordmark@Sun.COM return; 306711042SErik.Nordmark@Sun.COM } 306811042SErik.Nordmark@Sun.COM /* FALLTHRU */ 306911042SErik.Nordmark@Sun.COM default: 307011042SErik.Nordmark@Sun.COM /* 307111042SErik.Nordmark@Sun.COM * On a labeled system, we have to check whether the zone 307211042SErik.Nordmark@Sun.COM * itself is permitted to receive raw traffic. 307311042SErik.Nordmark@Sun.COM */ 307411042SErik.Nordmark@Sun.COM if (ira->ira_flags & IRAF_SYSTEM_LABELED) { 307511042SErik.Nordmark@Sun.COM if (!tsol_can_accept_raw(mp, ira, B_FALSE)) { 307611042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 307711042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 307811042SErik.Nordmark@Sun.COM freemsg(mp); 307911042SErik.Nordmark@Sun.COM return; 308011042SErik.Nordmark@Sun.COM } 308111042SErik.Nordmark@Sun.COM } 308211042SErik.Nordmark@Sun.COM break; 308311042SErik.Nordmark@Sun.COM } 308411042SErik.Nordmark@Sun.COM 308511042SErik.Nordmark@Sun.COM /* 308611042SErik.Nordmark@Sun.COM * The above input functions may have returned the pulled up message. 308711042SErik.Nordmark@Sun.COM * So ipha need to be reinitialized. 308811042SErik.Nordmark@Sun.COM */ 308911042SErik.Nordmark@Sun.COM ipha = (ipha_t *)mp->b_rptr; 309011042SErik.Nordmark@Sun.COM ira->ira_protocol = protocol = ipha->ipha_protocol; 309111042SErik.Nordmark@Sun.COM if (ipst->ips_ipcl_proto_fanout_v4[protocol].connf_head == NULL) { 309211042SErik.Nordmark@Sun.COM /* 309311042SErik.Nordmark@Sun.COM * No user-level listener for these packets packets. 309411042SErik.Nordmark@Sun.COM * Check for IPPROTO_ENCAP... 309511042SErik.Nordmark@Sun.COM */ 309611042SErik.Nordmark@Sun.COM if (protocol == IPPROTO_ENCAP && ipst->ips_ip_g_mrouter) { 309711042SErik.Nordmark@Sun.COM /* 309811042SErik.Nordmark@Sun.COM * Check policy here, 309911042SErik.Nordmark@Sun.COM * THEN ship off to ip_mroute_decap(). 310011042SErik.Nordmark@Sun.COM * 310111042SErik.Nordmark@Sun.COM * BTW, If I match a configured IP-in-IP 310211042SErik.Nordmark@Sun.COM * tunnel above, this path will not be reached, and 310311042SErik.Nordmark@Sun.COM * ip_mroute_decap will never be called. 310411042SErik.Nordmark@Sun.COM */ 310511042SErik.Nordmark@Sun.COM mp = ipsec_check_global_policy(mp, connp, 310611042SErik.Nordmark@Sun.COM ipha, NULL, ira, ns); 310711042SErik.Nordmark@Sun.COM if (mp != NULL) { 310811042SErik.Nordmark@Sun.COM ip_mroute_decap(mp, ira); 310911042SErik.Nordmark@Sun.COM } /* Else we already freed everything! */ 311011042SErik.Nordmark@Sun.COM } else { 311111042SErik.Nordmark@Sun.COM ip_proto_not_sup(mp, ira); 311211042SErik.Nordmark@Sun.COM } 311311042SErik.Nordmark@Sun.COM return; 311411042SErik.Nordmark@Sun.COM } 311511042SErik.Nordmark@Sun.COM 311611042SErik.Nordmark@Sun.COM /* 311711042SErik.Nordmark@Sun.COM * Handle fanout to raw sockets. There 311811042SErik.Nordmark@Sun.COM * can be more than one stream bound to a particular 311911042SErik.Nordmark@Sun.COM * protocol. When this is the case, each one gets a copy 312011042SErik.Nordmark@Sun.COM * of any incoming packets. 312111042SErik.Nordmark@Sun.COM */ 312211042SErik.Nordmark@Sun.COM ASSERT(ira->ira_protocol == ipha->ipha_protocol); 312311042SErik.Nordmark@Sun.COM ip_fanout_proto_v4(mp, ipha, ira); 312411042SErik.Nordmark@Sun.COM return; 312511042SErik.Nordmark@Sun.COM 312611042SErik.Nordmark@Sun.COM discard: 312711042SErik.Nordmark@Sun.COM BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards); 312811042SErik.Nordmark@Sun.COM ip_drop_input("ipIfStatsInDiscards", mp, ill); 312911042SErik.Nordmark@Sun.COM freemsg(mp); 313011042SErik.Nordmark@Sun.COM #undef rptr 313111042SErik.Nordmark@Sun.COM } 3132