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
|