Print this page
OS-5007 support SO_ATTACH_FILTER on ICMP sockets
Reviewed by: Cody Mello <melloc@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2013 by Delphix. All rights reserved.
  24  * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.

  25  */
  26 /* Copyright (c) 1990 Mentat Inc. */
  27 
  28 #include <sys/types.h>
  29 #include <sys/stream.h>
  30 #include <sys/stropts.h>
  31 #include <sys/strlog.h>
  32 #include <sys/strsun.h>
  33 #define _SUN_TPI_VERSION 2
  34 #include <sys/tihdr.h>
  35 #include <sys/timod.h>
  36 #include <sys/ddi.h>
  37 #include <sys/sunddi.h>
  38 #include <sys/strsubr.h>
  39 #include <sys/suntpi.h>
  40 #include <sys/xti_inet.h>
  41 #include <sys/cmn_err.h>
  42 #include <sys/kmem.h>
  43 #include <sys/cred.h>
  44 #include <sys/policy.h>


  63 #include <inet/ip.h>
  64 #include <inet/ip_impl.h>
  65 #include <inet/ipsec_impl.h>
  66 #include <inet/ip6.h>
  67 #include <inet/ip_ire.h>
  68 #include <inet/ip_if.h>
  69 #include <inet/ip_multi.h>
  70 #include <inet/ip_ndp.h>
  71 #include <inet/proto_set.h>
  72 #include <inet/mib2.h>
  73 #include <inet/nd.h>
  74 #include <inet/optcom.h>
  75 #include <inet/snmpcom.h>
  76 #include <inet/kstatcom.h>
  77 #include <inet/ipclassifier.h>
  78 
  79 #include <sys/tsol/label.h>
  80 #include <sys/tsol/tnet.h>
  81 
  82 #include <inet/rawip_impl.h>

  83 
  84 #include <sys/disp.h>
  85 
  86 /*
  87  * Synchronization notes:
  88  *
  89  * RAWIP is MT and uses the usual kernel synchronization primitives. We use
  90  * conn_lock to protect the icmp_t.
  91  *
  92  * Plumbing notes:
  93  * ICMP is always a device driver. For compatibility with mibopen() code
  94  * it is possible to I_PUSH "icmp", but that results in pushing a passthrough
  95  * dummy module.
  96  */
  97 static void     icmp_addr_req(queue_t *q, mblk_t *mp);
  98 static void     icmp_tpi_bind(queue_t *q, mblk_t *mp);
  99 static void     icmp_bind_proto(icmp_t *icmp);
 100 static int      icmp_build_hdr_template(conn_t *, const in6_addr_t *,
 101     const in6_addr_t *, uint32_t);
 102 static void     icmp_capability_req(queue_t *q, mblk_t *mp);


 994                 goto done;
 995         }
 996 
 997         connp = Q_TO_CONN(q);
 998         (void) rawip_do_close(connp);
 999 done:
1000         q->q_ptr = WR(q)->q_ptr = NULL;
1001         return (0);
1002 }
1003 
1004 static void
1005 icmp_close_free(conn_t *connp)
1006 {
1007         icmp_t *icmp = connp->conn_icmp;
1008 
1009         if (icmp->icmp_filter != NULL) {
1010                 kmem_free(icmp->icmp_filter, sizeof (icmp6_filter_t));
1011                 icmp->icmp_filter = NULL;
1012         }
1013 






1014         /*
1015          * Clear any fields which the kmem_cache constructor clears.
1016          * Only icmp_connp needs to be preserved.
1017          * TBD: We should make this more efficient to avoid clearing
1018          * everything.
1019          */
1020         ASSERT(icmp->icmp_connp == connp);
1021         bzero(icmp, sizeof (icmp_t));
1022         icmp->icmp_connp = connp;
1023 }
1024 
1025 /*
1026  * This routine handles each T_DISCON_REQ message passed to icmp
1027  * as an indicating that ICMP is no longer connected. This results
1028  * in telling IP to restore the binding to just the local address.
1029  */
1030 static int
1031 icmp_do_disconnect(conn_t *connp)
1032 {
1033         icmp_t  *icmp = connp->conn_icmp;


1947         mutex_enter(&connp->conn_lock);
1948         retval = conn_opt_get(&coas, level, name, ptr);
1949         mutex_exit(&connp->conn_lock);
1950         return (retval);
1951 }
1952 
1953 /*
1954  * This routine retrieves the current status of socket options.
1955  * It returns the size of the option retrieved, or -1.
1956  */
1957 int
1958 icmp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
1959 {
1960         conn_t          *connp = Q_TO_CONN(q);
1961         int             err;
1962 
1963         err = icmp_opt_get(connp, level, name, ptr);
1964         return (err);
1965 }
1966 


































































































1967 /*
1968  * This routine sets socket options.
1969  */
1970 int
1971 icmp_do_opt_set(conn_opt_arg_t *coa, int level, int name,
1972     uint_t inlen, uchar_t *invalp, cred_t *cr, boolean_t checkonly)
1973 {
1974         conn_t          *connp = coa->coa_connp;
1975         ip_xmit_attr_t  *ixa = coa->coa_ixa;
1976         icmp_t          *icmp = connp->conn_icmp;
1977         icmp_stack_t    *is = icmp->icmp_is;
1978         int             *i1 = (int *)invalp;
1979         boolean_t       onoff = (*i1 == 0) ? 0 : 1;
1980         int             error;
1981 
1982         ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
1983 
1984         /*
1985          * For fixed length options, no sanity check
1986          * of passed in length is done. It is assumed *_optcom_req()


2036                         /*
2037                          * For SCTP, we don't use icmp_bind_proto() for
2038                          * raw socket binding.
2039                          */
2040                         if (connp->conn_proto == IPPROTO_SCTP)
2041                                 return (0);
2042 
2043                         coa->coa_changed |= COA_ICMP_BIND_NEEDED;
2044                         return (0);
2045 
2046                 case SO_SNDBUF:
2047                         if (*i1 > is->is_max_buf) {
2048                                 return (ENOBUFS);
2049                         }
2050                         break;
2051                 case SO_RCVBUF:
2052                         if (*i1 > is->is_max_buf) {
2053                                 return (ENOBUFS);
2054                         }
2055                         break;




2056                 }
2057                 break;
2058 
2059         case IPPROTO_IP:
2060                 /*
2061                  * Only allow IPv4 option processing on IPv4 sockets.
2062                  */
2063                 if (connp->conn_family != AF_INET)
2064                         return (EINVAL);
2065 
2066                 switch (name) {
2067                 case IP_HDRINCL:
2068                         if (!checkonly) {
2069                                 mutex_enter(&connp->conn_lock);
2070                                 icmp->icmp_hdrincl = onoff;
2071                                 if (onoff)
2072                                         ixa->ixa_flags &= ~IXAF_SET_ULP_CKSUM;
2073                                 else
2074                                         ixa->ixa_flags |= IXAF_SET_ULP_CKSUM;
2075                                 mutex_exit(&connp->conn_lock);


2581         ASSERT(DB_TYPE(mp) == M_DATA);
2582         ASSERT(OK_32PTR(rptr));
2583         ASSERT(ira->ira_pktlen == msgdsize(mp));
2584         pkt_len = ira->ira_pktlen;
2585 
2586         /*
2587          * Get a snapshot of these and allow other threads to change
2588          * them after that. We need the same recv_ancillary when determining
2589          * the size as when adding the ancillary data items.
2590          */
2591         mutex_enter(&connp->conn_lock);
2592         recv_ancillary = connp->conn_recv_ancillary;
2593         mutex_exit(&connp->conn_lock);
2594 
2595         ip_hdr_length = ira->ira_ip_hdr_length;
2596         ASSERT(MBLKL(mp) >= ip_hdr_length);  /* IP did a pullup */
2597 
2598         /* Initialize regardless of IP version */
2599         ipps.ipp_fields = 0;
2600 








2601         if (ira->ira_flags & IRAF_IS_IPV4) {
2602                 ASSERT(IPH_HDR_VERSION(rptr) == IPV4_VERSION);
2603                 ASSERT(MBLKL(mp) >= sizeof (ipha_t));
2604                 ASSERT(ira->ira_ip_hdr_length == IPH_HDR_LENGTH(rptr));
2605 
2606                 ipha = (ipha_t *)mp->b_rptr;
2607                 if (recv_ancillary.crb_all != 0)
2608                         (void) ip_find_hdr_v4(ipha, &ipps, B_FALSE);
2609 
2610                 /*
2611                  * BSD for some reason adjusts ipha_length to exclude the
2612                  * IP header length. We do the same.
2613                  */
2614                 if (is->is_bsd_compat) {
2615                         ushort_t len;
2616 
2617                         len = ntohs(ipha->ipha_length);
2618                         if (mp->b_datap->db_ref > 1) {
2619                                 /*
2620                                  * Allocate a new IP header so that we can


5010 }
5011 
5012 /*
5013  * Free the ICMP stack instance.
5014  */
5015 static void
5016 rawip_stack_fini(netstackid_t stackid, void *arg)
5017 {
5018         icmp_stack_t *is = (icmp_stack_t *)arg;
5019 
5020         kmem_free(is->is_propinfo_tbl, sizeof (icmp_propinfo_tbl));
5021         is->is_propinfo_tbl = NULL;
5022 
5023         rawip_kstat_fini(stackid, is->is_ksp);
5024         is->is_ksp = NULL;
5025         ldi_ident_release(is->is_ldi_ident);
5026         kmem_free(is, sizeof (*is));
5027 }
5028 
5029 static void *
5030 rawip_kstat_init(netstackid_t stackid) {

5031         kstat_t *ksp;
5032 
5033         rawip_named_kstat_t template = {
5034                 { "inDatagrams",        KSTAT_DATA_UINT32, 0 },
5035                 { "inCksumErrs",        KSTAT_DATA_UINT32, 0 },
5036                 { "inErrors",           KSTAT_DATA_UINT32, 0 },
5037                 { "outDatagrams",       KSTAT_DATA_UINT32, 0 },
5038                 { "outErrors",          KSTAT_DATA_UINT32, 0 },
5039         };
5040 
5041         ksp = kstat_create_netstack("icmp", 0, "rawip", "mib2",
5042                                         KSTAT_TYPE_NAMED,
5043                                         NUM_OF_FIELDS(rawip_named_kstat_t),
5044                                         0, stackid);
5045         if (ksp == NULL || ksp->ks_data == NULL)
5046                 return (NULL);
5047 
5048         bcopy(&template, ksp->ks_data, sizeof (template));
5049         ksp->ks_update = rawip_kstat_update;
5050         ksp->ks_private = (void *)(uintptr_t)stackid;
5051 
5052         kstat_install(ksp);
5053         return (ksp);
5054 }
5055 
5056 static void
5057 rawip_kstat_fini(netstackid_t stackid, kstat_t *ksp)
5058 {
5059         if (ksp != NULL) {
5060                 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
5061                 kstat_delete_netstack(ksp, stackid);
5062         }
5063 }
5064 




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2013 by Delphix. All rights reserved.
  24  * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  25  * Copyright 2016 Joyent, Inc.
  26  */
  27 /* Copyright (c) 1990 Mentat Inc. */
  28 
  29 #include <sys/types.h>
  30 #include <sys/stream.h>
  31 #include <sys/stropts.h>
  32 #include <sys/strlog.h>
  33 #include <sys/strsun.h>
  34 #define _SUN_TPI_VERSION 2
  35 #include <sys/tihdr.h>
  36 #include <sys/timod.h>
  37 #include <sys/ddi.h>
  38 #include <sys/sunddi.h>
  39 #include <sys/strsubr.h>
  40 #include <sys/suntpi.h>
  41 #include <sys/xti_inet.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/kmem.h>
  44 #include <sys/cred.h>
  45 #include <sys/policy.h>


  64 #include <inet/ip.h>
  65 #include <inet/ip_impl.h>
  66 #include <inet/ipsec_impl.h>
  67 #include <inet/ip6.h>
  68 #include <inet/ip_ire.h>
  69 #include <inet/ip_if.h>
  70 #include <inet/ip_multi.h>
  71 #include <inet/ip_ndp.h>
  72 #include <inet/proto_set.h>
  73 #include <inet/mib2.h>
  74 #include <inet/nd.h>
  75 #include <inet/optcom.h>
  76 #include <inet/snmpcom.h>
  77 #include <inet/kstatcom.h>
  78 #include <inet/ipclassifier.h>
  79 
  80 #include <sys/tsol/label.h>
  81 #include <sys/tsol/tnet.h>
  82 
  83 #include <inet/rawip_impl.h>
  84 #include <net/bpf.h>
  85 
  86 #include <sys/disp.h>
  87 
  88 /*
  89  * Synchronization notes:
  90  *
  91  * RAWIP is MT and uses the usual kernel synchronization primitives. We use
  92  * conn_lock to protect the icmp_t.
  93  *
  94  * Plumbing notes:
  95  * ICMP is always a device driver. For compatibility with mibopen() code
  96  * it is possible to I_PUSH "icmp", but that results in pushing a passthrough
  97  * dummy module.
  98  */
  99 static void     icmp_addr_req(queue_t *q, mblk_t *mp);
 100 static void     icmp_tpi_bind(queue_t *q, mblk_t *mp);
 101 static void     icmp_bind_proto(icmp_t *icmp);
 102 static int      icmp_build_hdr_template(conn_t *, const in6_addr_t *,
 103     const in6_addr_t *, uint32_t);
 104 static void     icmp_capability_req(queue_t *q, mblk_t *mp);


 996                 goto done;
 997         }
 998 
 999         connp = Q_TO_CONN(q);
1000         (void) rawip_do_close(connp);
1001 done:
1002         q->q_ptr = WR(q)->q_ptr = NULL;
1003         return (0);
1004 }
1005 
1006 static void
1007 icmp_close_free(conn_t *connp)
1008 {
1009         icmp_t *icmp = connp->conn_icmp;
1010 
1011         if (icmp->icmp_filter != NULL) {
1012                 kmem_free(icmp->icmp_filter, sizeof (icmp6_filter_t));
1013                 icmp->icmp_filter = NULL;
1014         }
1015 
1016         if (icmp->icmp_bpf_len != 0) {
1017                 kmem_free(icmp->icmp_bpf_prog, icmp->icmp_bpf_len);
1018                 icmp->icmp_bpf_len = 0;
1019                 icmp->icmp_bpf_prog = NULL;
1020         }
1021 
1022         /*
1023          * Clear any fields which the kmem_cache constructor clears.
1024          * Only icmp_connp needs to be preserved.
1025          * TBD: We should make this more efficient to avoid clearing
1026          * everything.
1027          */
1028         ASSERT(icmp->icmp_connp == connp);
1029         bzero(icmp, sizeof (icmp_t));
1030         icmp->icmp_connp = connp;
1031 }
1032 
1033 /*
1034  * This routine handles each T_DISCON_REQ message passed to icmp
1035  * as an indicating that ICMP is no longer connected. This results
1036  * in telling IP to restore the binding to just the local address.
1037  */
1038 static int
1039 icmp_do_disconnect(conn_t *connp)
1040 {
1041         icmp_t  *icmp = connp->conn_icmp;


1955         mutex_enter(&connp->conn_lock);
1956         retval = conn_opt_get(&coas, level, name, ptr);
1957         mutex_exit(&connp->conn_lock);
1958         return (retval);
1959 }
1960 
1961 /*
1962  * This routine retrieves the current status of socket options.
1963  * It returns the size of the option retrieved, or -1.
1964  */
1965 int
1966 icmp_tpi_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
1967 {
1968         conn_t          *connp = Q_TO_CONN(q);
1969         int             err;
1970 
1971         err = icmp_opt_get(connp, level, name, ptr);
1972         return (err);
1973 }
1974 
1975 static int
1976 icmp_attach_filter(icmp_t *icmp, uint_t inlen, const uchar_t *invalp)
1977 {
1978         struct bpf_program prog;
1979         ip_bpf_insn_t *insns = NULL;
1980         unsigned int size;
1981 
1982 #ifdef _LP64
1983         if (get_udatamodel() != DATAMODEL_NATIVE) {
1984                 struct bpf_program32 *prog32;
1985 
1986                 if (inlen != sizeof (struct bpf_program32)) {
1987                         return (EINVAL);
1988                 }
1989                 prog32 = (struct bpf_program32 *)invalp;
1990                 prog.bf_len = prog32->bf_len;
1991                 prog.bf_insns = (void *)(uint64_t)prog32->bf_insns;
1992         } else
1993 #endif
1994         if (inlen == sizeof (struct bpf_program)) {
1995                 bcopy(invalp, &prog, sizeof (prog));
1996         } else {
1997                 return (EINVAL);
1998         }
1999 
2000         if (prog.bf_len > BPF_MAXINSNS || prog.bf_len == 0) {
2001                 return (EINVAL);
2002         }
2003         size = prog.bf_len * sizeof (struct bpf_insn);
2004         insns = kmem_alloc(size, KM_SLEEP);
2005         if (copyin(prog.bf_insns, insns, size) != 0) {
2006                 kmem_free(insns, size);
2007                 return (EFAULT);
2008         }
2009         if (!ip_bpf_validate(insns, prog.bf_len)) {
2010                 kmem_free(insns, size);
2011                 return (EINVAL);
2012         }
2013 
2014         rw_enter(&icmp->icmp_bpf_lock, RW_WRITER);
2015         if (icmp->icmp_bpf_len != 0) {
2016                 ASSERT(icmp->icmp_bpf_prog != NULL);
2017 
2018                 kmem_free(icmp->icmp_bpf_prog, icmp->icmp_bpf_len);
2019         }
2020         icmp->icmp_bpf_len = size;
2021         icmp->icmp_bpf_prog = insns;
2022         rw_exit(&icmp->icmp_bpf_lock);
2023         return (0);
2024 }
2025 
2026 static int
2027 icmp_detach_filter(icmp_t *icmp)
2028 {
2029         int error;
2030 
2031         rw_enter(&icmp->icmp_bpf_lock, RW_WRITER);
2032         if (icmp->icmp_bpf_len == 0) {
2033                 ASSERT(icmp->icmp_bpf_prog == NULL);
2034                 error = ENOENT;
2035         } else {
2036                 kmem_free(icmp->icmp_bpf_prog,
2037                     icmp->icmp_bpf_len);
2038                 icmp->icmp_bpf_len = 0;
2039                 icmp->icmp_bpf_prog = NULL;
2040                 error = 0;
2041         }
2042         rw_exit(&icmp->icmp_bpf_lock);
2043         return (error);
2044 }
2045 
2046 static boolean_t
2047 icmp_eval_filter(icmp_t *icmp, mblk_t *mp, ip_recv_attr_t *ira)
2048 {
2049         boolean_t res;
2050         uchar_t *buf = mp->b_rptr;
2051         uint_t wirelen, len = MBLKL(mp);
2052 
2053         rw_enter(&icmp->icmp_bpf_lock, RW_READER);
2054         if (icmp->icmp_bpf_len == 0) {
2055                 rw_exit(&icmp->icmp_bpf_lock);
2056                 return (B_FALSE);
2057         }
2058         if (ira->ira_flags & IRAF_IS_IPV4) {
2059                 ipha_t *ipha = (ipha_t *)buf;
2060 
2061                 wirelen = ntohs(ipha->ipha_length);
2062         } else {
2063                 ip6_t *ip6h = (ip6_t *)buf;
2064 
2065                 wirelen = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN;
2066         }
2067         res = !ip_bpf_filter(icmp->icmp_bpf_prog, buf, wirelen, len);
2068         rw_exit(&icmp->icmp_bpf_lock);
2069 
2070         return (res);
2071 }
2072 
2073 /*
2074  * This routine sets socket options.
2075  */
2076 int
2077 icmp_do_opt_set(conn_opt_arg_t *coa, int level, int name,
2078     uint_t inlen, uchar_t *invalp, cred_t *cr, boolean_t checkonly)
2079 {
2080         conn_t          *connp = coa->coa_connp;
2081         ip_xmit_attr_t  *ixa = coa->coa_ixa;
2082         icmp_t          *icmp = connp->conn_icmp;
2083         icmp_stack_t    *is = icmp->icmp_is;
2084         int             *i1 = (int *)invalp;
2085         boolean_t       onoff = (*i1 == 0) ? 0 : 1;
2086         int             error;
2087 
2088         ASSERT(MUTEX_NOT_HELD(&coa->coa_connp->conn_lock));
2089 
2090         /*
2091          * For fixed length options, no sanity check
2092          * of passed in length is done. It is assumed *_optcom_req()


2142                         /*
2143                          * For SCTP, we don't use icmp_bind_proto() for
2144                          * raw socket binding.
2145                          */
2146                         if (connp->conn_proto == IPPROTO_SCTP)
2147                                 return (0);
2148 
2149                         coa->coa_changed |= COA_ICMP_BIND_NEEDED;
2150                         return (0);
2151 
2152                 case SO_SNDBUF:
2153                         if (*i1 > is->is_max_buf) {
2154                                 return (ENOBUFS);
2155                         }
2156                         break;
2157                 case SO_RCVBUF:
2158                         if (*i1 > is->is_max_buf) {
2159                                 return (ENOBUFS);
2160                         }
2161                         break;
2162                 case SO_ATTACH_FILTER:
2163                         return (icmp_attach_filter(icmp, inlen, invalp));
2164                 case SO_DETACH_FILTER:
2165                         return (icmp_detach_filter(icmp));
2166                 }
2167                 break;
2168 
2169         case IPPROTO_IP:
2170                 /*
2171                  * Only allow IPv4 option processing on IPv4 sockets.
2172                  */
2173                 if (connp->conn_family != AF_INET)
2174                         return (EINVAL);
2175 
2176                 switch (name) {
2177                 case IP_HDRINCL:
2178                         if (!checkonly) {
2179                                 mutex_enter(&connp->conn_lock);
2180                                 icmp->icmp_hdrincl = onoff;
2181                                 if (onoff)
2182                                         ixa->ixa_flags &= ~IXAF_SET_ULP_CKSUM;
2183                                 else
2184                                         ixa->ixa_flags |= IXAF_SET_ULP_CKSUM;
2185                                 mutex_exit(&connp->conn_lock);


2691         ASSERT(DB_TYPE(mp) == M_DATA);
2692         ASSERT(OK_32PTR(rptr));
2693         ASSERT(ira->ira_pktlen == msgdsize(mp));
2694         pkt_len = ira->ira_pktlen;
2695 
2696         /*
2697          * Get a snapshot of these and allow other threads to change
2698          * them after that. We need the same recv_ancillary when determining
2699          * the size as when adding the ancillary data items.
2700          */
2701         mutex_enter(&connp->conn_lock);
2702         recv_ancillary = connp->conn_recv_ancillary;
2703         mutex_exit(&connp->conn_lock);
2704 
2705         ip_hdr_length = ira->ira_ip_hdr_length;
2706         ASSERT(MBLKL(mp) >= ip_hdr_length);  /* IP did a pullup */
2707 
2708         /* Initialize regardless of IP version */
2709         ipps.ipp_fields = 0;
2710 
2711         /* Apply socket filter, if needed */
2712         if (icmp->icmp_bpf_len != 0) {
2713                 if (icmp_eval_filter(icmp, mp, ira)) {
2714                         freemsg(mp);
2715                         return;
2716                 }
2717         }
2718 
2719         if (ira->ira_flags & IRAF_IS_IPV4) {
2720                 ASSERT(IPH_HDR_VERSION(rptr) == IPV4_VERSION);
2721                 ASSERT(MBLKL(mp) >= sizeof (ipha_t));
2722                 ASSERT(ira->ira_ip_hdr_length == IPH_HDR_LENGTH(rptr));
2723 
2724                 ipha = (ipha_t *)mp->b_rptr;
2725                 if (recv_ancillary.crb_all != 0)
2726                         (void) ip_find_hdr_v4(ipha, &ipps, B_FALSE);
2727 
2728                 /*
2729                  * BSD for some reason adjusts ipha_length to exclude the
2730                  * IP header length. We do the same.
2731                  */
2732                 if (is->is_bsd_compat) {
2733                         ushort_t len;
2734 
2735                         len = ntohs(ipha->ipha_length);
2736                         if (mp->b_datap->db_ref > 1) {
2737                                 /*
2738                                  * Allocate a new IP header so that we can


5128 }
5129 
5130 /*
5131  * Free the ICMP stack instance.
5132  */
5133 static void
5134 rawip_stack_fini(netstackid_t stackid, void *arg)
5135 {
5136         icmp_stack_t *is = (icmp_stack_t *)arg;
5137 
5138         kmem_free(is->is_propinfo_tbl, sizeof (icmp_propinfo_tbl));
5139         is->is_propinfo_tbl = NULL;
5140 
5141         rawip_kstat_fini(stackid, is->is_ksp);
5142         is->is_ksp = NULL;
5143         ldi_ident_release(is->is_ldi_ident);
5144         kmem_free(is, sizeof (*is));
5145 }
5146 
5147 static void *
5148 rawip_kstat_init(netstackid_t stackid)
5149 {
5150         kstat_t *ksp;
5151 
5152         rawip_named_kstat_t template = {
5153                 { "inDatagrams",        KSTAT_DATA_UINT32, 0 },
5154                 { "inCksumErrs",        KSTAT_DATA_UINT32, 0 },
5155                 { "inErrors",           KSTAT_DATA_UINT32, 0 },
5156                 { "outDatagrams",       KSTAT_DATA_UINT32, 0 },
5157                 { "outErrors",          KSTAT_DATA_UINT32, 0 },
5158         };
5159 
5160         ksp = kstat_create_netstack("icmp", 0, "rawip", "mib2",
5161             KSTAT_TYPE_NAMED, NUM_OF_FIELDS(rawip_named_kstat_t), 0, stackid);


5162         if (ksp == NULL || ksp->ks_data == NULL)
5163                 return (NULL);
5164 
5165         bcopy(&template, ksp->ks_data, sizeof (template));
5166         ksp->ks_update = rawip_kstat_update;
5167         ksp->ks_private = (void *)(uintptr_t)stackid;
5168 
5169         kstat_install(ksp);
5170         return (ksp);
5171 }
5172 
5173 static void
5174 rawip_kstat_fini(netstackid_t stackid, kstat_t *ksp)
5175 {
5176         if (ksp != NULL) {
5177                 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
5178                 kstat_delete_netstack(ksp, stackid);
5179         }
5180 }
5181