1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <sys/types.h> 32*0Sstevel@tonic-gate #include <sys/stream.h> 33*0Sstevel@tonic-gate #include <sys/stropts.h> 34*0Sstevel@tonic-gate #include <sys/strlog.h> 35*0Sstevel@tonic-gate #include <sys/strsun.h> 36*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 37*0Sstevel@tonic-gate #include <sys/tihdr.h> 38*0Sstevel@tonic-gate #include <sys/timod.h> 39*0Sstevel@tonic-gate #include <sys/ddi.h> 40*0Sstevel@tonic-gate #include <sys/sunddi.h> 41*0Sstevel@tonic-gate #include <sys/cmn_err.h> 42*0Sstevel@tonic-gate #include <sys/debug.h> 43*0Sstevel@tonic-gate #include <sys/kmem.h> 44*0Sstevel@tonic-gate #include <sys/policy.h> 45*0Sstevel@tonic-gate #include <sys/zone.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #include <sys/socket.h> 48*0Sstevel@tonic-gate #include <sys/isa_defs.h> 49*0Sstevel@tonic-gate #include <sys/suntpi.h> 50*0Sstevel@tonic-gate #include <sys/xti_inet.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #include <net/route.h> 53*0Sstevel@tonic-gate #include <net/if.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #include <netinet/in.h> 56*0Sstevel@tonic-gate #include <netinet/ip6.h> 57*0Sstevel@tonic-gate #include <netinet/icmp6.h> 58*0Sstevel@tonic-gate #include <inet/common.h> 59*0Sstevel@tonic-gate #include <inet/ip.h> 60*0Sstevel@tonic-gate #include <inet/ip6.h> 61*0Sstevel@tonic-gate #include <inet/ip_ire.h> 62*0Sstevel@tonic-gate #include <inet/mi.h> 63*0Sstevel@tonic-gate #include <inet/nd.h> 64*0Sstevel@tonic-gate #include <inet/optcom.h> 65*0Sstevel@tonic-gate #include <inet/snmpcom.h> 66*0Sstevel@tonic-gate #include <inet/kstatcom.h> 67*0Sstevel@tonic-gate #include <inet/rawip_impl.h> 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #include <netinet/ip_mroute.h> 70*0Sstevel@tonic-gate #include <inet/tcp.h> 71*0Sstevel@tonic-gate #include <net/pfkeyv2.h> 72*0Sstevel@tonic-gate #include <inet/ipsec_info.h> 73*0Sstevel@tonic-gate #include <inet/ipclassifier.h> 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate #define ICMP6 "icmp6" 76*0Sstevel@tonic-gate major_t ICMP6_MAJ; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * Object to represent database of options to search passed to 80*0Sstevel@tonic-gate * {sock,tpi}optcom_req() interface routine to take care of option 81*0Sstevel@tonic-gate * management and associated methods. 82*0Sstevel@tonic-gate * XXX These and other extern's should really move to a icmp header. 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate extern optdb_obj_t icmp_opt_obj; 85*0Sstevel@tonic-gate extern uint_t icmp_max_optsize; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * Synchronization notes: 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * At all points in this code where exclusive access is required, we 91*0Sstevel@tonic-gate * pass a message to a subroutine by invoking qwriter(..., PERIM_OUTER) 92*0Sstevel@tonic-gate * which will arrange to call the routine only after all threads have 93*0Sstevel@tonic-gate * exited the shared resource. 94*0Sstevel@tonic-gate */ 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */ 97*0Sstevel@tonic-gate typedef struct icmpparam_s { 98*0Sstevel@tonic-gate uint_t icmp_param_min; 99*0Sstevel@tonic-gate uint_t icmp_param_max; 100*0Sstevel@tonic-gate uint_t icmp_param_value; 101*0Sstevel@tonic-gate char *icmp_param_name; 102*0Sstevel@tonic-gate } icmpparam_t; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate static void icmp_addr_req(queue_t *q, mblk_t *mp); 105*0Sstevel@tonic-gate static void icmp_bind(queue_t *q, mblk_t *mp); 106*0Sstevel@tonic-gate static void icmp_bind_proto(queue_t *q); 107*0Sstevel@tonic-gate static int icmp_build_hdrs(queue_t *q, icmp_t *icmp); 108*0Sstevel@tonic-gate static void icmp_capability_req(queue_t *q, mblk_t *mp); 109*0Sstevel@tonic-gate static int icmp_close(queue_t *q); 110*0Sstevel@tonic-gate static void icmp_connect(queue_t *q, mblk_t *mp); 111*0Sstevel@tonic-gate static void icmp_disconnect(queue_t *q, mblk_t *mp); 112*0Sstevel@tonic-gate static void icmp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, 113*0Sstevel@tonic-gate int sys_error); 114*0Sstevel@tonic-gate static void icmp_err_ack_prim(queue_t *q, mblk_t *mp, t_scalar_t primitive, 115*0Sstevel@tonic-gate t_scalar_t t_error, int sys_error); 116*0Sstevel@tonic-gate static void icmp_icmp_error(queue_t *q, mblk_t *mp); 117*0Sstevel@tonic-gate static void icmp_icmp_error_ipv6(queue_t *q, mblk_t *mp); 118*0Sstevel@tonic-gate static void icmp_info_req(queue_t *q, mblk_t *mp); 119*0Sstevel@tonic-gate static mblk_t *icmp_ip_bind_mp(icmp_t *icmp, t_scalar_t bind_prim, 120*0Sstevel@tonic-gate t_scalar_t addr_length, in_port_t); 121*0Sstevel@tonic-gate static int icmp_open(queue_t *q, dev_t *devp, int flag, 122*0Sstevel@tonic-gate int sflag, cred_t *credp); 123*0Sstevel@tonic-gate static int icmp_unitdata_opt_process(queue_t *q, mblk_t *mp, 124*0Sstevel@tonic-gate int *errorp, void *thisdg_attrs); 125*0Sstevel@tonic-gate static boolean_t icmp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name); 126*0Sstevel@tonic-gate int icmp_opt_set(queue_t *q, uint_t optset_context, 127*0Sstevel@tonic-gate int level, int name, uint_t inlen, 128*0Sstevel@tonic-gate uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 129*0Sstevel@tonic-gate void *thisdg_attrs, cred_t *cr, mblk_t *mblk); 130*0Sstevel@tonic-gate int icmp_opt_get(queue_t *q, int level, int name, 131*0Sstevel@tonic-gate uchar_t *ptr); 132*0Sstevel@tonic-gate static int icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); 133*0Sstevel@tonic-gate static boolean_t icmp_param_register(icmpparam_t *icmppa, int cnt); 134*0Sstevel@tonic-gate static int icmp_param_set(queue_t *q, mblk_t *mp, char *value, 135*0Sstevel@tonic-gate caddr_t cp, cred_t *cr); 136*0Sstevel@tonic-gate static int icmp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky, 137*0Sstevel@tonic-gate uchar_t **optbufp, uint_t *optlenp); 138*0Sstevel@tonic-gate static void icmp_rput(queue_t *q, mblk_t *mp); 139*0Sstevel@tonic-gate static void icmp_rput_bind_ack(queue_t *q, mblk_t *mp); 140*0Sstevel@tonic-gate static int icmp_snmp_get(queue_t *q, mblk_t *mpctl); 141*0Sstevel@tonic-gate static int icmp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name, 142*0Sstevel@tonic-gate uchar_t *ptr, int len); 143*0Sstevel@tonic-gate static int icmp_status_report(queue_t *q, mblk_t *mp, caddr_t cp, 144*0Sstevel@tonic-gate cred_t *cr); 145*0Sstevel@tonic-gate static void icmp_ud_err(queue_t *q, mblk_t *mp, t_scalar_t err); 146*0Sstevel@tonic-gate static void icmp_unbind(queue_t *q, mblk_t *mp); 147*0Sstevel@tonic-gate static void icmp_wput(queue_t *q, mblk_t *mp); 148*0Sstevel@tonic-gate static void icmp_wput_ipv6(queue_t *q, mblk_t *mp, sin6_t *sin6, 149*0Sstevel@tonic-gate t_scalar_t tudr_optlen); 150*0Sstevel@tonic-gate static void icmp_wput_other(queue_t *q, mblk_t *mp); 151*0Sstevel@tonic-gate static void icmp_wput_iocdata(queue_t *q, mblk_t *mp); 152*0Sstevel@tonic-gate static void icmp_wput_restricted(queue_t *q, mblk_t *mp); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate static void rawip_kstat_init(void); 155*0Sstevel@tonic-gate static void rawip_kstat_fini(void); 156*0Sstevel@tonic-gate static int rawip_kstat_update(kstat_t *kp, int rw); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate static struct module_info info = { 160*0Sstevel@tonic-gate 5707, "icmp", 1, INFPSZ, 512, 128 161*0Sstevel@tonic-gate }; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate static struct qinit rinit = { 164*0Sstevel@tonic-gate (pfi_t)icmp_rput, NULL, icmp_open, icmp_close, NULL, &info 165*0Sstevel@tonic-gate }; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate static struct qinit winit = { 168*0Sstevel@tonic-gate (pfi_t)icmp_wput, NULL, NULL, NULL, NULL, &info 169*0Sstevel@tonic-gate }; 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate struct streamtab icmpinfo = { 172*0Sstevel@tonic-gate &rinit, &winit 173*0Sstevel@tonic-gate }; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate static sin_t sin_null; /* Zero address for quick clears */ 176*0Sstevel@tonic-gate static sin6_t sin6_null; /* Zero address for quick clears */ 177*0Sstevel@tonic-gate static void *icmp_g_head; /* Head for list of open icmp streams. */ 178*0Sstevel@tonic-gate static IDP icmp_g_nd; /* Points to table of ICMP ND variables. */ 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* MIB-2 stuff for SNMP */ 181*0Sstevel@tonic-gate static mib2_rawip_t rawip_mib; /* SNMP fixed size info */ 182*0Sstevel@tonic-gate static kstat_t *rawip_mibkp; /* kstat exporting rawip_mib data */ 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages */ 185*0Sstevel@tonic-gate static struct T_info_ack icmp_g_t_info_ack = { 186*0Sstevel@tonic-gate T_INFO_ACK, 187*0Sstevel@tonic-gate IP_MAXPACKET, /* TSDU_size. icmp allows maximum size messages. */ 188*0Sstevel@tonic-gate T_INVALID, /* ETSDU_size. icmp does not support expedited data. */ 189*0Sstevel@tonic-gate T_INVALID, /* CDATA_size. icmp does not support connect data. */ 190*0Sstevel@tonic-gate T_INVALID, /* DDATA_size. icmp does not support disconnect data. */ 191*0Sstevel@tonic-gate 0, /* ADDR_size - filled in later. */ 192*0Sstevel@tonic-gate 0, /* OPT_size - not initialized here */ 193*0Sstevel@tonic-gate IP_MAXPACKET, /* TIDU_size. icmp allows maximum size messages. */ 194*0Sstevel@tonic-gate T_CLTS, /* SERV_type. icmp supports connection-less. */ 195*0Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from icmp_state. */ 196*0Sstevel@tonic-gate (XPG4_1|SENDZERO) /* PROVIDER_flag */ 197*0Sstevel@tonic-gate }; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Table of ND variables supported by icmp. These are loaded into icmp_g_nd 201*0Sstevel@tonic-gate * in icmp_open. 202*0Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate static icmpparam_t icmp_param_arr[] = { 205*0Sstevel@tonic-gate /* min max value name */ 206*0Sstevel@tonic-gate { 0, 128, 32, "icmp_wroff_extra" }, 207*0Sstevel@tonic-gate { 1, 255, 255, "icmp_ipv4_ttl" }, 208*0Sstevel@tonic-gate { 0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS, "icmp_ipv6_hoplimit"}, 209*0Sstevel@tonic-gate { 0, 1, 1, "icmp_bsd_compat" }, 210*0Sstevel@tonic-gate { 4096, 65536, 8192, "icmp_xmit_hiwat"}, 211*0Sstevel@tonic-gate { 0, 65536, 1024, "icmp_xmit_lowat"}, 212*0Sstevel@tonic-gate { 4096, 65536, 8192, "icmp_recv_hiwat"}, 213*0Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "icmp_max_buf"}, 214*0Sstevel@tonic-gate }; 215*0Sstevel@tonic-gate #define icmp_wroff_extra icmp_param_arr[0].icmp_param_value 216*0Sstevel@tonic-gate #define icmp_ipv4_ttl icmp_param_arr[1].icmp_param_value 217*0Sstevel@tonic-gate #define icmp_ipv6_hoplimit icmp_param_arr[2].icmp_param_value 218*0Sstevel@tonic-gate #define icmp_bsd_compat icmp_param_arr[3].icmp_param_value 219*0Sstevel@tonic-gate #define icmp_xmit_hiwat icmp_param_arr[4].icmp_param_value 220*0Sstevel@tonic-gate #define icmp_xmit_lowat icmp_param_arr[5].icmp_param_value 221*0Sstevel@tonic-gate #define icmp_recv_hiwat icmp_param_arr[6].icmp_param_value 222*0Sstevel@tonic-gate #define icmp_max_buf icmp_param_arr[7].icmp_param_value 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * This routine is called to handle each O_T_BIND_REQ/T_BIND_REQ message 226*0Sstevel@tonic-gate * passed to icmp_wput. 227*0Sstevel@tonic-gate * The O_T_BIND_REQ/T_BIND_REQ is passed downstream to ip with the ICMP 228*0Sstevel@tonic-gate * protocol type placed in the message following the address. A T_BIND_ACK 229*0Sstevel@tonic-gate * message is passed upstream when ip acknowledges the request. 230*0Sstevel@tonic-gate * (Called as writer.) 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate static void 233*0Sstevel@tonic-gate icmp_bind(queue_t *q, mblk_t *mp) 234*0Sstevel@tonic-gate { 235*0Sstevel@tonic-gate sin_t *sin; 236*0Sstevel@tonic-gate sin6_t *sin6; 237*0Sstevel@tonic-gate mblk_t *mp1; 238*0Sstevel@tonic-gate struct T_bind_req *tbr; 239*0Sstevel@tonic-gate icmp_t *icmp; 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 242*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (*tbr)) { 243*0Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 244*0Sstevel@tonic-gate "icmp_bind: bad req, len %u", 245*0Sstevel@tonic-gate (uint_t)(mp->b_wptr - mp->b_rptr)); 246*0Sstevel@tonic-gate icmp_err_ack(q, mp, TPROTO, 0); 247*0Sstevel@tonic-gate return; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate if (icmp->icmp_state != TS_UNBND) { 250*0Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 251*0Sstevel@tonic-gate "icmp_bind: bad state, %d", icmp->icmp_state); 252*0Sstevel@tonic-gate icmp_err_ack(q, mp, TOUTSTATE, 0); 253*0Sstevel@tonic-gate return; 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate /* 256*0Sstevel@tonic-gate * Reallocate the message to make sure we have enough room for an 257*0Sstevel@tonic-gate * address and the protocol type. 258*0Sstevel@tonic-gate */ 259*0Sstevel@tonic-gate mp1 = reallocb(mp, sizeof (struct T_bind_ack) + sizeof (sin6_t) + 1, 1); 260*0Sstevel@tonic-gate if (!mp1) { 261*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 262*0Sstevel@tonic-gate return; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate mp = mp1; 265*0Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 266*0Sstevel@tonic-gate switch (tbr->ADDR_length) { 267*0Sstevel@tonic-gate case 0: /* Generic request */ 268*0Sstevel@tonic-gate tbr->ADDR_offset = sizeof (struct T_bind_req); 269*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 270*0Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin_t); 271*0Sstevel@tonic-gate sin = (sin_t *)&tbr[1]; 272*0Sstevel@tonic-gate *sin = sin_null; 273*0Sstevel@tonic-gate sin->sin_family = AF_INET; 274*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin[1]; 275*0Sstevel@tonic-gate } else { 276*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 277*0Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin6_t); 278*0Sstevel@tonic-gate sin6 = (sin6_t *)&tbr[1]; 279*0Sstevel@tonic-gate *sin6 = sin6_null; 280*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 281*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin6[1]; 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate break; 284*0Sstevel@tonic-gate case sizeof (sin_t): /* Complete IP address */ 285*0Sstevel@tonic-gate sin = (sin_t *)mi_offset_param(mp, tbr->ADDR_offset, 286*0Sstevel@tonic-gate sizeof (sin_t)); 287*0Sstevel@tonic-gate if (sin == NULL || !OK_32PTR((char *)sin)) { 288*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EINVAL); 289*0Sstevel@tonic-gate return; 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET || 292*0Sstevel@tonic-gate sin->sin_family != AF_INET) { 293*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 294*0Sstevel@tonic-gate return; 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate break; 297*0Sstevel@tonic-gate case sizeof (sin6_t): /* Complete IP address */ 298*0Sstevel@tonic-gate sin6 = (sin6_t *)mi_offset_param(mp, tbr->ADDR_offset, 299*0Sstevel@tonic-gate sizeof (sin6_t)); 300*0Sstevel@tonic-gate if (sin6 == NULL || !OK_32PTR((char *)sin6)) { 301*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EINVAL); 302*0Sstevel@tonic-gate return; 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6 || 305*0Sstevel@tonic-gate sin6->sin6_family != AF_INET6) { 306*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 307*0Sstevel@tonic-gate return; 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate /* No support for mapped addresses on raw sockets */ 310*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 311*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EADDRNOTAVAIL); 312*0Sstevel@tonic-gate return; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate break; 315*0Sstevel@tonic-gate default: 316*0Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 317*0Sstevel@tonic-gate "icmp_bind: bad ADDR_length %d", tbr->ADDR_length); 318*0Sstevel@tonic-gate icmp_err_ack(q, mp, TBADADDR, 0); 319*0Sstevel@tonic-gate return; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate /* 322*0Sstevel@tonic-gate * Copy the source address into our icmp structure. This address 323*0Sstevel@tonic-gate * may still be zero; if so, ip will fill in the correct address 324*0Sstevel@tonic-gate * each time an outbound packet is passed to it. 325*0Sstevel@tonic-gate * If we are binding to a broadcast or multicast address icmp_rput 326*0Sstevel@tonic-gate * will clear the source address when it receives the T_BIND_ACK. 327*0Sstevel@tonic-gate */ 328*0Sstevel@tonic-gate icmp->icmp_state = TS_IDLE; 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 331*0Sstevel@tonic-gate ASSERT(sin != NULL); 332*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV4_VERSION); 333*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, 334*0Sstevel@tonic-gate &icmp->icmp_v6src); 335*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 336*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len; 337*0Sstevel@tonic-gate icmp->icmp_bound_v6src = icmp->icmp_v6src; 338*0Sstevel@tonic-gate } else { 339*0Sstevel@tonic-gate int error; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate ASSERT(sin6 != NULL); 342*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV6_VERSION); 343*0Sstevel@tonic-gate icmp->icmp_v6src = sin6->sin6_addr; 344*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = icmp->icmp_sticky_hdrs_len; 345*0Sstevel@tonic-gate icmp->icmp_bound_v6src = icmp->icmp_v6src; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* Rebuild the header template */ 348*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 349*0Sstevel@tonic-gate if (error != 0) { 350*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, error); 351*0Sstevel@tonic-gate return; 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Place protocol type in the O_T_BIND_REQ/T_BIND_REQ following 356*0Sstevel@tonic-gate * the address. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate *mp->b_wptr++ = icmp->icmp_proto; 359*0Sstevel@tonic-gate if (!(V6_OR_V4_INADDR_ANY(icmp->icmp_v6src))) { 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Append a request for an IRE if src not 0 (INADDR_ANY) 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 364*0Sstevel@tonic-gate if (!mp->b_cont) { 365*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 366*0Sstevel@tonic-gate return; 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 369*0Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* Pass the O_T_BIND_REQ/T_BIND_REQ to ip. */ 373*0Sstevel@tonic-gate putnext(q, mp); 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate /* 377*0Sstevel@tonic-gate * Send message to IP to just bind to the protocol. 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate static void 380*0Sstevel@tonic-gate icmp_bind_proto(queue_t *q) 381*0Sstevel@tonic-gate { 382*0Sstevel@tonic-gate mblk_t *mp; 383*0Sstevel@tonic-gate struct T_bind_req *tbr; 384*0Sstevel@tonic-gate icmp_t *icmp; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 387*0Sstevel@tonic-gate mp = allocb(sizeof (struct T_bind_req) + sizeof (sin6_t) + 1, 388*0Sstevel@tonic-gate BPRI_MED); 389*0Sstevel@tonic-gate if (!mp) { 390*0Sstevel@tonic-gate return; 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 393*0Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 394*0Sstevel@tonic-gate tbr->PRIM_type = O_T_BIND_REQ; /* change to T_BIND_REQ ? */ 395*0Sstevel@tonic-gate tbr->ADDR_offset = sizeof (struct T_bind_req); 396*0Sstevel@tonic-gate if (icmp->icmp_ipversion == IPV4_VERSION) { 397*0Sstevel@tonic-gate sin_t *sin; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin_t); 400*0Sstevel@tonic-gate sin = (sin_t *)&tbr[1]; 401*0Sstevel@tonic-gate *sin = sin_null; 402*0Sstevel@tonic-gate sin->sin_family = AF_INET; 403*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin[1]; 404*0Sstevel@tonic-gate } else { 405*0Sstevel@tonic-gate sin6_t *sin6; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV6_VERSION); 408*0Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin6_t); 409*0Sstevel@tonic-gate sin6 = (sin6_t *)&tbr[1]; 410*0Sstevel@tonic-gate *sin6 = sin6_null; 411*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 412*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin6[1]; 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* Place protocol type in the O_T_BIND_REQ following the address. */ 416*0Sstevel@tonic-gate *mp->b_wptr++ = icmp->icmp_proto; 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* Pass the O_T_BIND_REQ to ip. */ 419*0Sstevel@tonic-gate putnext(q, mp); 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * This routine handles each T_CONN_REQ message passed to icmp. It 424*0Sstevel@tonic-gate * associates a default destination address with the stream. 425*0Sstevel@tonic-gate * 426*0Sstevel@tonic-gate * This routine sends down a T_BIND_REQ to IP with the following mblks: 427*0Sstevel@tonic-gate * T_BIND_REQ - specifying local and remote address. 428*0Sstevel@tonic-gate * IRE_DB_REQ_TYPE - to get an IRE back containing ire_type and src 429*0Sstevel@tonic-gate * T_OK_ACK - for the T_CONN_REQ 430*0Sstevel@tonic-gate * T_CONN_CON - to keep the TPI user happy 431*0Sstevel@tonic-gate * 432*0Sstevel@tonic-gate * The connect completes in icmp_rput. 433*0Sstevel@tonic-gate * When a T_BIND_ACK is received information is extracted from the IRE 434*0Sstevel@tonic-gate * and the two appended messages are sent to the TPI user. 435*0Sstevel@tonic-gate * Should icmp_rput receive T_ERROR_ACK for the T_BIND_REQ it will convert 436*0Sstevel@tonic-gate * it to an error ack for the appropriate primitive. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate static void 439*0Sstevel@tonic-gate icmp_connect(queue_t *q, mblk_t *mp) 440*0Sstevel@tonic-gate { 441*0Sstevel@tonic-gate sin_t *sin; 442*0Sstevel@tonic-gate sin6_t *sin6; 443*0Sstevel@tonic-gate mblk_t *mp1, *mp2; 444*0Sstevel@tonic-gate struct T_conn_req *tcr; 445*0Sstevel@tonic-gate icmp_t *icmp; 446*0Sstevel@tonic-gate ipaddr_t v4dst; 447*0Sstevel@tonic-gate in6_addr_t v6dst; 448*0Sstevel@tonic-gate uint32_t flowinfo; 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 451*0Sstevel@tonic-gate tcr = (struct T_conn_req *)mp->b_rptr; 452*0Sstevel@tonic-gate /* Sanity checks */ 453*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr < sizeof (struct T_conn_req))) { 454*0Sstevel@tonic-gate icmp_err_ack(q, mp, TPROTO, 0); 455*0Sstevel@tonic-gate return; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate if (icmp->icmp_state == TS_DATA_XFER) { 459*0Sstevel@tonic-gate /* Already connected - clear out state */ 460*0Sstevel@tonic-gate icmp->icmp_v6src = icmp->icmp_bound_v6src; 461*0Sstevel@tonic-gate icmp->icmp_state = TS_IDLE; 462*0Sstevel@tonic-gate } 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (tcr->OPT_length != 0) { 466*0Sstevel@tonic-gate icmp_err_ack(q, mp, TBADOPT, 0); 467*0Sstevel@tonic-gate return; 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate switch (tcr->DEST_length) { 470*0Sstevel@tonic-gate default: 471*0Sstevel@tonic-gate icmp_err_ack(q, mp, TBADADDR, 0); 472*0Sstevel@tonic-gate return; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate case sizeof (sin_t): 475*0Sstevel@tonic-gate sin = (sin_t *)mi_offset_param(mp, tcr->DEST_offset, 476*0Sstevel@tonic-gate sizeof (sin_t)); 477*0Sstevel@tonic-gate if (sin == NULL || !OK_32PTR((char *)sin)) { 478*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EINVAL); 479*0Sstevel@tonic-gate return; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET || 482*0Sstevel@tonic-gate sin->sin_family != AF_INET) { 483*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 484*0Sstevel@tonic-gate return; 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate v4dst = sin->sin_addr.s_addr; 487*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst); 488*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV4_VERSION); 489*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 490*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len; 491*0Sstevel@tonic-gate break; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate case sizeof (sin6_t): 494*0Sstevel@tonic-gate sin6 = (sin6_t *)mi_offset_param(mp, tcr->DEST_offset, 495*0Sstevel@tonic-gate sizeof (sin6_t)); 496*0Sstevel@tonic-gate if (sin6 == NULL || !OK_32PTR((char *)sin6)) { 497*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EINVAL); 498*0Sstevel@tonic-gate return; 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6 || 501*0Sstevel@tonic-gate sin6->sin6_family != AF_INET6) { 502*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 503*0Sstevel@tonic-gate return; 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate /* No support for mapped addresses on raw sockets */ 506*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 507*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, EADDRNOTAVAIL); 508*0Sstevel@tonic-gate return; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate v6dst = sin6->sin6_addr; 511*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV6_VERSION); 512*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = icmp->icmp_sticky_hdrs_len; 513*0Sstevel@tonic-gate flowinfo = sin6->sin6_flowinfo; 514*0Sstevel@tonic-gate break; 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate if (icmp->icmp_ipversion == IPV4_VERSION) { 517*0Sstevel@tonic-gate /* 518*0Sstevel@tonic-gate * Interpret a zero destination to mean loopback. 519*0Sstevel@tonic-gate * Update the T_CONN_REQ (sin/sin6) since it is used to 520*0Sstevel@tonic-gate * generate the T_CONN_CON. 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate if (v4dst == INADDR_ANY) { 523*0Sstevel@tonic-gate v4dst = htonl(INADDR_LOOPBACK); 524*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst); 525*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 526*0Sstevel@tonic-gate sin->sin_addr.s_addr = v4dst; 527*0Sstevel@tonic-gate } else { 528*0Sstevel@tonic-gate sin6->sin6_addr = v6dst; 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate icmp->icmp_v6dst = v6dst; 532*0Sstevel@tonic-gate icmp->icmp_flowinfo = 0; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * If the destination address is multicast and 536*0Sstevel@tonic-gate * an outgoing multicast interface has been set, 537*0Sstevel@tonic-gate * use the address of that interface as our 538*0Sstevel@tonic-gate * source address if no source address has been set. 539*0Sstevel@tonic-gate */ 540*0Sstevel@tonic-gate if (V4_PART_OF_V6(icmp->icmp_v6src) == INADDR_ANY && 541*0Sstevel@tonic-gate CLASSD(v4dst) && 542*0Sstevel@tonic-gate icmp->icmp_multicast_if_addr != INADDR_ANY) { 543*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(icmp->icmp_multicast_if_addr, 544*0Sstevel@tonic-gate &icmp->icmp_v6src); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate } else { 547*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV6_VERSION); 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * Interpret a zero destination to mean loopback. 550*0Sstevel@tonic-gate * Update the T_CONN_REQ (sin/sin6) since it is used to 551*0Sstevel@tonic-gate * generate the T_CONN_CON. 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&v6dst)) { 554*0Sstevel@tonic-gate v6dst = ipv6_loopback; 555*0Sstevel@tonic-gate sin6->sin6_addr = v6dst; 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate icmp->icmp_v6dst = v6dst; 558*0Sstevel@tonic-gate icmp->icmp_flowinfo = flowinfo; 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * If the destination address is multicast and 561*0Sstevel@tonic-gate * an outgoing multicast interface has been set, 562*0Sstevel@tonic-gate * then the ip bind logic will pick the correct source 563*0Sstevel@tonic-gate * address (i.e. matching the outgoing multicast interface). 564*0Sstevel@tonic-gate */ 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * Send down bind to IP to verify that there is a route 569*0Sstevel@tonic-gate * and to determine the source address. 570*0Sstevel@tonic-gate * This will come back as T_BIND_ACK with an IRE_DB_TYPE in rput. 571*0Sstevel@tonic-gate */ 572*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 573*0Sstevel@tonic-gate mp1 = icmp_ip_bind_mp(icmp, O_T_BIND_REQ, sizeof (ipa_conn_t), 574*0Sstevel@tonic-gate sin->sin_port); 575*0Sstevel@tonic-gate } else { 576*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 577*0Sstevel@tonic-gate mp1 = icmp_ip_bind_mp(icmp, O_T_BIND_REQ, sizeof (ipa6_conn_t), 578*0Sstevel@tonic-gate sin6->sin6_port); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate if (mp1 == NULL) { 581*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 582*0Sstevel@tonic-gate return; 583*0Sstevel@tonic-gate } 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate /* 586*0Sstevel@tonic-gate * We also have to send a connection confirmation to 587*0Sstevel@tonic-gate * keep TLI happy. Prepare it for icmp_rput. 588*0Sstevel@tonic-gate */ 589*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 590*0Sstevel@tonic-gate mp2 = mi_tpi_conn_con(NULL, (char *)sin, sizeof (*sin), NULL, 591*0Sstevel@tonic-gate 0); 592*0Sstevel@tonic-gate } else { 593*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 594*0Sstevel@tonic-gate mp2 = mi_tpi_conn_con(NULL, (char *)sin6, sizeof (*sin6), NULL, 595*0Sstevel@tonic-gate 0); 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate if (mp2 == NULL) { 598*0Sstevel@tonic-gate freemsg(mp1); 599*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 600*0Sstevel@tonic-gate return; 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate mp = mi_tpi_ok_ack_alloc(mp); 604*0Sstevel@tonic-gate if (mp == NULL) { 605*0Sstevel@tonic-gate /* Unable to reuse the T_CONN_REQ for the ack. */ 606*0Sstevel@tonic-gate freemsg(mp2); 607*0Sstevel@tonic-gate icmp_err_ack_prim(q, mp1, T_CONN_REQ, TSYSERR, ENOMEM); 608*0Sstevel@tonic-gate return; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate icmp->icmp_state = TS_DATA_XFER; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* Hang onto the T_OK_ACK and T_CONN_CON for later. */ 614*0Sstevel@tonic-gate linkb(mp1, mp); 615*0Sstevel@tonic-gate linkb(mp1, mp2); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate putnext(q, mp1); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate static int 621*0Sstevel@tonic-gate icmp_close(queue_t *q) 622*0Sstevel@tonic-gate { 623*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 624*0Sstevel@tonic-gate int i1; 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate qprocsoff(q); 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate /* If there are any options associated with the stream, free them. */ 629*0Sstevel@tonic-gate if (icmp->icmp_ip_snd_options) 630*0Sstevel@tonic-gate mi_free((char *)icmp->icmp_ip_snd_options); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate if (icmp->icmp_filter != NULL) 633*0Sstevel@tonic-gate kmem_free(icmp->icmp_filter, sizeof (icmp6_filter_t)); 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate /* Free memory associated with sticky options */ 636*0Sstevel@tonic-gate if (icmp->icmp_sticky_hdrs_len != 0) { 637*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_hdrs, 638*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs_len); 639*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs = NULL; 640*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs_len = 0; 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) { 643*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_ipp.ipp_hopopts, 644*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_hopoptslen); 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) { 647*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_ipp.ipp_rtdstopts, 648*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_rtdstoptslen); 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTHDR) { 651*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_ipp.ipp_rthdr, 652*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_rthdrlen); 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) { 655*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_ipp.ipp_dstopts, 656*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_dstoptslen); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_PATHMTU) { 659*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_ipp.ipp_pathmtu, 660*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_pathmtulen); 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_fields &= 663*0Sstevel@tonic-gate ~(IPPF_HOPOPTS|IPPF_RTDSTOPTS|IPPF_RTHDR|IPPF_DSTOPTS); 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate crfree(icmp->icmp_credp); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate /* Free the icmp structure and release the minor device number. */ 668*0Sstevel@tonic-gate i1 = mi_close_comm(&icmp_g_head, q); 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate return (i1); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate /* 674*0Sstevel@tonic-gate * This routine handles each T_DISCON_REQ message passed to icmp 675*0Sstevel@tonic-gate * as an indicating that ICMP is no longer connected. This results 676*0Sstevel@tonic-gate * in sending a T_BIND_REQ to IP to restore the binding to just 677*0Sstevel@tonic-gate * the local address. 678*0Sstevel@tonic-gate * 679*0Sstevel@tonic-gate * This routine sends down a T_BIND_REQ to IP with the following mblks: 680*0Sstevel@tonic-gate * T_BIND_REQ - specifying just the local address. 681*0Sstevel@tonic-gate * T_OK_ACK - for the T_DISCON_REQ 682*0Sstevel@tonic-gate * 683*0Sstevel@tonic-gate * The disconnect completes in icmp_rput. 684*0Sstevel@tonic-gate * When a T_BIND_ACK is received the appended T_OK_ACK is sent to the TPI user. 685*0Sstevel@tonic-gate * Should icmp_rput receive T_ERROR_ACK for the T_BIND_REQ it will convert 686*0Sstevel@tonic-gate * it to an error ack for the appropriate primitive. 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate static void 689*0Sstevel@tonic-gate icmp_disconnect(queue_t *q, mblk_t *mp) 690*0Sstevel@tonic-gate { 691*0Sstevel@tonic-gate icmp_t *icmp; 692*0Sstevel@tonic-gate mblk_t *mp1; 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate if (icmp->icmp_state != TS_DATA_XFER) { 697*0Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 698*0Sstevel@tonic-gate "icmp_disconnect: bad state, %d", icmp->icmp_state); 699*0Sstevel@tonic-gate icmp_err_ack(q, mp, TOUTSTATE, 0); 700*0Sstevel@tonic-gate return; 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate icmp->icmp_v6src = icmp->icmp_bound_v6src; 703*0Sstevel@tonic-gate icmp->icmp_state = TS_IDLE; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * Send down bind to IP to remove the full binding and revert 707*0Sstevel@tonic-gate * to the local address binding. 708*0Sstevel@tonic-gate */ 709*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 710*0Sstevel@tonic-gate mp1 = icmp_ip_bind_mp(icmp, O_T_BIND_REQ, sizeof (sin_t), 0); 711*0Sstevel@tonic-gate } else { 712*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 713*0Sstevel@tonic-gate mp1 = icmp_ip_bind_mp(icmp, O_T_BIND_REQ, sizeof (sin6_t), 0); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate if (mp1 == NULL) { 716*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 717*0Sstevel@tonic-gate return; 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate mp = mi_tpi_ok_ack_alloc(mp); 720*0Sstevel@tonic-gate if (mp == NULL) { 721*0Sstevel@tonic-gate /* Unable to reuse the T_DISCON_REQ for the ack. */ 722*0Sstevel@tonic-gate icmp_err_ack_prim(q, mp1, T_DISCON_REQ, TSYSERR, ENOMEM); 723*0Sstevel@tonic-gate return; 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) { 727*0Sstevel@tonic-gate int error; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate /* Rebuild the header template */ 730*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 731*0Sstevel@tonic-gate if (error != 0) { 732*0Sstevel@tonic-gate icmp_err_ack_prim(q, mp, T_DISCON_REQ, TSYSERR, error); 733*0Sstevel@tonic-gate freemsg(mp1); 734*0Sstevel@tonic-gate return; 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate icmp->icmp_discon_pending = 1; 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate /* Append the T_OK_ACK to the T_BIND_REQ for icmp_rput */ 740*0Sstevel@tonic-gate linkb(mp1, mp); 741*0Sstevel@tonic-gate putnext(q, mp1); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate /* This routine creates a T_ERROR_ACK message and passes it upstream. */ 745*0Sstevel@tonic-gate static void 746*0Sstevel@tonic-gate icmp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 747*0Sstevel@tonic-gate { 748*0Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 749*0Sstevel@tonic-gate qreply(q, mp); 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate /* Shorthand to generate and send TPI error acks to our client */ 753*0Sstevel@tonic-gate static void 754*0Sstevel@tonic-gate icmp_err_ack_prim(queue_t *q, mblk_t *mp, t_scalar_t primitive, 755*0Sstevel@tonic-gate t_scalar_t t_error, int sys_error) 756*0Sstevel@tonic-gate { 757*0Sstevel@tonic-gate struct T_error_ack *teackp; 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack), 760*0Sstevel@tonic-gate M_PCPROTO, T_ERROR_ACK)) != NULL) { 761*0Sstevel@tonic-gate teackp = (struct T_error_ack *)mp->b_rptr; 762*0Sstevel@tonic-gate teackp->ERROR_prim = primitive; 763*0Sstevel@tonic-gate teackp->TLI_error = t_error; 764*0Sstevel@tonic-gate teackp->UNIX_error = sys_error; 765*0Sstevel@tonic-gate qreply(q, mp); 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate } 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate /* 770*0Sstevel@tonic-gate * icmp_icmp_error is called by icmp_rput to process ICMP 771*0Sstevel@tonic-gate * messages passed up by IP. 772*0Sstevel@tonic-gate * Generates the appropriate T_UDERROR_IND for permanent 773*0Sstevel@tonic-gate * (non-transient) errors. 774*0Sstevel@tonic-gate * Assumes that IP has pulled up everything up to and including 775*0Sstevel@tonic-gate * the ICMP header. 776*0Sstevel@tonic-gate */ 777*0Sstevel@tonic-gate static void 778*0Sstevel@tonic-gate icmp_icmp_error(queue_t *q, mblk_t *mp) 779*0Sstevel@tonic-gate { 780*0Sstevel@tonic-gate icmph_t *icmph; 781*0Sstevel@tonic-gate ipha_t *ipha; 782*0Sstevel@tonic-gate int iph_hdr_length; 783*0Sstevel@tonic-gate sin_t sin; 784*0Sstevel@tonic-gate sin6_t sin6; 785*0Sstevel@tonic-gate mblk_t *mp1; 786*0Sstevel@tonic-gate int error = 0; 787*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate /* 790*0Sstevel@tonic-gate * Deliver T_UDERROR_IND when the application has asked for it. 791*0Sstevel@tonic-gate * The socket layer enables this automatically when connected. 792*0Sstevel@tonic-gate */ 793*0Sstevel@tonic-gate if (!icmp->icmp_dgram_errind) { 794*0Sstevel@tonic-gate freemsg(mp); 795*0Sstevel@tonic-gate return; 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) != IPV4_VERSION) { 801*0Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION); 802*0Sstevel@tonic-gate icmp_icmp_error_ipv6(q, mp); 803*0Sstevel@tonic-gate return; 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION); 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate iph_hdr_length = IPH_HDR_LENGTH(ipha); 808*0Sstevel@tonic-gate icmph = (icmph_t *)(&mp->b_rptr[iph_hdr_length]); 809*0Sstevel@tonic-gate ipha = (ipha_t *)&icmph[1]; 810*0Sstevel@tonic-gate iph_hdr_length = IPH_HDR_LENGTH(ipha); 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate switch (icmph->icmph_type) { 813*0Sstevel@tonic-gate case ICMP_DEST_UNREACHABLE: 814*0Sstevel@tonic-gate switch (icmph->icmph_code) { 815*0Sstevel@tonic-gate case ICMP_FRAGMENTATION_NEEDED: 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * IP has already adjusted the path MTU. 818*0Sstevel@tonic-gate * XXX Somehow pass MTU indication to application? 819*0Sstevel@tonic-gate */ 820*0Sstevel@tonic-gate break; 821*0Sstevel@tonic-gate case ICMP_PORT_UNREACHABLE: 822*0Sstevel@tonic-gate case ICMP_PROTOCOL_UNREACHABLE: 823*0Sstevel@tonic-gate error = ECONNREFUSED; 824*0Sstevel@tonic-gate break; 825*0Sstevel@tonic-gate default: 826*0Sstevel@tonic-gate /* Transient errors */ 827*0Sstevel@tonic-gate break; 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate break; 830*0Sstevel@tonic-gate default: 831*0Sstevel@tonic-gate /* Transient errors */ 832*0Sstevel@tonic-gate break; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate if (error == 0) { 835*0Sstevel@tonic-gate freemsg(mp); 836*0Sstevel@tonic-gate return; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate switch (icmp->icmp_family) { 840*0Sstevel@tonic-gate case AF_INET: 841*0Sstevel@tonic-gate sin = sin_null; 842*0Sstevel@tonic-gate sin.sin_family = AF_INET; 843*0Sstevel@tonic-gate sin.sin_addr.s_addr = ipha->ipha_dst; 844*0Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin, sizeof (sin_t), NULL, 0, 845*0Sstevel@tonic-gate error); 846*0Sstevel@tonic-gate break; 847*0Sstevel@tonic-gate case AF_INET6: 848*0Sstevel@tonic-gate sin6 = sin6_null; 849*0Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 850*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &sin6.sin6_addr); 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin6, sizeof (sin6_t), 853*0Sstevel@tonic-gate NULL, 0, error); 854*0Sstevel@tonic-gate break; 855*0Sstevel@tonic-gate } 856*0Sstevel@tonic-gate if (mp1) 857*0Sstevel@tonic-gate putnext(q, mp1); 858*0Sstevel@tonic-gate freemsg(mp); 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate /* 862*0Sstevel@tonic-gate * icmp_icmp_error_ipv6 is called by icmp_icmp_error to process ICMPv6 863*0Sstevel@tonic-gate * for IPv6 packets. 864*0Sstevel@tonic-gate * Send permanent (non-transient) errors upstream. 865*0Sstevel@tonic-gate * Assumes that IP has pulled up all the extension headers as well 866*0Sstevel@tonic-gate * as the ICMPv6 header. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate static void 869*0Sstevel@tonic-gate icmp_icmp_error_ipv6(queue_t *q, mblk_t *mp) 870*0Sstevel@tonic-gate { 871*0Sstevel@tonic-gate icmp6_t *icmp6; 872*0Sstevel@tonic-gate ip6_t *ip6h, *outer_ip6h; 873*0Sstevel@tonic-gate uint16_t iph_hdr_length; 874*0Sstevel@tonic-gate uint8_t *nexthdrp; 875*0Sstevel@tonic-gate sin6_t sin6; 876*0Sstevel@tonic-gate mblk_t *mp1; 877*0Sstevel@tonic-gate int error = 0; 878*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate outer_ip6h = (ip6_t *)mp->b_rptr; 881*0Sstevel@tonic-gate if (outer_ip6h->ip6_nxt != IPPROTO_ICMPV6) 882*0Sstevel@tonic-gate iph_hdr_length = ip_hdr_length_v6(mp, outer_ip6h); 883*0Sstevel@tonic-gate else 884*0Sstevel@tonic-gate iph_hdr_length = IPV6_HDR_LEN; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate icmp6 = (icmp6_t *)&mp->b_rptr[iph_hdr_length]; 887*0Sstevel@tonic-gate ip6h = (ip6_t *)&icmp6[1]; 888*0Sstevel@tonic-gate if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &iph_hdr_length, &nexthdrp)) { 889*0Sstevel@tonic-gate freemsg(mp); 890*0Sstevel@tonic-gate return; 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate if (*nexthdrp != icmp->icmp_proto) { 893*0Sstevel@tonic-gate /* 894*0Sstevel@tonic-gate * Could have switched icmp_proto after while ip did fanout of 895*0Sstevel@tonic-gate * this message 896*0Sstevel@tonic-gate */ 897*0Sstevel@tonic-gate freemsg(mp); 898*0Sstevel@tonic-gate return; 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate switch (icmp6->icmp6_type) { 901*0Sstevel@tonic-gate case ICMP6_DST_UNREACH: 902*0Sstevel@tonic-gate switch (icmp6->icmp6_code) { 903*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOPORT: 904*0Sstevel@tonic-gate error = ECONNREFUSED; 905*0Sstevel@tonic-gate break; 906*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADMIN: 907*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOROUTE: 908*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_BEYONDSCOPE: 909*0Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADDR: 910*0Sstevel@tonic-gate /* Transient errors */ 911*0Sstevel@tonic-gate break; 912*0Sstevel@tonic-gate default: 913*0Sstevel@tonic-gate break; 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate break; 916*0Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG: { 917*0Sstevel@tonic-gate struct T_unitdata_ind *tudi; 918*0Sstevel@tonic-gate struct T_opthdr *toh; 919*0Sstevel@tonic-gate size_t udi_size; 920*0Sstevel@tonic-gate mblk_t *newmp; 921*0Sstevel@tonic-gate t_scalar_t opt_length = sizeof (struct T_opthdr) + 922*0Sstevel@tonic-gate sizeof (struct ip6_mtuinfo); 923*0Sstevel@tonic-gate sin6_t *sin6; 924*0Sstevel@tonic-gate struct ip6_mtuinfo *mtuinfo; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate /* 927*0Sstevel@tonic-gate * If the application has requested to receive path mtu 928*0Sstevel@tonic-gate * information, send up an empty message containing an 929*0Sstevel@tonic-gate * IPV6_PATHMTU ancillary data item. 930*0Sstevel@tonic-gate */ 931*0Sstevel@tonic-gate if (!icmp->icmp_ipv6_recvpathmtu) 932*0Sstevel@tonic-gate break; 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t) + 935*0Sstevel@tonic-gate opt_length; 936*0Sstevel@tonic-gate if ((newmp = allocb(udi_size, BPRI_MED)) == NULL) { 937*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 938*0Sstevel@tonic-gate break; 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate /* 942*0Sstevel@tonic-gate * newmp->b_cont is left to NULL on purpose. This is an 943*0Sstevel@tonic-gate * empty message containing only ancillary data. 944*0Sstevel@tonic-gate */ 945*0Sstevel@tonic-gate newmp->b_datap->db_type = M_PROTO; 946*0Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)newmp->b_rptr; 947*0Sstevel@tonic-gate newmp->b_wptr = (uchar_t *)tudi + udi_size; 948*0Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 949*0Sstevel@tonic-gate tudi->SRC_length = sizeof (sin6_t); 950*0Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 951*0Sstevel@tonic-gate tudi->OPT_offset = tudi->SRC_offset + sizeof (sin6_t); 952*0Sstevel@tonic-gate tudi->OPT_length = opt_length; 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate sin6 = (sin6_t *)&tudi[1]; 955*0Sstevel@tonic-gate bzero(sin6, sizeof (sin6_t)); 956*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 957*0Sstevel@tonic-gate sin6->sin6_addr = icmp->icmp_v6dst; 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate toh = (struct T_opthdr *)&sin6[1]; 960*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 961*0Sstevel@tonic-gate toh->name = IPV6_PATHMTU; 962*0Sstevel@tonic-gate toh->len = opt_length; 963*0Sstevel@tonic-gate toh->status = 0; 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate mtuinfo = (struct ip6_mtuinfo *)&toh[1]; 966*0Sstevel@tonic-gate bzero(mtuinfo, sizeof (struct ip6_mtuinfo)); 967*0Sstevel@tonic-gate mtuinfo->ip6m_addr.sin6_family = AF_INET6; 968*0Sstevel@tonic-gate mtuinfo->ip6m_addr.sin6_addr = ip6h->ip6_dst; 969*0Sstevel@tonic-gate mtuinfo->ip6m_mtu = icmp6->icmp6_mtu; 970*0Sstevel@tonic-gate /* 971*0Sstevel@tonic-gate * We've consumed everything we need from the original 972*0Sstevel@tonic-gate * message. Free it, then send our empty message. 973*0Sstevel@tonic-gate */ 974*0Sstevel@tonic-gate freemsg(mp); 975*0Sstevel@tonic-gate putnext(q, newmp); 976*0Sstevel@tonic-gate return; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate case ICMP6_TIME_EXCEEDED: 979*0Sstevel@tonic-gate /* Transient errors */ 980*0Sstevel@tonic-gate break; 981*0Sstevel@tonic-gate case ICMP6_PARAM_PROB: 982*0Sstevel@tonic-gate /* If this corresponds to an ICMP_PROTOCOL_UNREACHABLE */ 983*0Sstevel@tonic-gate if (icmp6->icmp6_code == ICMP6_PARAMPROB_NEXTHEADER && 984*0Sstevel@tonic-gate (uchar_t *)ip6h + icmp6->icmp6_pptr == 985*0Sstevel@tonic-gate (uchar_t *)nexthdrp) { 986*0Sstevel@tonic-gate error = ECONNREFUSED; 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate break; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate if (error == 0) { 992*0Sstevel@tonic-gate freemsg(mp); 993*0Sstevel@tonic-gate return; 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate sin6 = sin6_null; 997*0Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 998*0Sstevel@tonic-gate sin6.sin6_addr = ip6h->ip6_dst; 999*0Sstevel@tonic-gate sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK; 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin6, sizeof (sin6_t), NULL, 0, 1002*0Sstevel@tonic-gate error); 1003*0Sstevel@tonic-gate if (mp1) 1004*0Sstevel@tonic-gate putnext(q, mp1); 1005*0Sstevel@tonic-gate freemsg(mp); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate /* 1009*0Sstevel@tonic-gate * This routine responds to T_ADDR_REQ messages. It is called by icmp_wput. 1010*0Sstevel@tonic-gate * The local address is filled in if endpoint is bound. The remote address 1011*0Sstevel@tonic-gate * is filled in if remote address has been precified ("connected endpoint") 1012*0Sstevel@tonic-gate * (The concept of connected CLTS sockets is alien to published TPI 1013*0Sstevel@tonic-gate * but we support it anyway). 1014*0Sstevel@tonic-gate */ 1015*0Sstevel@tonic-gate static void 1016*0Sstevel@tonic-gate icmp_addr_req(queue_t *q, mblk_t *mp) 1017*0Sstevel@tonic-gate { 1018*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 1019*0Sstevel@tonic-gate mblk_t *ackmp; 1020*0Sstevel@tonic-gate struct T_addr_ack *taa; 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate /* Make it large enough for worst case */ 1023*0Sstevel@tonic-gate ackmp = reallocb(mp, sizeof (struct T_addr_ack) + 1024*0Sstevel@tonic-gate 2 * sizeof (sin6_t), 1); 1025*0Sstevel@tonic-gate if (ackmp == NULL) { 1026*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOMEM); 1027*0Sstevel@tonic-gate return; 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate taa = (struct T_addr_ack *)ackmp->b_rptr; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate bzero(taa, sizeof (struct T_addr_ack)); 1032*0Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&taa[1]; 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate taa->PRIM_type = T_ADDR_ACK; 1035*0Sstevel@tonic-gate ackmp->b_datap->db_type = M_PCPROTO; 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate /* 1038*0Sstevel@tonic-gate * Note: Following code assumes 32 bit alignment of basic 1039*0Sstevel@tonic-gate * data structures like sin_t and struct T_addr_ack. 1040*0Sstevel@tonic-gate */ 1041*0Sstevel@tonic-gate if (icmp->icmp_state != TS_UNBND) { 1042*0Sstevel@tonic-gate /* 1043*0Sstevel@tonic-gate * Fill in local address 1044*0Sstevel@tonic-gate */ 1045*0Sstevel@tonic-gate taa->LOCADDR_offset = sizeof (*taa); 1046*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 1047*0Sstevel@tonic-gate sin_t *sin; 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate taa->LOCADDR_length = sizeof (sin_t); 1050*0Sstevel@tonic-gate sin = (sin_t *)&taa[1]; 1051*0Sstevel@tonic-gate /* Fill zeroes and then intialize non-zero fields */ 1052*0Sstevel@tonic-gate *sin = sin_null; 1053*0Sstevel@tonic-gate sin->sin_family = AF_INET; 1054*0Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&icmp->icmp_v6src) && 1055*0Sstevel@tonic-gate !IN6_IS_ADDR_UNSPECIFIED(&icmp->icmp_v6src)) { 1056*0Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&icmp->icmp_v6src, 1057*0Sstevel@tonic-gate sin->sin_addr.s_addr); 1058*0Sstevel@tonic-gate } else { 1059*0Sstevel@tonic-gate /* 1060*0Sstevel@tonic-gate * INADDR_ANY 1061*0Sstevel@tonic-gate * icmp_v6src is not set, we might be bound to 1062*0Sstevel@tonic-gate * broadcast/multicast. Use icmp_bound_v6src as 1063*0Sstevel@tonic-gate * local address instead (that could 1064*0Sstevel@tonic-gate * also still be INADDR_ANY) 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&icmp->icmp_bound_v6src, 1067*0Sstevel@tonic-gate sin->sin_addr.s_addr); 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin[1]; 1070*0Sstevel@tonic-gate } else { 1071*0Sstevel@tonic-gate sin6_t *sin6; 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 1074*0Sstevel@tonic-gate taa->LOCADDR_length = sizeof (sin6_t); 1075*0Sstevel@tonic-gate sin6 = (sin6_t *)&taa[1]; 1076*0Sstevel@tonic-gate /* Fill zeroes and then intialize non-zero fields */ 1077*0Sstevel@tonic-gate *sin6 = sin6_null; 1078*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1079*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&icmp->icmp_v6src)) { 1080*0Sstevel@tonic-gate sin6->sin6_addr = icmp->icmp_v6src; 1081*0Sstevel@tonic-gate } else { 1082*0Sstevel@tonic-gate /* 1083*0Sstevel@tonic-gate * UNSPECIFIED 1084*0Sstevel@tonic-gate * icmp_v6src is not set, we might be bound to 1085*0Sstevel@tonic-gate * broadcast/multicast. Use icmp_bound_v6src as 1086*0Sstevel@tonic-gate * local address instead (that could 1087*0Sstevel@tonic-gate * also still be UNSPECIFIED) 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate sin6->sin6_addr = icmp->icmp_bound_v6src; 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin6[1]; 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate ASSERT(ackmp->b_wptr <= ackmp->b_datap->db_lim); 1095*0Sstevel@tonic-gate qreply(q, ackmp); 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate static void 1099*0Sstevel@tonic-gate icmp_copy_info(struct T_info_ack *tap, icmp_t *icmp) 1100*0Sstevel@tonic-gate { 1101*0Sstevel@tonic-gate *tap = icmp_g_t_info_ack; 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) 1104*0Sstevel@tonic-gate tap->ADDR_size = sizeof (sin6_t); 1105*0Sstevel@tonic-gate else 1106*0Sstevel@tonic-gate tap->ADDR_size = sizeof (sin_t); 1107*0Sstevel@tonic-gate tap->CURRENT_state = icmp->icmp_state; 1108*0Sstevel@tonic-gate tap->OPT_size = icmp_max_optsize; 1109*0Sstevel@tonic-gate } 1110*0Sstevel@tonic-gate 1111*0Sstevel@tonic-gate /* 1112*0Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 1113*0Sstevel@tonic-gate * icmp_wput. Much of the T_CAPABILITY_ACK information is copied from 1114*0Sstevel@tonic-gate * icmp_g_t_info_ack. The current state of the stream is copied from 1115*0Sstevel@tonic-gate * icmp_state. 1116*0Sstevel@tonic-gate */ 1117*0Sstevel@tonic-gate static void 1118*0Sstevel@tonic-gate icmp_capability_req(queue_t *q, mblk_t *mp) 1119*0Sstevel@tonic-gate { 1120*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 1121*0Sstevel@tonic-gate t_uscalar_t cap_bits1; 1122*0Sstevel@tonic-gate struct T_capability_ack *tcap; 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 1127*0Sstevel@tonic-gate mp->b_datap->db_type, T_CAPABILITY_ACK); 1128*0Sstevel@tonic-gate if (!mp) 1129*0Sstevel@tonic-gate return; 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 1132*0Sstevel@tonic-gate tcap->CAP_bits1 = 0; 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 1135*0Sstevel@tonic-gate icmp_copy_info(&tcap->INFO_ack, icmp); 1136*0Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 1137*0Sstevel@tonic-gate } 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate qreply(q, mp); 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate /* 1143*0Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by icmp_wput. 1144*0Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from icmp_g_t_info_ack. 1145*0Sstevel@tonic-gate * The current state of the stream is copied from icmp_state. 1146*0Sstevel@tonic-gate */ 1147*0Sstevel@tonic-gate static void 1148*0Sstevel@tonic-gate icmp_info_req(queue_t *q, mblk_t *mp) 1149*0Sstevel@tonic-gate { 1150*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 1153*0Sstevel@tonic-gate T_INFO_ACK); 1154*0Sstevel@tonic-gate if (!mp) 1155*0Sstevel@tonic-gate return; 1156*0Sstevel@tonic-gate icmp_copy_info((struct T_info_ack *)mp->b_rptr, icmp); 1157*0Sstevel@tonic-gate qreply(q, mp); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate /* 1161*0Sstevel@tonic-gate * IP recognizes seven kinds of bind requests: 1162*0Sstevel@tonic-gate * 1163*0Sstevel@tonic-gate * - A zero-length address binds only to the protocol number. 1164*0Sstevel@tonic-gate * 1165*0Sstevel@tonic-gate * - A 4-byte address is treated as a request to 1166*0Sstevel@tonic-gate * validate that the address is a valid local IPv4 1167*0Sstevel@tonic-gate * address, appropriate for an application to bind to. 1168*0Sstevel@tonic-gate * IP does the verification, but does not make any note 1169*0Sstevel@tonic-gate * of the address at this time. 1170*0Sstevel@tonic-gate * 1171*0Sstevel@tonic-gate * - A 16-byte address contains is treated as a request 1172*0Sstevel@tonic-gate * to validate a local IPv6 address, as the 4-byte 1173*0Sstevel@tonic-gate * address case above. 1174*0Sstevel@tonic-gate * 1175*0Sstevel@tonic-gate * - A 16-byte sockaddr_in to validate the local IPv4 address and also 1176*0Sstevel@tonic-gate * use it for the inbound fanout of packets. 1177*0Sstevel@tonic-gate * 1178*0Sstevel@tonic-gate * - A 24-byte sockaddr_in6 to validate the local IPv6 address and also 1179*0Sstevel@tonic-gate * use it for the inbound fanout of packets. 1180*0Sstevel@tonic-gate * 1181*0Sstevel@tonic-gate * - A 12-byte address (ipa_conn_t) containing complete IPv4 fanout 1182*0Sstevel@tonic-gate * information consisting of local and remote addresses 1183*0Sstevel@tonic-gate * and ports (unused for raw sockets). In this case, the addresses are both 1184*0Sstevel@tonic-gate * validated as appropriate for this operation, and, if 1185*0Sstevel@tonic-gate * so, the information is retained for use in the 1186*0Sstevel@tonic-gate * inbound fanout. 1187*0Sstevel@tonic-gate * 1188*0Sstevel@tonic-gate * - A 36-byte address address (ipa6_conn_t) containing complete IPv6 1189*0Sstevel@tonic-gate * fanout information, like the 12-byte case above. 1190*0Sstevel@tonic-gate * 1191*0Sstevel@tonic-gate * IP will also fill in the IRE request mblk with information 1192*0Sstevel@tonic-gate * regarding our peer. In all cases, we notify IP of our protocol 1193*0Sstevel@tonic-gate * type by appending a single protocol byte to the bind request. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate static mblk_t * 1196*0Sstevel@tonic-gate icmp_ip_bind_mp(icmp_t *icmp, t_scalar_t bind_prim, t_scalar_t addr_length, 1197*0Sstevel@tonic-gate in_port_t fport) 1198*0Sstevel@tonic-gate { 1199*0Sstevel@tonic-gate char *cp; 1200*0Sstevel@tonic-gate mblk_t *mp; 1201*0Sstevel@tonic-gate struct T_bind_req *tbr; 1202*0Sstevel@tonic-gate ipa_conn_t *ac; 1203*0Sstevel@tonic-gate ipa6_conn_t *ac6; 1204*0Sstevel@tonic-gate sin_t *sin; 1205*0Sstevel@tonic-gate sin6_t *sin6; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate ASSERT(bind_prim == O_T_BIND_REQ || bind_prim == T_BIND_REQ); 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate mp = allocb(sizeof (*tbr) + addr_length + 1, BPRI_HI); 1210*0Sstevel@tonic-gate if (mp == NULL) 1211*0Sstevel@tonic-gate return (NULL); 1212*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1213*0Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 1214*0Sstevel@tonic-gate tbr->PRIM_type = bind_prim; 1215*0Sstevel@tonic-gate tbr->ADDR_offset = sizeof (*tbr); 1216*0Sstevel@tonic-gate tbr->CONIND_number = 0; 1217*0Sstevel@tonic-gate tbr->ADDR_length = addr_length; 1218*0Sstevel@tonic-gate cp = (char *)&tbr[1]; 1219*0Sstevel@tonic-gate switch (addr_length) { 1220*0Sstevel@tonic-gate case sizeof (ipa_conn_t): 1221*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET); 1222*0Sstevel@tonic-gate /* Append a request for an IRE */ 1223*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 1224*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1225*0Sstevel@tonic-gate freemsg(mp); 1226*0Sstevel@tonic-gate return (NULL); 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 1229*0Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate /* cp known to be 32 bit aligned */ 1232*0Sstevel@tonic-gate ac = (ipa_conn_t *)cp; 1233*0Sstevel@tonic-gate ac->ac_laddr = V4_PART_OF_V6(icmp->icmp_v6src); 1234*0Sstevel@tonic-gate ac->ac_faddr = V4_PART_OF_V6(icmp->icmp_v6dst); 1235*0Sstevel@tonic-gate ac->ac_fport = fport; 1236*0Sstevel@tonic-gate ac->ac_lport = 0; 1237*0Sstevel@tonic-gate break; 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate case sizeof (ipa6_conn_t): 1240*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 1241*0Sstevel@tonic-gate /* Append a request for an IRE */ 1242*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 1243*0Sstevel@tonic-gate if (mp->b_cont == NULL) { 1244*0Sstevel@tonic-gate freemsg(mp); 1245*0Sstevel@tonic-gate return (NULL); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 1248*0Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 1249*0Sstevel@tonic-gate 1250*0Sstevel@tonic-gate /* cp known to be 32 bit aligned */ 1251*0Sstevel@tonic-gate ac6 = (ipa6_conn_t *)cp; 1252*0Sstevel@tonic-gate ac6->ac6_laddr = icmp->icmp_v6src; 1253*0Sstevel@tonic-gate ac6->ac6_faddr = icmp->icmp_v6dst; 1254*0Sstevel@tonic-gate ac6->ac6_fport = fport; 1255*0Sstevel@tonic-gate ac6->ac6_lport = 0; 1256*0Sstevel@tonic-gate break; 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate case sizeof (sin_t): 1259*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET); 1260*0Sstevel@tonic-gate /* Append a request for an IRE */ 1261*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 1262*0Sstevel@tonic-gate if (!mp->b_cont) { 1263*0Sstevel@tonic-gate freemsg(mp); 1264*0Sstevel@tonic-gate return (NULL); 1265*0Sstevel@tonic-gate } 1266*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 1267*0Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate sin = (sin_t *)cp; 1270*0Sstevel@tonic-gate *sin = sin_null; 1271*0Sstevel@tonic-gate sin->sin_family = AF_INET; 1272*0Sstevel@tonic-gate sin->sin_addr.s_addr = V4_PART_OF_V6(icmp->icmp_bound_v6src); 1273*0Sstevel@tonic-gate break; 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate case sizeof (sin6_t): 1276*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 1277*0Sstevel@tonic-gate /* Append a request for an IRE */ 1278*0Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 1279*0Sstevel@tonic-gate if (!mp->b_cont) { 1280*0Sstevel@tonic-gate freemsg(mp); 1281*0Sstevel@tonic-gate return (NULL); 1282*0Sstevel@tonic-gate } 1283*0Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 1284*0Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate sin6 = (sin6_t *)cp; 1287*0Sstevel@tonic-gate *sin6 = sin6_null; 1288*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1289*0Sstevel@tonic-gate sin6->sin6_addr = icmp->icmp_bound_v6src; 1290*0Sstevel@tonic-gate break; 1291*0Sstevel@tonic-gate } 1292*0Sstevel@tonic-gate /* Add protocol number to end */ 1293*0Sstevel@tonic-gate cp[addr_length] = icmp->icmp_proto; 1294*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&cp[addr_length + 1]; 1295*0Sstevel@tonic-gate return (mp); 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate /* 1299*0Sstevel@tonic-gate * This is the open routine for icmp. It allocates a icmp_t structure for 1300*0Sstevel@tonic-gate * the stream and, on the first open of the module, creates an ND table. 1301*0Sstevel@tonic-gate */ 1302*0Sstevel@tonic-gate static int 1303*0Sstevel@tonic-gate icmp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 1304*0Sstevel@tonic-gate { 1305*0Sstevel@tonic-gate int err; 1306*0Sstevel@tonic-gate icmp_t *icmp; 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate /* If the stream is already open, return immediately. */ 1309*0Sstevel@tonic-gate if (q->q_ptr != NULL) 1310*0Sstevel@tonic-gate return (0); 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate /* If this is not a push of icmp as a module, fail. */ 1313*0Sstevel@tonic-gate if (sflag != MODOPEN) 1314*0Sstevel@tonic-gate return (EINVAL); 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate /* 1317*0Sstevel@tonic-gate * Defer the qprocson until everything is initialized since 1318*0Sstevel@tonic-gate * we are D_MTPERQ and after qprocson the rput routine can 1319*0Sstevel@tonic-gate * run. (Could do qprocson earlier since icmp currently 1320*0Sstevel@tonic-gate * has an outer perimeter.) 1321*0Sstevel@tonic-gate */ 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate /* 1324*0Sstevel@tonic-gate * Create a icmp_t structure for this stream and link into the 1325*0Sstevel@tonic-gate * list of open streams. 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate err = mi_open_comm(&icmp_g_head, sizeof (icmp_t), q, devp, 1328*0Sstevel@tonic-gate flag, sflag, credp); 1329*0Sstevel@tonic-gate if (err) 1330*0Sstevel@tonic-gate return (err); 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate /* 1333*0Sstevel@tonic-gate * The receive hiwat is only looked at on the stream head queue. 1334*0Sstevel@tonic-gate * Store in q_hiwat in order to return on SO_RCVBUF getsockopts. 1335*0Sstevel@tonic-gate */ 1336*0Sstevel@tonic-gate q->q_hiwat = icmp_recv_hiwat; 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate /* Set the initial state of the stream and the privilege status. */ 1339*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 1340*0Sstevel@tonic-gate icmp->icmp_state = TS_UNBND; 1341*0Sstevel@tonic-gate icmp->icmp_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 1342*0Sstevel@tonic-gate icmp->icmp_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 1343*0Sstevel@tonic-gate icmp->icmp_filter = NULL; 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate icmp->icmp_credp = credp; 1346*0Sstevel@tonic-gate crhold(credp); 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate icmp->icmp_zoneid = getzoneid(); 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate if (getmajor(*devp) == (major_t)ICMP6_MAJ) { 1351*0Sstevel@tonic-gate icmp->icmp_ipversion = IPV6_VERSION; 1352*0Sstevel@tonic-gate icmp->icmp_family = AF_INET6; 1353*0Sstevel@tonic-gate /* May be changed by a SO_PROTOTYPE socket option. */ 1354*0Sstevel@tonic-gate icmp->icmp_proto = IPPROTO_ICMPV6; 1355*0Sstevel@tonic-gate icmp->icmp_checksum_off = 2; /* Offset for icmp6_cksum */ 1356*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = IPV6_HDR_LEN; 1357*0Sstevel@tonic-gate icmp->icmp_ttl = (uint8_t)icmp_ipv6_hoplimit; 1358*0Sstevel@tonic-gate } else { 1359*0Sstevel@tonic-gate icmp->icmp_ipversion = IPV4_VERSION; 1360*0Sstevel@tonic-gate icmp->icmp_family = AF_INET; 1361*0Sstevel@tonic-gate /* May be changed by a SO_PROTOTYPE socket option. */ 1362*0Sstevel@tonic-gate icmp->icmp_proto = IPPROTO_ICMP; 1363*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH; 1364*0Sstevel@tonic-gate icmp->icmp_ttl = (uint8_t)icmp_ipv4_ttl; 1365*0Sstevel@tonic-gate } 1366*0Sstevel@tonic-gate qprocson(q); 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate /* 1369*0Sstevel@tonic-gate * Check if icmp is being I_PUSHed by a non-privileged user. 1370*0Sstevel@tonic-gate * If so, we set icmp_restricted to indicate that only MIB 1371*0Sstevel@tonic-gate * traffic may pass. 1372*0Sstevel@tonic-gate */ 1373*0Sstevel@tonic-gate if (secpolicy_net_icmpaccess(credp) != 0) { 1374*0Sstevel@tonic-gate icmp->icmp_restricted = 1; 1375*0Sstevel@tonic-gate } 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate /* 1378*0Sstevel@tonic-gate * The transmit hiwat is only looked at on IP's queue. 1379*0Sstevel@tonic-gate * Store in q_hiwat in order to return on SO_SNDBUF 1380*0Sstevel@tonic-gate * getsockopts. 1381*0Sstevel@tonic-gate */ 1382*0Sstevel@tonic-gate WR(q)->q_hiwat = icmp_xmit_hiwat; 1383*0Sstevel@tonic-gate WR(q)->q_next->q_hiwat = WR(q)->q_hiwat; 1384*0Sstevel@tonic-gate WR(q)->q_lowat = icmp_xmit_lowat; 1385*0Sstevel@tonic-gate WR(q)->q_next->q_lowat = WR(q)->q_lowat; 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) { 1388*0Sstevel@tonic-gate /* Build initial header template for transmit */ 1389*0Sstevel@tonic-gate int error; 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 1392*0Sstevel@tonic-gate if (error != 0) { 1393*0Sstevel@tonic-gate (void) icmp_close(q); 1394*0Sstevel@tonic-gate return (error); 1395*0Sstevel@tonic-gate } 1396*0Sstevel@tonic-gate } 1397*0Sstevel@tonic-gate /* Set the Stream head write offset. */ 1398*0Sstevel@tonic-gate (void) mi_set_sth_wroff(q, icmp->icmp_max_hdr_len + icmp_wroff_extra); 1399*0Sstevel@tonic-gate (void) mi_set_sth_hiwat(q, q->q_hiwat); 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate return (0); 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate /* 1405*0Sstevel@tonic-gate * Which ICMP options OK to set through T_UNITDATA_REQ... 1406*0Sstevel@tonic-gate */ 1407*0Sstevel@tonic-gate /* ARGSUSED */ 1408*0Sstevel@tonic-gate static boolean_t 1409*0Sstevel@tonic-gate icmp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name) 1410*0Sstevel@tonic-gate { 1411*0Sstevel@tonic-gate return (B_TRUE); 1412*0Sstevel@tonic-gate } 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate /* 1415*0Sstevel@tonic-gate * This routine gets default values of certain options whose default 1416*0Sstevel@tonic-gate * values are maintained by protcol specific code 1417*0Sstevel@tonic-gate */ 1418*0Sstevel@tonic-gate /* ARGSUSED */ 1419*0Sstevel@tonic-gate int 1420*0Sstevel@tonic-gate icmp_opt_default(queue_t *q, int level, int name, uchar_t *ptr) 1421*0Sstevel@tonic-gate { 1422*0Sstevel@tonic-gate int *i1 = (int *)ptr; 1423*0Sstevel@tonic-gate 1424*0Sstevel@tonic-gate switch (level) { 1425*0Sstevel@tonic-gate case IPPROTO_IP: 1426*0Sstevel@tonic-gate switch (name) { 1427*0Sstevel@tonic-gate case IP_MULTICAST_TTL: 1428*0Sstevel@tonic-gate *ptr = (uchar_t)IP_DEFAULT_MULTICAST_TTL; 1429*0Sstevel@tonic-gate return (sizeof (uchar_t)); 1430*0Sstevel@tonic-gate case IP_MULTICAST_LOOP: 1431*0Sstevel@tonic-gate *ptr = (uchar_t)IP_DEFAULT_MULTICAST_LOOP; 1432*0Sstevel@tonic-gate return (sizeof (uchar_t)); 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate break; 1435*0Sstevel@tonic-gate case IPPROTO_IPV6: 1436*0Sstevel@tonic-gate switch (name) { 1437*0Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 1438*0Sstevel@tonic-gate *i1 = IP_DEFAULT_MULTICAST_TTL; 1439*0Sstevel@tonic-gate return (sizeof (int)); 1440*0Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 1441*0Sstevel@tonic-gate *i1 = IP_DEFAULT_MULTICAST_LOOP; 1442*0Sstevel@tonic-gate return (sizeof (int)); 1443*0Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 1444*0Sstevel@tonic-gate *i1 = icmp_ipv6_hoplimit; 1445*0Sstevel@tonic-gate return (sizeof (int)); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate break; 1448*0Sstevel@tonic-gate case IPPROTO_ICMPV6: 1449*0Sstevel@tonic-gate switch (name) { 1450*0Sstevel@tonic-gate case ICMP6_FILTER: 1451*0Sstevel@tonic-gate /* Make it look like "pass all" */ 1452*0Sstevel@tonic-gate ICMP6_FILTER_SETPASSALL((icmp6_filter_t *)ptr); 1453*0Sstevel@tonic-gate return (sizeof (icmp6_filter_t)); 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate break; 1456*0Sstevel@tonic-gate } 1457*0Sstevel@tonic-gate return (-1); 1458*0Sstevel@tonic-gate } 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate /* 1461*0Sstevel@tonic-gate * This routine retrieves the current status of socket options. 1462*0Sstevel@tonic-gate * It returns the size of the option retrieved. 1463*0Sstevel@tonic-gate */ 1464*0Sstevel@tonic-gate int 1465*0Sstevel@tonic-gate icmp_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 1466*0Sstevel@tonic-gate { 1467*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 1468*0Sstevel@tonic-gate int *i1 = (int *)ptr; 1469*0Sstevel@tonic-gate ip6_pkt_t *ipp = &icmp->icmp_sticky_ipp; 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate switch (level) { 1472*0Sstevel@tonic-gate case SOL_SOCKET: 1473*0Sstevel@tonic-gate switch (name) { 1474*0Sstevel@tonic-gate case SO_DEBUG: 1475*0Sstevel@tonic-gate *i1 = icmp->icmp_debug; 1476*0Sstevel@tonic-gate break; 1477*0Sstevel@tonic-gate case SO_TYPE: 1478*0Sstevel@tonic-gate *i1 = SOCK_RAW; 1479*0Sstevel@tonic-gate break; 1480*0Sstevel@tonic-gate case SO_PROTOTYPE: 1481*0Sstevel@tonic-gate *i1 = icmp->icmp_proto; 1482*0Sstevel@tonic-gate break; 1483*0Sstevel@tonic-gate case SO_REUSEADDR: 1484*0Sstevel@tonic-gate *i1 = icmp->icmp_reuseaddr; 1485*0Sstevel@tonic-gate break; 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate /* 1488*0Sstevel@tonic-gate * The following three items are available here, 1489*0Sstevel@tonic-gate * but are only meaningful to IP. 1490*0Sstevel@tonic-gate */ 1491*0Sstevel@tonic-gate case SO_DONTROUTE: 1492*0Sstevel@tonic-gate *i1 = icmp->icmp_dontroute; 1493*0Sstevel@tonic-gate break; 1494*0Sstevel@tonic-gate case SO_USELOOPBACK: 1495*0Sstevel@tonic-gate *i1 = icmp->icmp_useloopback; 1496*0Sstevel@tonic-gate break; 1497*0Sstevel@tonic-gate case SO_BROADCAST: 1498*0Sstevel@tonic-gate *i1 = icmp->icmp_broadcast; 1499*0Sstevel@tonic-gate break; 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate case SO_SNDBUF: 1502*0Sstevel@tonic-gate ASSERT(q->q_hiwat <= INT_MAX); 1503*0Sstevel@tonic-gate *i1 = (int)q->q_hiwat; 1504*0Sstevel@tonic-gate break; 1505*0Sstevel@tonic-gate case SO_RCVBUF: 1506*0Sstevel@tonic-gate ASSERT(RD(q)->q_hiwat <= INT_MAX); 1507*0Sstevel@tonic-gate *i1 = (int)RD(q)->q_hiwat; 1508*0Sstevel@tonic-gate break; 1509*0Sstevel@tonic-gate case SO_DGRAM_ERRIND: 1510*0Sstevel@tonic-gate *i1 = icmp->icmp_dgram_errind; 1511*0Sstevel@tonic-gate break; 1512*0Sstevel@tonic-gate /* 1513*0Sstevel@tonic-gate * Following three not meaningful for icmp 1514*0Sstevel@tonic-gate * Action is same as "default" to which we fallthrough 1515*0Sstevel@tonic-gate * so we keep them in comments. 1516*0Sstevel@tonic-gate * case SO_LINGER: 1517*0Sstevel@tonic-gate * case SO_KEEPALIVE: 1518*0Sstevel@tonic-gate * case SO_OOBINLINE: 1519*0Sstevel@tonic-gate */ 1520*0Sstevel@tonic-gate default: 1521*0Sstevel@tonic-gate return (-1); 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate break; 1524*0Sstevel@tonic-gate case IPPROTO_IP: 1525*0Sstevel@tonic-gate /* 1526*0Sstevel@tonic-gate * Only allow IPv4 option processing on IPv4 sockets. 1527*0Sstevel@tonic-gate */ 1528*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET) 1529*0Sstevel@tonic-gate return (-1); 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate switch (name) { 1532*0Sstevel@tonic-gate case IP_OPTIONS: 1533*0Sstevel@tonic-gate case T_IP_OPTIONS: 1534*0Sstevel@tonic-gate /* Options are passed up with each packet */ 1535*0Sstevel@tonic-gate return (0); 1536*0Sstevel@tonic-gate case IP_HDRINCL: 1537*0Sstevel@tonic-gate *i1 = (int)icmp->icmp_hdrincl; 1538*0Sstevel@tonic-gate break; 1539*0Sstevel@tonic-gate case IP_TOS: 1540*0Sstevel@tonic-gate case T_IP_TOS: 1541*0Sstevel@tonic-gate *i1 = (int)icmp->icmp_type_of_service; 1542*0Sstevel@tonic-gate break; 1543*0Sstevel@tonic-gate case IP_TTL: 1544*0Sstevel@tonic-gate *i1 = (int)icmp->icmp_ttl; 1545*0Sstevel@tonic-gate break; 1546*0Sstevel@tonic-gate case IP_MULTICAST_IF: 1547*0Sstevel@tonic-gate /* 0 address if not set */ 1548*0Sstevel@tonic-gate *(ipaddr_t *)ptr = icmp->icmp_multicast_if_addr; 1549*0Sstevel@tonic-gate return (sizeof (ipaddr_t)); 1550*0Sstevel@tonic-gate case IP_MULTICAST_TTL: 1551*0Sstevel@tonic-gate *(uchar_t *)ptr = icmp->icmp_multicast_ttl; 1552*0Sstevel@tonic-gate return (sizeof (uchar_t)); 1553*0Sstevel@tonic-gate case IP_MULTICAST_LOOP: 1554*0Sstevel@tonic-gate *ptr = icmp->icmp_multicast_loop; 1555*0Sstevel@tonic-gate return (sizeof (uint8_t)); 1556*0Sstevel@tonic-gate case IP_BOUND_IF: 1557*0Sstevel@tonic-gate /* Zero if not set */ 1558*0Sstevel@tonic-gate *i1 = icmp->icmp_bound_if; 1559*0Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 1560*0Sstevel@tonic-gate case IP_UNSPEC_SRC: 1561*0Sstevel@tonic-gate *ptr = icmp->icmp_unspec_source; 1562*0Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 1563*0Sstevel@tonic-gate case IP_XMIT_IF: 1564*0Sstevel@tonic-gate *i1 = icmp->icmp_xmit_if; 1565*0Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 1566*0Sstevel@tonic-gate case IP_RECVIF: 1567*0Sstevel@tonic-gate *ptr = icmp->icmp_recvif; 1568*0Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 1569*0Sstevel@tonic-gate /* 1570*0Sstevel@tonic-gate * Cannot "get" the value of following options 1571*0Sstevel@tonic-gate * at this level. Action is same as "default" to 1572*0Sstevel@tonic-gate * which we fallthrough so we keep them in comments. 1573*0Sstevel@tonic-gate * 1574*0Sstevel@tonic-gate * case IP_ADD_MEMBERSHIP: 1575*0Sstevel@tonic-gate * case IP_DROP_MEMBERSHIP: 1576*0Sstevel@tonic-gate * case IP_BLOCK_SOURCE: 1577*0Sstevel@tonic-gate * case IP_UNBLOCK_SOURCE: 1578*0Sstevel@tonic-gate * case IP_ADD_SOURCE_MEMBERSHIP: 1579*0Sstevel@tonic-gate * case IP_DROP_SOURCE_MEMBERSHIP: 1580*0Sstevel@tonic-gate * case MCAST_JOIN_GROUP: 1581*0Sstevel@tonic-gate * case MCAST_LEAVE_GROUP: 1582*0Sstevel@tonic-gate * case MCAST_BLOCK_SOURCE: 1583*0Sstevel@tonic-gate * case MCAST_UNBLOCK_SOURCE: 1584*0Sstevel@tonic-gate * case MCAST_JOIN_SOURCE_GROUP: 1585*0Sstevel@tonic-gate * case MCAST_LEAVE_SOURCE_GROUP: 1586*0Sstevel@tonic-gate * case MRT_INIT: 1587*0Sstevel@tonic-gate * case MRT_DONE: 1588*0Sstevel@tonic-gate * case MRT_ADD_VIF: 1589*0Sstevel@tonic-gate * case MRT_DEL_VIF: 1590*0Sstevel@tonic-gate * case MRT_ADD_MFC: 1591*0Sstevel@tonic-gate * case MRT_DEL_MFC: 1592*0Sstevel@tonic-gate * case MRT_VERSION: 1593*0Sstevel@tonic-gate * case MRT_ASSERT: 1594*0Sstevel@tonic-gate * case IP_SEC_OPT: 1595*0Sstevel@tonic-gate * case IP_DONTFAILOVER_IF: 1596*0Sstevel@tonic-gate */ 1597*0Sstevel@tonic-gate default: 1598*0Sstevel@tonic-gate return (-1); 1599*0Sstevel@tonic-gate } 1600*0Sstevel@tonic-gate break; 1601*0Sstevel@tonic-gate case IPPROTO_IPV6: 1602*0Sstevel@tonic-gate /* 1603*0Sstevel@tonic-gate * Only allow IPv6 option processing on native IPv6 sockets. 1604*0Sstevel@tonic-gate */ 1605*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6) 1606*0Sstevel@tonic-gate return (-1); 1607*0Sstevel@tonic-gate switch (name) { 1608*0Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 1609*0Sstevel@tonic-gate *i1 = (unsigned int)icmp->icmp_ttl; 1610*0Sstevel@tonic-gate break; 1611*0Sstevel@tonic-gate case IPV6_MULTICAST_IF: 1612*0Sstevel@tonic-gate /* 0 index if not set */ 1613*0Sstevel@tonic-gate *i1 = icmp->icmp_multicast_if_index; 1614*0Sstevel@tonic-gate break; 1615*0Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 1616*0Sstevel@tonic-gate *i1 = icmp->icmp_multicast_ttl; 1617*0Sstevel@tonic-gate break; 1618*0Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 1619*0Sstevel@tonic-gate *i1 = icmp->icmp_multicast_loop; 1620*0Sstevel@tonic-gate break; 1621*0Sstevel@tonic-gate case IPV6_BOUND_IF: 1622*0Sstevel@tonic-gate /* Zero if not set */ 1623*0Sstevel@tonic-gate *i1 = icmp->icmp_bound_if; 1624*0Sstevel@tonic-gate break; 1625*0Sstevel@tonic-gate case IPV6_UNSPEC_SRC: 1626*0Sstevel@tonic-gate *i1 = icmp->icmp_unspec_source; 1627*0Sstevel@tonic-gate break; 1628*0Sstevel@tonic-gate case IPV6_CHECKSUM: 1629*0Sstevel@tonic-gate /* 1630*0Sstevel@tonic-gate * Return offset or -1 if no checksum offset. 1631*0Sstevel@tonic-gate * Does not apply to IPPROTO_ICMPV6 1632*0Sstevel@tonic-gate */ 1633*0Sstevel@tonic-gate if (icmp->icmp_proto == IPPROTO_ICMPV6) 1634*0Sstevel@tonic-gate return (-1); 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gate if (icmp->icmp_raw_checksum) { 1637*0Sstevel@tonic-gate *i1 = icmp->icmp_checksum_off; 1638*0Sstevel@tonic-gate } else { 1639*0Sstevel@tonic-gate *i1 = -1; 1640*0Sstevel@tonic-gate } 1641*0Sstevel@tonic-gate break; 1642*0Sstevel@tonic-gate case IPV6_JOIN_GROUP: 1643*0Sstevel@tonic-gate case IPV6_LEAVE_GROUP: 1644*0Sstevel@tonic-gate case MCAST_JOIN_GROUP: 1645*0Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 1646*0Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 1647*0Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 1648*0Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 1649*0Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 1650*0Sstevel@tonic-gate /* cannot "get" the value for these */ 1651*0Sstevel@tonic-gate return (-1); 1652*0Sstevel@tonic-gate case IPV6_RECVPKTINFO: 1653*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvpktinfo; 1654*0Sstevel@tonic-gate break; 1655*0Sstevel@tonic-gate case IPV6_RECVTCLASS: 1656*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvtclass; 1657*0Sstevel@tonic-gate break; 1658*0Sstevel@tonic-gate case IPV6_RECVPATHMTU: 1659*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvpathmtu; 1660*0Sstevel@tonic-gate break; 1661*0Sstevel@tonic-gate case IPV6_V6ONLY: 1662*0Sstevel@tonic-gate *i1 = 1; 1663*0Sstevel@tonic-gate break; 1664*0Sstevel@tonic-gate case IPV6_RECVHOPLIMIT: 1665*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvhoplimit; 1666*0Sstevel@tonic-gate break; 1667*0Sstevel@tonic-gate case IPV6_RECVHOPOPTS: 1668*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvhopopts; 1669*0Sstevel@tonic-gate break; 1670*0Sstevel@tonic-gate case IPV6_RECVDSTOPTS: 1671*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvdstopts; 1672*0Sstevel@tonic-gate break; 1673*0Sstevel@tonic-gate case _OLD_IPV6_RECVDSTOPTS: 1674*0Sstevel@tonic-gate *i1 = icmp->icmp_old_ipv6_recvdstopts; 1675*0Sstevel@tonic-gate break; 1676*0Sstevel@tonic-gate case IPV6_RECVRTHDRDSTOPTS: 1677*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvrtdstopts; 1678*0Sstevel@tonic-gate break; 1679*0Sstevel@tonic-gate case IPV6_RECVRTHDR: 1680*0Sstevel@tonic-gate *i1 = icmp->icmp_ipv6_recvrthdr; 1681*0Sstevel@tonic-gate break; 1682*0Sstevel@tonic-gate case IPV6_PKTINFO: { 1683*0Sstevel@tonic-gate /* XXX assumes that caller has room for max size! */ 1684*0Sstevel@tonic-gate struct in6_pktinfo *pkti; 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate pkti = (struct in6_pktinfo *)ptr; 1687*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_IFINDEX) 1688*0Sstevel@tonic-gate pkti->ipi6_ifindex = ipp->ipp_ifindex; 1689*0Sstevel@tonic-gate else 1690*0Sstevel@tonic-gate pkti->ipi6_ifindex = 0; 1691*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_ADDR) 1692*0Sstevel@tonic-gate pkti->ipi6_addr = ipp->ipp_addr; 1693*0Sstevel@tonic-gate else 1694*0Sstevel@tonic-gate pkti->ipi6_addr = ipv6_all_zeros; 1695*0Sstevel@tonic-gate return (sizeof (struct in6_pktinfo)); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate case IPV6_HOPLIMIT: 1698*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HOPLIMIT) 1699*0Sstevel@tonic-gate *i1 = ipp->ipp_hoplimit; 1700*0Sstevel@tonic-gate else 1701*0Sstevel@tonic-gate *i1 = -1; /* Not set */ 1702*0Sstevel@tonic-gate break; 1703*0Sstevel@tonic-gate case IPV6_NEXTHOP: { 1704*0Sstevel@tonic-gate sin6_t *sin6 = (sin6_t *)ptr; 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_NEXTHOP)) 1707*0Sstevel@tonic-gate return (0); 1708*0Sstevel@tonic-gate *sin6 = sin6_null; 1709*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1710*0Sstevel@tonic-gate sin6->sin6_addr = ipp->ipp_nexthop; 1711*0Sstevel@tonic-gate return (sizeof (sin6_t)); 1712*0Sstevel@tonic-gate } 1713*0Sstevel@tonic-gate case IPV6_HOPOPTS: 1714*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_HOPOPTS)) 1715*0Sstevel@tonic-gate return (0); 1716*0Sstevel@tonic-gate bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen); 1717*0Sstevel@tonic-gate return (ipp->ipp_hopoptslen); 1718*0Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: 1719*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_RTDSTOPTS)) 1720*0Sstevel@tonic-gate return (0); 1721*0Sstevel@tonic-gate bcopy(ipp->ipp_rtdstopts, ptr, ipp->ipp_rtdstoptslen); 1722*0Sstevel@tonic-gate return (ipp->ipp_rtdstoptslen); 1723*0Sstevel@tonic-gate case IPV6_RTHDR: 1724*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_RTHDR)) 1725*0Sstevel@tonic-gate return (0); 1726*0Sstevel@tonic-gate bcopy(ipp->ipp_rthdr, ptr, ipp->ipp_rthdrlen); 1727*0Sstevel@tonic-gate return (ipp->ipp_rthdrlen); 1728*0Sstevel@tonic-gate case IPV6_DSTOPTS: 1729*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_DSTOPTS)) 1730*0Sstevel@tonic-gate return (0); 1731*0Sstevel@tonic-gate bcopy(ipp->ipp_dstopts, ptr, ipp->ipp_dstoptslen); 1732*0Sstevel@tonic-gate return (ipp->ipp_dstoptslen); 1733*0Sstevel@tonic-gate case IPV6_PATHMTU: 1734*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_PATHMTU)) 1735*0Sstevel@tonic-gate return (0); 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate return (ip_fill_mtuinfo(&icmp->icmp_v6dst, 0, 1738*0Sstevel@tonic-gate (struct ip6_mtuinfo *)ptr)); 1739*0Sstevel@tonic-gate case IPV6_TCLASS: 1740*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_TCLASS) 1741*0Sstevel@tonic-gate *i1 = ipp->ipp_tclass; 1742*0Sstevel@tonic-gate else 1743*0Sstevel@tonic-gate *i1 = IPV6_FLOW_TCLASS( 1744*0Sstevel@tonic-gate IPV6_DEFAULT_VERS_AND_FLOW); 1745*0Sstevel@tonic-gate break; 1746*0Sstevel@tonic-gate default: 1747*0Sstevel@tonic-gate return (-1); 1748*0Sstevel@tonic-gate } 1749*0Sstevel@tonic-gate break; 1750*0Sstevel@tonic-gate case IPPROTO_ICMPV6: 1751*0Sstevel@tonic-gate /* 1752*0Sstevel@tonic-gate * Only allow IPv6 option processing on native IPv6 sockets. 1753*0Sstevel@tonic-gate */ 1754*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6) 1755*0Sstevel@tonic-gate return (-1); 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate if (icmp->icmp_proto != IPPROTO_ICMPV6) 1758*0Sstevel@tonic-gate return (-1); 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate switch (name) { 1761*0Sstevel@tonic-gate case ICMP6_FILTER: 1762*0Sstevel@tonic-gate if (icmp->icmp_filter == NULL) { 1763*0Sstevel@tonic-gate /* Make it look like "pass all" */ 1764*0Sstevel@tonic-gate ICMP6_FILTER_SETPASSALL((icmp6_filter_t *)ptr); 1765*0Sstevel@tonic-gate } else { 1766*0Sstevel@tonic-gate (void) bcopy(icmp->icmp_filter, ptr, 1767*0Sstevel@tonic-gate sizeof (icmp6_filter_t)); 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate return (sizeof (icmp6_filter_t)); 1770*0Sstevel@tonic-gate default: 1771*0Sstevel@tonic-gate return (-1); 1772*0Sstevel@tonic-gate } 1773*0Sstevel@tonic-gate default: 1774*0Sstevel@tonic-gate return (-1); 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate return (sizeof (int)); 1777*0Sstevel@tonic-gate } 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate /* This routine sets socket options. */ 1780*0Sstevel@tonic-gate /* ARGSUSED */ 1781*0Sstevel@tonic-gate int 1782*0Sstevel@tonic-gate icmp_opt_set(queue_t *q, uint_t optset_context, int level, int name, 1783*0Sstevel@tonic-gate uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 1784*0Sstevel@tonic-gate void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 1785*0Sstevel@tonic-gate { 1786*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 1787*0Sstevel@tonic-gate int *i1 = (int *)invalp; 1788*0Sstevel@tonic-gate boolean_t onoff = (*i1 == 0) ? 0 : 1; 1789*0Sstevel@tonic-gate boolean_t checkonly; 1790*0Sstevel@tonic-gate int error; 1791*0Sstevel@tonic-gate 1792*0Sstevel@tonic-gate switch (optset_context) { 1793*0Sstevel@tonic-gate case SETFN_OPTCOM_CHECKONLY: 1794*0Sstevel@tonic-gate checkonly = B_TRUE; 1795*0Sstevel@tonic-gate /* 1796*0Sstevel@tonic-gate * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 1797*0Sstevel@tonic-gate * inlen != 0 implies value supplied and 1798*0Sstevel@tonic-gate * we have to "pretend" to set it. 1799*0Sstevel@tonic-gate * inlen == 0 implies that there is no 1800*0Sstevel@tonic-gate * value part in T_CHECK request and just validation 1801*0Sstevel@tonic-gate * done elsewhere should be enough, we just return here. 1802*0Sstevel@tonic-gate */ 1803*0Sstevel@tonic-gate if (inlen == 0) { 1804*0Sstevel@tonic-gate *outlenp = 0; 1805*0Sstevel@tonic-gate return (0); 1806*0Sstevel@tonic-gate } 1807*0Sstevel@tonic-gate break; 1808*0Sstevel@tonic-gate case SETFN_OPTCOM_NEGOTIATE: 1809*0Sstevel@tonic-gate checkonly = B_FALSE; 1810*0Sstevel@tonic-gate break; 1811*0Sstevel@tonic-gate case SETFN_UD_NEGOTIATE: 1812*0Sstevel@tonic-gate case SETFN_CONN_NEGOTIATE: 1813*0Sstevel@tonic-gate checkonly = B_FALSE; 1814*0Sstevel@tonic-gate /* 1815*0Sstevel@tonic-gate * Negotiating local and "association-related" options 1816*0Sstevel@tonic-gate * through T_UNITDATA_REQ. 1817*0Sstevel@tonic-gate * 1818*0Sstevel@tonic-gate * Following routine can filter out ones we do not 1819*0Sstevel@tonic-gate * want to be "set" this way. 1820*0Sstevel@tonic-gate */ 1821*0Sstevel@tonic-gate if (!icmp_opt_allow_udr_set(level, name)) { 1822*0Sstevel@tonic-gate *outlenp = 0; 1823*0Sstevel@tonic-gate return (EINVAL); 1824*0Sstevel@tonic-gate } 1825*0Sstevel@tonic-gate break; 1826*0Sstevel@tonic-gate default: 1827*0Sstevel@tonic-gate /* 1828*0Sstevel@tonic-gate * We should never get here 1829*0Sstevel@tonic-gate */ 1830*0Sstevel@tonic-gate *outlenp = 0; 1831*0Sstevel@tonic-gate return (EINVAL); 1832*0Sstevel@tonic-gate } 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 1835*0Sstevel@tonic-gate (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 1836*0Sstevel@tonic-gate 1837*0Sstevel@tonic-gate /* 1838*0Sstevel@tonic-gate * For fixed length options, no sanity check 1839*0Sstevel@tonic-gate * of passed in length is done. It is assumed *_optcom_req() 1840*0Sstevel@tonic-gate * routines do the right thing. 1841*0Sstevel@tonic-gate */ 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate switch (level) { 1844*0Sstevel@tonic-gate case SOL_SOCKET: 1845*0Sstevel@tonic-gate switch (name) { 1846*0Sstevel@tonic-gate case SO_DEBUG: 1847*0Sstevel@tonic-gate if (!checkonly) 1848*0Sstevel@tonic-gate icmp->icmp_debug = onoff; 1849*0Sstevel@tonic-gate break; 1850*0Sstevel@tonic-gate case SO_PROTOTYPE: 1851*0Sstevel@tonic-gate if ((*i1 & 0xFF) != IPPROTO_ICMP && 1852*0Sstevel@tonic-gate (*i1 & 0xFF) != IPPROTO_ICMPV6 && 1853*0Sstevel@tonic-gate secpolicy_net_rawaccess(cr) != 0) { 1854*0Sstevel@tonic-gate *outlenp = 0; 1855*0Sstevel@tonic-gate return (EACCES); 1856*0Sstevel@tonic-gate } 1857*0Sstevel@tonic-gate /* Can't use IPPROTO_RAW with IPv6 */ 1858*0Sstevel@tonic-gate if ((*i1 & 0xFF) == IPPROTO_RAW && 1859*0Sstevel@tonic-gate icmp->icmp_family == AF_INET6) { 1860*0Sstevel@tonic-gate *outlenp = 0; 1861*0Sstevel@tonic-gate return (EPROTONOSUPPORT); 1862*0Sstevel@tonic-gate } 1863*0Sstevel@tonic-gate if (checkonly) { 1864*0Sstevel@tonic-gate /* T_CHECK case */ 1865*0Sstevel@tonic-gate *(int *)outvalp = (*i1 & 0xFF); 1866*0Sstevel@tonic-gate break; 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate icmp->icmp_proto = *i1 & 0xFF; 1869*0Sstevel@tonic-gate if ((icmp->icmp_proto == IPPROTO_RAW || 1870*0Sstevel@tonic-gate icmp->icmp_proto == IPPROTO_IGMP) && 1871*0Sstevel@tonic-gate icmp->icmp_family == AF_INET) 1872*0Sstevel@tonic-gate icmp->icmp_hdrincl = 1; 1873*0Sstevel@tonic-gate else 1874*0Sstevel@tonic-gate icmp->icmp_hdrincl = 0; 1875*0Sstevel@tonic-gate 1876*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6 && 1877*0Sstevel@tonic-gate icmp->icmp_proto == IPPROTO_ICMPV6) { 1878*0Sstevel@tonic-gate /* Set offset for icmp6_cksum */ 1879*0Sstevel@tonic-gate icmp->icmp_raw_checksum = 0; 1880*0Sstevel@tonic-gate icmp->icmp_checksum_off = 2; 1881*0Sstevel@tonic-gate } 1882*0Sstevel@tonic-gate if (icmp->icmp_proto == IPPROTO_UDP || 1883*0Sstevel@tonic-gate icmp->icmp_proto == IPPROTO_TCP || 1884*0Sstevel@tonic-gate icmp->icmp_proto == IPPROTO_SCTP) { 1885*0Sstevel@tonic-gate icmp->icmp_no_tp_cksum = 1; 1886*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_fields |= 1887*0Sstevel@tonic-gate IPPF_NO_CKSUM; 1888*0Sstevel@tonic-gate } else { 1889*0Sstevel@tonic-gate icmp->icmp_no_tp_cksum = 0; 1890*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_fields &= 1891*0Sstevel@tonic-gate ~IPPF_NO_CKSUM; 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate if (icmp->icmp_filter != NULL && 1895*0Sstevel@tonic-gate icmp->icmp_proto != IPPROTO_ICMPV6) { 1896*0Sstevel@tonic-gate kmem_free(icmp->icmp_filter, 1897*0Sstevel@tonic-gate sizeof (icmp6_filter_t)); 1898*0Sstevel@tonic-gate icmp->icmp_filter = NULL; 1899*0Sstevel@tonic-gate } 1900*0Sstevel@tonic-gate 1901*0Sstevel@tonic-gate /* Rebuild the header template */ 1902*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 1903*0Sstevel@tonic-gate if (error != 0) { 1904*0Sstevel@tonic-gate *outlenp = 0; 1905*0Sstevel@tonic-gate return (error); 1906*0Sstevel@tonic-gate } 1907*0Sstevel@tonic-gate 1908*0Sstevel@tonic-gate icmp_bind_proto(q); 1909*0Sstevel@tonic-gate *outlenp = sizeof (int); 1910*0Sstevel@tonic-gate *(int *)outvalp = *i1 & 0xFF; 1911*0Sstevel@tonic-gate return (0); 1912*0Sstevel@tonic-gate case SO_REUSEADDR: 1913*0Sstevel@tonic-gate if (!checkonly) 1914*0Sstevel@tonic-gate icmp->icmp_reuseaddr = onoff; 1915*0Sstevel@tonic-gate break; 1916*0Sstevel@tonic-gate 1917*0Sstevel@tonic-gate /* 1918*0Sstevel@tonic-gate * The following three items are available here, 1919*0Sstevel@tonic-gate * but are only meaningful to IP. 1920*0Sstevel@tonic-gate */ 1921*0Sstevel@tonic-gate case SO_DONTROUTE: 1922*0Sstevel@tonic-gate if (!checkonly) 1923*0Sstevel@tonic-gate icmp->icmp_dontroute = onoff; 1924*0Sstevel@tonic-gate break; 1925*0Sstevel@tonic-gate case SO_USELOOPBACK: 1926*0Sstevel@tonic-gate if (!checkonly) 1927*0Sstevel@tonic-gate icmp->icmp_useloopback = onoff; 1928*0Sstevel@tonic-gate break; 1929*0Sstevel@tonic-gate case SO_BROADCAST: 1930*0Sstevel@tonic-gate if (!checkonly) 1931*0Sstevel@tonic-gate icmp->icmp_broadcast = onoff; 1932*0Sstevel@tonic-gate break; 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate case SO_SNDBUF: 1935*0Sstevel@tonic-gate if (*i1 > icmp_max_buf) { 1936*0Sstevel@tonic-gate *outlenp = 0; 1937*0Sstevel@tonic-gate return (ENOBUFS); 1938*0Sstevel@tonic-gate } 1939*0Sstevel@tonic-gate if (!checkonly) { 1940*0Sstevel@tonic-gate q->q_hiwat = *i1; 1941*0Sstevel@tonic-gate q->q_next->q_hiwat = *i1; 1942*0Sstevel@tonic-gate } 1943*0Sstevel@tonic-gate break; 1944*0Sstevel@tonic-gate case SO_RCVBUF: 1945*0Sstevel@tonic-gate if (*i1 > icmp_max_buf) { 1946*0Sstevel@tonic-gate *outlenp = 0; 1947*0Sstevel@tonic-gate return (ENOBUFS); 1948*0Sstevel@tonic-gate } 1949*0Sstevel@tonic-gate if (!checkonly) { 1950*0Sstevel@tonic-gate RD(q)->q_hiwat = *i1; 1951*0Sstevel@tonic-gate (void) mi_set_sth_hiwat(RD(q), *i1); 1952*0Sstevel@tonic-gate } 1953*0Sstevel@tonic-gate break; 1954*0Sstevel@tonic-gate case SO_DGRAM_ERRIND: 1955*0Sstevel@tonic-gate if (!checkonly) 1956*0Sstevel@tonic-gate icmp->icmp_dgram_errind = onoff; 1957*0Sstevel@tonic-gate break; 1958*0Sstevel@tonic-gate /* 1959*0Sstevel@tonic-gate * Following three not meaningful for icmp 1960*0Sstevel@tonic-gate * Action is same as "default" so we keep them 1961*0Sstevel@tonic-gate * in comments. 1962*0Sstevel@tonic-gate * case SO_LINGER: 1963*0Sstevel@tonic-gate * case SO_KEEPALIVE: 1964*0Sstevel@tonic-gate * case SO_OOBINLINE: 1965*0Sstevel@tonic-gate */ 1966*0Sstevel@tonic-gate default: 1967*0Sstevel@tonic-gate *outlenp = 0; 1968*0Sstevel@tonic-gate return (EINVAL); 1969*0Sstevel@tonic-gate } 1970*0Sstevel@tonic-gate break; 1971*0Sstevel@tonic-gate case IPPROTO_IP: 1972*0Sstevel@tonic-gate /* 1973*0Sstevel@tonic-gate * Only allow IPv4 option processing on IPv4 sockets. 1974*0Sstevel@tonic-gate */ 1975*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET) { 1976*0Sstevel@tonic-gate *outlenp = 0; 1977*0Sstevel@tonic-gate return (ENOPROTOOPT); 1978*0Sstevel@tonic-gate } 1979*0Sstevel@tonic-gate switch (name) { 1980*0Sstevel@tonic-gate case IP_OPTIONS: 1981*0Sstevel@tonic-gate case T_IP_OPTIONS: 1982*0Sstevel@tonic-gate /* Save options for use by IP. */ 1983*0Sstevel@tonic-gate if (inlen & 0x3) { 1984*0Sstevel@tonic-gate *outlenp = 0; 1985*0Sstevel@tonic-gate return (EINVAL); 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate if (checkonly) 1988*0Sstevel@tonic-gate break; 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate if (icmp->icmp_ip_snd_options) { 1991*0Sstevel@tonic-gate mi_free((char *)icmp->icmp_ip_snd_options); 1992*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len = 0; 1993*0Sstevel@tonic-gate icmp->icmp_ip_snd_options = NULL; 1994*0Sstevel@tonic-gate } 1995*0Sstevel@tonic-gate if (inlen) { 1996*0Sstevel@tonic-gate icmp->icmp_ip_snd_options = 1997*0Sstevel@tonic-gate (uchar_t *)mi_alloc(inlen, BPRI_HI); 1998*0Sstevel@tonic-gate if (icmp->icmp_ip_snd_options) { 1999*0Sstevel@tonic-gate bcopy(invalp, 2000*0Sstevel@tonic-gate icmp->icmp_ip_snd_options, inlen); 2001*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len = inlen; 2002*0Sstevel@tonic-gate } 2003*0Sstevel@tonic-gate } 2004*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 2005*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len; 2006*0Sstevel@tonic-gate (void) mi_set_sth_wroff(RD(q), icmp->icmp_max_hdr_len + 2007*0Sstevel@tonic-gate icmp_wroff_extra); 2008*0Sstevel@tonic-gate break; 2009*0Sstevel@tonic-gate case IP_HDRINCL: 2010*0Sstevel@tonic-gate if (!checkonly) 2011*0Sstevel@tonic-gate icmp->icmp_hdrincl = onoff; 2012*0Sstevel@tonic-gate break; 2013*0Sstevel@tonic-gate case IP_TOS: 2014*0Sstevel@tonic-gate case T_IP_TOS: 2015*0Sstevel@tonic-gate if (!checkonly) { 2016*0Sstevel@tonic-gate icmp->icmp_type_of_service = (uint8_t)*i1; 2017*0Sstevel@tonic-gate } 2018*0Sstevel@tonic-gate break; 2019*0Sstevel@tonic-gate case IP_TTL: 2020*0Sstevel@tonic-gate if (!checkonly) { 2021*0Sstevel@tonic-gate icmp->icmp_ttl = (uint8_t)*i1; 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate break; 2024*0Sstevel@tonic-gate case IP_MULTICAST_IF: 2025*0Sstevel@tonic-gate /* 2026*0Sstevel@tonic-gate * TODO should check OPTMGMT reply and undo this if 2027*0Sstevel@tonic-gate * there is an error. 2028*0Sstevel@tonic-gate */ 2029*0Sstevel@tonic-gate if (!checkonly) 2030*0Sstevel@tonic-gate icmp->icmp_multicast_if_addr = *i1; 2031*0Sstevel@tonic-gate break; 2032*0Sstevel@tonic-gate case IP_MULTICAST_TTL: 2033*0Sstevel@tonic-gate if (!checkonly) 2034*0Sstevel@tonic-gate icmp->icmp_multicast_ttl = *invalp; 2035*0Sstevel@tonic-gate break; 2036*0Sstevel@tonic-gate case IP_MULTICAST_LOOP: 2037*0Sstevel@tonic-gate if (!checkonly) { 2038*0Sstevel@tonic-gate icmp->icmp_multicast_loop = 2039*0Sstevel@tonic-gate (*invalp == 0) ? 0 : 1; 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate break; 2042*0Sstevel@tonic-gate case IP_BOUND_IF: 2043*0Sstevel@tonic-gate if (!checkonly) 2044*0Sstevel@tonic-gate icmp->icmp_bound_if = *i1; 2045*0Sstevel@tonic-gate break; 2046*0Sstevel@tonic-gate case IP_UNSPEC_SRC: 2047*0Sstevel@tonic-gate if (!checkonly) 2048*0Sstevel@tonic-gate icmp->icmp_unspec_source = onoff; 2049*0Sstevel@tonic-gate break; 2050*0Sstevel@tonic-gate case IP_XMIT_IF: 2051*0Sstevel@tonic-gate if (!checkonly) 2052*0Sstevel@tonic-gate icmp->icmp_xmit_if = *i1; 2053*0Sstevel@tonic-gate break; 2054*0Sstevel@tonic-gate case IP_RECVIF: 2055*0Sstevel@tonic-gate if (!checkonly) 2056*0Sstevel@tonic-gate icmp->icmp_recvif = onoff; 2057*0Sstevel@tonic-gate break; 2058*0Sstevel@tonic-gate case IP_ADD_MEMBERSHIP: 2059*0Sstevel@tonic-gate case IP_DROP_MEMBERSHIP: 2060*0Sstevel@tonic-gate case IP_BLOCK_SOURCE: 2061*0Sstevel@tonic-gate case IP_UNBLOCK_SOURCE: 2062*0Sstevel@tonic-gate case IP_ADD_SOURCE_MEMBERSHIP: 2063*0Sstevel@tonic-gate case IP_DROP_SOURCE_MEMBERSHIP: 2064*0Sstevel@tonic-gate case MCAST_JOIN_GROUP: 2065*0Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 2066*0Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 2067*0Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 2068*0Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 2069*0Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 2070*0Sstevel@tonic-gate case MRT_INIT: 2071*0Sstevel@tonic-gate case MRT_DONE: 2072*0Sstevel@tonic-gate case MRT_ADD_VIF: 2073*0Sstevel@tonic-gate case MRT_DEL_VIF: 2074*0Sstevel@tonic-gate case MRT_ADD_MFC: 2075*0Sstevel@tonic-gate case MRT_DEL_MFC: 2076*0Sstevel@tonic-gate case MRT_VERSION: 2077*0Sstevel@tonic-gate case MRT_ASSERT: 2078*0Sstevel@tonic-gate case IP_SEC_OPT: 2079*0Sstevel@tonic-gate case IP_DONTFAILOVER_IF: 2080*0Sstevel@tonic-gate /* 2081*0Sstevel@tonic-gate * "soft" error (negative) 2082*0Sstevel@tonic-gate * option not handled at this level 2083*0Sstevel@tonic-gate * Note: Do not modify *outlenp 2084*0Sstevel@tonic-gate */ 2085*0Sstevel@tonic-gate return (-EINVAL); 2086*0Sstevel@tonic-gate default: 2087*0Sstevel@tonic-gate *outlenp = 0; 2088*0Sstevel@tonic-gate return (EINVAL); 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate break; 2091*0Sstevel@tonic-gate case IPPROTO_IPV6: { 2092*0Sstevel@tonic-gate ip6_pkt_t *ipp; 2093*0Sstevel@tonic-gate boolean_t sticky; 2094*0Sstevel@tonic-gate 2095*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6) { 2096*0Sstevel@tonic-gate *outlenp = 0; 2097*0Sstevel@tonic-gate return (ENOPROTOOPT); 2098*0Sstevel@tonic-gate } 2099*0Sstevel@tonic-gate /* 2100*0Sstevel@tonic-gate * Deal with both sticky options and ancillary data 2101*0Sstevel@tonic-gate */ 2102*0Sstevel@tonic-gate if (thisdg_attrs == NULL) { 2103*0Sstevel@tonic-gate /* sticky options, or none */ 2104*0Sstevel@tonic-gate ipp = &icmp->icmp_sticky_ipp; 2105*0Sstevel@tonic-gate sticky = B_TRUE; 2106*0Sstevel@tonic-gate } else { 2107*0Sstevel@tonic-gate /* ancillary data */ 2108*0Sstevel@tonic-gate ipp = (ip6_pkt_t *)thisdg_attrs; 2109*0Sstevel@tonic-gate sticky = B_FALSE; 2110*0Sstevel@tonic-gate } 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate switch (name) { 2113*0Sstevel@tonic-gate case IPV6_MULTICAST_IF: 2114*0Sstevel@tonic-gate if (!checkonly) 2115*0Sstevel@tonic-gate icmp->icmp_multicast_if_index = *i1; 2116*0Sstevel@tonic-gate break; 2117*0Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 2118*0Sstevel@tonic-gate /* -1 means use default */ 2119*0Sstevel@tonic-gate if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) { 2120*0Sstevel@tonic-gate *outlenp = 0; 2121*0Sstevel@tonic-gate return (EINVAL); 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate if (!checkonly) { 2124*0Sstevel@tonic-gate if (*i1 == -1) { 2125*0Sstevel@tonic-gate icmp->icmp_ttl = ipp->ipp_hoplimit = 2126*0Sstevel@tonic-gate icmp_ipv6_hoplimit; 2127*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_HOPLIMIT; 2128*0Sstevel@tonic-gate /* Pass modified value to IP. */ 2129*0Sstevel@tonic-gate *i1 = ipp->ipp_hoplimit; 2130*0Sstevel@tonic-gate } else { 2131*0Sstevel@tonic-gate icmp->icmp_ttl = ipp->ipp_hoplimit = 2132*0Sstevel@tonic-gate (uint8_t)*i1; 2133*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPLIMIT; 2134*0Sstevel@tonic-gate } 2135*0Sstevel@tonic-gate /* Rebuild the header template */ 2136*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2137*0Sstevel@tonic-gate if (error != 0) { 2138*0Sstevel@tonic-gate *outlenp = 0; 2139*0Sstevel@tonic-gate return (error); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate } 2142*0Sstevel@tonic-gate break; 2143*0Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 2144*0Sstevel@tonic-gate /* -1 means use default */ 2145*0Sstevel@tonic-gate if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) { 2146*0Sstevel@tonic-gate *outlenp = 0; 2147*0Sstevel@tonic-gate return (EINVAL); 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate if (!checkonly) { 2150*0Sstevel@tonic-gate if (*i1 == -1) { 2151*0Sstevel@tonic-gate icmp->icmp_multicast_ttl = 2152*0Sstevel@tonic-gate ipp->ipp_multi_hoplimit = 2153*0Sstevel@tonic-gate IP_DEFAULT_MULTICAST_TTL; 2154*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_MULTI_HOPLIMIT; 2155*0Sstevel@tonic-gate /* Pass modified value to IP. */ 2156*0Sstevel@tonic-gate *i1 = ipp->ipp_multi_hoplimit; 2157*0Sstevel@tonic-gate } else { 2158*0Sstevel@tonic-gate icmp->icmp_multicast_ttl = 2159*0Sstevel@tonic-gate ipp->ipp_multi_hoplimit = 2160*0Sstevel@tonic-gate (uint8_t)*i1; 2161*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_MULTI_HOPLIMIT; 2162*0Sstevel@tonic-gate } 2163*0Sstevel@tonic-gate /* Rebuild the header template */ 2164*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2165*0Sstevel@tonic-gate if (error != 0) { 2166*0Sstevel@tonic-gate *outlenp = 0; 2167*0Sstevel@tonic-gate return (error); 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate } 2170*0Sstevel@tonic-gate break; 2171*0Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 2172*0Sstevel@tonic-gate if (*i1 != 0 && *i1 != 1) { 2173*0Sstevel@tonic-gate *outlenp = 0; 2174*0Sstevel@tonic-gate return (EINVAL); 2175*0Sstevel@tonic-gate } 2176*0Sstevel@tonic-gate if (!checkonly) 2177*0Sstevel@tonic-gate icmp->icmp_multicast_loop = *i1; 2178*0Sstevel@tonic-gate break; 2179*0Sstevel@tonic-gate case IPV6_CHECKSUM: 2180*0Sstevel@tonic-gate /* 2181*0Sstevel@tonic-gate * Integer offset into the user data of where the 2182*0Sstevel@tonic-gate * checksum is located. 2183*0Sstevel@tonic-gate * Offset of -1 disables option. 2184*0Sstevel@tonic-gate * Does not apply to IPPROTO_ICMPV6. 2185*0Sstevel@tonic-gate */ 2186*0Sstevel@tonic-gate if (icmp->icmp_proto == IPPROTO_ICMPV6 || !sticky) { 2187*0Sstevel@tonic-gate *outlenp = 0; 2188*0Sstevel@tonic-gate return (EINVAL); 2189*0Sstevel@tonic-gate } 2190*0Sstevel@tonic-gate if ((*i1 != -1) && ((*i1 < 0) || (*i1 & 0x1) != 0)) { 2191*0Sstevel@tonic-gate /* Negative or not 16 bit aligned offset */ 2192*0Sstevel@tonic-gate *outlenp = 0; 2193*0Sstevel@tonic-gate return (EINVAL); 2194*0Sstevel@tonic-gate } 2195*0Sstevel@tonic-gate if (checkonly) 2196*0Sstevel@tonic-gate break; 2197*0Sstevel@tonic-gate 2198*0Sstevel@tonic-gate if (*i1 == -1) { 2199*0Sstevel@tonic-gate icmp->icmp_raw_checksum = 0; 2200*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_RAW_CKSUM; 2201*0Sstevel@tonic-gate } else { 2202*0Sstevel@tonic-gate icmp->icmp_raw_checksum = 1; 2203*0Sstevel@tonic-gate icmp->icmp_checksum_off = *i1; 2204*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_RAW_CKSUM; 2205*0Sstevel@tonic-gate } 2206*0Sstevel@tonic-gate /* Rebuild the header template */ 2207*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2208*0Sstevel@tonic-gate if (error != 0) { 2209*0Sstevel@tonic-gate *outlenp = 0; 2210*0Sstevel@tonic-gate return (error); 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate break; 2213*0Sstevel@tonic-gate case IPV6_JOIN_GROUP: 2214*0Sstevel@tonic-gate case IPV6_LEAVE_GROUP: 2215*0Sstevel@tonic-gate case MCAST_JOIN_GROUP: 2216*0Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 2217*0Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 2218*0Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 2219*0Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 2220*0Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 2221*0Sstevel@tonic-gate /* 2222*0Sstevel@tonic-gate * "soft" error (negative) 2223*0Sstevel@tonic-gate * option not handled at this level 2224*0Sstevel@tonic-gate * Note: Do not modify *outlenp 2225*0Sstevel@tonic-gate */ 2226*0Sstevel@tonic-gate return (-EINVAL); 2227*0Sstevel@tonic-gate case IPV6_BOUND_IF: 2228*0Sstevel@tonic-gate if (!checkonly) 2229*0Sstevel@tonic-gate icmp->icmp_bound_if = *i1; 2230*0Sstevel@tonic-gate break; 2231*0Sstevel@tonic-gate case IPV6_UNSPEC_SRC: 2232*0Sstevel@tonic-gate if (!checkonly) 2233*0Sstevel@tonic-gate icmp->icmp_unspec_source = onoff; 2234*0Sstevel@tonic-gate break; 2235*0Sstevel@tonic-gate case IPV6_RECVTCLASS: 2236*0Sstevel@tonic-gate if (!checkonly) 2237*0Sstevel@tonic-gate icmp->icmp_ipv6_recvtclass = onoff; 2238*0Sstevel@tonic-gate break; 2239*0Sstevel@tonic-gate /* 2240*0Sstevel@tonic-gate * Set boolean switches for ancillary data delivery 2241*0Sstevel@tonic-gate */ 2242*0Sstevel@tonic-gate case IPV6_RECVPKTINFO: 2243*0Sstevel@tonic-gate if (!checkonly) 2244*0Sstevel@tonic-gate icmp->icmp_ipv6_recvpktinfo = onoff; 2245*0Sstevel@tonic-gate break; 2246*0Sstevel@tonic-gate case IPV6_RECVPATHMTU: 2247*0Sstevel@tonic-gate if (!checkonly) 2248*0Sstevel@tonic-gate icmp->icmp_ipv6_recvpathmtu = onoff; 2249*0Sstevel@tonic-gate break; 2250*0Sstevel@tonic-gate case IPV6_RECVHOPLIMIT: 2251*0Sstevel@tonic-gate if (!checkonly) 2252*0Sstevel@tonic-gate icmp->icmp_ipv6_recvhoplimit = onoff; 2253*0Sstevel@tonic-gate break; 2254*0Sstevel@tonic-gate case IPV6_RECVHOPOPTS: 2255*0Sstevel@tonic-gate if (!checkonly) 2256*0Sstevel@tonic-gate icmp->icmp_ipv6_recvhopopts = onoff; 2257*0Sstevel@tonic-gate break; 2258*0Sstevel@tonic-gate case IPV6_RECVDSTOPTS: 2259*0Sstevel@tonic-gate if (!checkonly) 2260*0Sstevel@tonic-gate icmp->icmp_ipv6_recvdstopts = onoff; 2261*0Sstevel@tonic-gate break; 2262*0Sstevel@tonic-gate case _OLD_IPV6_RECVDSTOPTS: 2263*0Sstevel@tonic-gate if (!checkonly) 2264*0Sstevel@tonic-gate icmp->icmp_old_ipv6_recvdstopts = onoff; 2265*0Sstevel@tonic-gate break; 2266*0Sstevel@tonic-gate case IPV6_RECVRTHDRDSTOPTS: 2267*0Sstevel@tonic-gate if (!checkonly) 2268*0Sstevel@tonic-gate icmp->icmp_ipv6_recvrtdstopts = onoff; 2269*0Sstevel@tonic-gate break; 2270*0Sstevel@tonic-gate case IPV6_RECVRTHDR: 2271*0Sstevel@tonic-gate if (!checkonly) 2272*0Sstevel@tonic-gate icmp->icmp_ipv6_recvrthdr = onoff; 2273*0Sstevel@tonic-gate break; 2274*0Sstevel@tonic-gate /* 2275*0Sstevel@tonic-gate * Set sticky options or ancillary data. 2276*0Sstevel@tonic-gate * If sticky options, (re)build any extension headers 2277*0Sstevel@tonic-gate * that might be needed as a result. 2278*0Sstevel@tonic-gate */ 2279*0Sstevel@tonic-gate case IPV6_PKTINFO: 2280*0Sstevel@tonic-gate /* 2281*0Sstevel@tonic-gate * The source address and ifindex are verified 2282*0Sstevel@tonic-gate * in ip_opt_set(). For ancillary data the 2283*0Sstevel@tonic-gate * source address is checked in ip_wput_v6. 2284*0Sstevel@tonic-gate */ 2285*0Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (struct in6_pktinfo)) 2286*0Sstevel@tonic-gate return (EINVAL); 2287*0Sstevel@tonic-gate if (checkonly) 2288*0Sstevel@tonic-gate break; 2289*0Sstevel@tonic-gate 2290*0Sstevel@tonic-gate if (inlen == 0) { 2291*0Sstevel@tonic-gate ipp->ipp_fields &= ~(IPPF_IFINDEX|IPPF_ADDR); 2292*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= 2293*0Sstevel@tonic-gate (IPPF_IFINDEX|IPPF_ADDR); 2294*0Sstevel@tonic-gate } else { 2295*0Sstevel@tonic-gate struct in6_pktinfo *pkti; 2296*0Sstevel@tonic-gate 2297*0Sstevel@tonic-gate pkti = (struct in6_pktinfo *)invalp; 2298*0Sstevel@tonic-gate ipp->ipp_ifindex = pkti->ipi6_ifindex; 2299*0Sstevel@tonic-gate ipp->ipp_addr = pkti->ipi6_addr; 2300*0Sstevel@tonic-gate if (ipp->ipp_ifindex != 0) 2301*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_IFINDEX; 2302*0Sstevel@tonic-gate else 2303*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_IFINDEX; 2304*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 2305*0Sstevel@tonic-gate &ipp->ipp_addr)) 2306*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_ADDR; 2307*0Sstevel@tonic-gate else 2308*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_ADDR; 2309*0Sstevel@tonic-gate } 2310*0Sstevel@tonic-gate if (sticky) { 2311*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2312*0Sstevel@tonic-gate if (error != 0) 2313*0Sstevel@tonic-gate return (error); 2314*0Sstevel@tonic-gate } 2315*0Sstevel@tonic-gate break; 2316*0Sstevel@tonic-gate case IPV6_HOPLIMIT: 2317*0Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (int)) 2318*0Sstevel@tonic-gate return (EINVAL); 2319*0Sstevel@tonic-gate if (checkonly) 2320*0Sstevel@tonic-gate break; 2321*0Sstevel@tonic-gate 2322*0Sstevel@tonic-gate if (inlen == 0) { 2323*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_HOPLIMIT; 2324*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_HOPLIMIT; 2325*0Sstevel@tonic-gate } else { 2326*0Sstevel@tonic-gate if (*i1 > 255 || *i1 < -1) 2327*0Sstevel@tonic-gate return (EINVAL); 2328*0Sstevel@tonic-gate if (*i1 == -1) 2329*0Sstevel@tonic-gate ipp->ipp_hoplimit = icmp_ipv6_hoplimit; 2330*0Sstevel@tonic-gate else 2331*0Sstevel@tonic-gate ipp->ipp_hoplimit = *i1; 2332*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPLIMIT; 2333*0Sstevel@tonic-gate } 2334*0Sstevel@tonic-gate if (sticky) { 2335*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2336*0Sstevel@tonic-gate if (error != 0) 2337*0Sstevel@tonic-gate return (error); 2338*0Sstevel@tonic-gate } 2339*0Sstevel@tonic-gate break; 2340*0Sstevel@tonic-gate case IPV6_TCLASS: 2341*0Sstevel@tonic-gate /* 2342*0Sstevel@tonic-gate * IPV6_RECVTCLASS accepts -1 as use kernel default 2343*0Sstevel@tonic-gate * and [0, 255] as the actualy traffic class. 2344*0Sstevel@tonic-gate */ 2345*0Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (int)) 2346*0Sstevel@tonic-gate return (EINVAL); 2347*0Sstevel@tonic-gate if (checkonly) 2348*0Sstevel@tonic-gate break; 2349*0Sstevel@tonic-gate 2350*0Sstevel@tonic-gate if (inlen == 0) { 2351*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_TCLASS; 2352*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_TCLASS; 2353*0Sstevel@tonic-gate } else { 2354*0Sstevel@tonic-gate if (*i1 >= 256 || *i1 < -1) 2355*0Sstevel@tonic-gate return (EINVAL); 2356*0Sstevel@tonic-gate if (*i1 == -1) { 2357*0Sstevel@tonic-gate ipp->ipp_tclass = 2358*0Sstevel@tonic-gate IPV6_FLOW_TCLASS( 2359*0Sstevel@tonic-gate IPV6_DEFAULT_VERS_AND_FLOW); 2360*0Sstevel@tonic-gate } else { 2361*0Sstevel@tonic-gate ipp->ipp_tclass = *i1; 2362*0Sstevel@tonic-gate } 2363*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_TCLASS; 2364*0Sstevel@tonic-gate } 2365*0Sstevel@tonic-gate if (sticky) { 2366*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2367*0Sstevel@tonic-gate if (error != 0) 2368*0Sstevel@tonic-gate return (error); 2369*0Sstevel@tonic-gate } 2370*0Sstevel@tonic-gate break; 2371*0Sstevel@tonic-gate case IPV6_NEXTHOP: 2372*0Sstevel@tonic-gate /* 2373*0Sstevel@tonic-gate * IP will verify that the nexthop is reachable 2374*0Sstevel@tonic-gate * and fail for sticky options. 2375*0Sstevel@tonic-gate */ 2376*0Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (sin6_t)) 2377*0Sstevel@tonic-gate return (EINVAL); 2378*0Sstevel@tonic-gate if (checkonly) 2379*0Sstevel@tonic-gate break; 2380*0Sstevel@tonic-gate 2381*0Sstevel@tonic-gate if (inlen == 0) { 2382*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_NEXTHOP; 2383*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_NEXTHOP; 2384*0Sstevel@tonic-gate } else { 2385*0Sstevel@tonic-gate sin6_t *sin6 = (sin6_t *)invalp; 2386*0Sstevel@tonic-gate 2387*0Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6) 2388*0Sstevel@tonic-gate return (EAFNOSUPPORT); 2389*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2390*0Sstevel@tonic-gate return (EADDRNOTAVAIL); 2391*0Sstevel@tonic-gate ipp->ipp_nexthop = sin6->sin6_addr; 2392*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 2393*0Sstevel@tonic-gate &ipp->ipp_nexthop)) 2394*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_NEXTHOP; 2395*0Sstevel@tonic-gate else 2396*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_NEXTHOP; 2397*0Sstevel@tonic-gate } 2398*0Sstevel@tonic-gate if (sticky) { 2399*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2400*0Sstevel@tonic-gate if (error != 0) 2401*0Sstevel@tonic-gate return (error); 2402*0Sstevel@tonic-gate } 2403*0Sstevel@tonic-gate break; 2404*0Sstevel@tonic-gate case IPV6_HOPOPTS: { 2405*0Sstevel@tonic-gate ip6_hbh_t *hopts = (ip6_hbh_t *)invalp; 2406*0Sstevel@tonic-gate /* 2407*0Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 2408*0Sstevel@tonic-gate * eight bytes, and matching size passed in. 2409*0Sstevel@tonic-gate */ 2410*0Sstevel@tonic-gate if (inlen != 0 && 2411*0Sstevel@tonic-gate inlen != (8 * (hopts->ip6h_len + 1))) 2412*0Sstevel@tonic-gate return (EINVAL); 2413*0Sstevel@tonic-gate 2414*0Sstevel@tonic-gate if (checkonly) 2415*0Sstevel@tonic-gate break; 2416*0Sstevel@tonic-gate if (inlen == 0) { 2417*0Sstevel@tonic-gate if (sticky && 2418*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS) != 0) { 2419*0Sstevel@tonic-gate kmem_free(ipp->ipp_hopopts, 2420*0Sstevel@tonic-gate ipp->ipp_hopoptslen); 2421*0Sstevel@tonic-gate ipp->ipp_hopopts = NULL; 2422*0Sstevel@tonic-gate ipp->ipp_hopoptslen = 0; 2423*0Sstevel@tonic-gate } 2424*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_HOPOPTS; 2425*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_HOPOPTS; 2426*0Sstevel@tonic-gate } else { 2427*0Sstevel@tonic-gate error = icmp_pkt_set(invalp, inlen, sticky, 2428*0Sstevel@tonic-gate (uchar_t **)&ipp->ipp_hopopts, 2429*0Sstevel@tonic-gate &ipp->ipp_hopoptslen); 2430*0Sstevel@tonic-gate if (error != 0) 2431*0Sstevel@tonic-gate return (error); 2432*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPOPTS; 2433*0Sstevel@tonic-gate } 2434*0Sstevel@tonic-gate if (sticky) { 2435*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2436*0Sstevel@tonic-gate if (error != 0) 2437*0Sstevel@tonic-gate return (error); 2438*0Sstevel@tonic-gate } 2439*0Sstevel@tonic-gate break; 2440*0Sstevel@tonic-gate } 2441*0Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: { 2442*0Sstevel@tonic-gate ip6_dest_t *dopts = (ip6_dest_t *)invalp; 2443*0Sstevel@tonic-gate 2444*0Sstevel@tonic-gate /* 2445*0Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 2446*0Sstevel@tonic-gate * eight bytes, and matching size passed in. 2447*0Sstevel@tonic-gate */ 2448*0Sstevel@tonic-gate if (inlen != 0 && 2449*0Sstevel@tonic-gate inlen != (8 * (dopts->ip6d_len + 1))) 2450*0Sstevel@tonic-gate return (EINVAL); 2451*0Sstevel@tonic-gate 2452*0Sstevel@tonic-gate if (checkonly) 2453*0Sstevel@tonic-gate break; 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate if (inlen == 0) { 2456*0Sstevel@tonic-gate if (sticky && 2457*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTDSTOPTS) != 0) { 2458*0Sstevel@tonic-gate kmem_free(ipp->ipp_rtdstopts, 2459*0Sstevel@tonic-gate ipp->ipp_rtdstoptslen); 2460*0Sstevel@tonic-gate ipp->ipp_rtdstopts = NULL; 2461*0Sstevel@tonic-gate ipp->ipp_rtdstoptslen = 0; 2462*0Sstevel@tonic-gate } 2463*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_RTDSTOPTS; 2464*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_RTDSTOPTS; 2465*0Sstevel@tonic-gate } else { 2466*0Sstevel@tonic-gate error = icmp_pkt_set(invalp, inlen, sticky, 2467*0Sstevel@tonic-gate (uchar_t **)&ipp->ipp_rtdstopts, 2468*0Sstevel@tonic-gate &ipp->ipp_rtdstoptslen); 2469*0Sstevel@tonic-gate if (error != 0) 2470*0Sstevel@tonic-gate return (error); 2471*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_RTDSTOPTS; 2472*0Sstevel@tonic-gate } 2473*0Sstevel@tonic-gate if (sticky) { 2474*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2475*0Sstevel@tonic-gate if (error != 0) 2476*0Sstevel@tonic-gate return (error); 2477*0Sstevel@tonic-gate } 2478*0Sstevel@tonic-gate break; 2479*0Sstevel@tonic-gate } 2480*0Sstevel@tonic-gate case IPV6_DSTOPTS: { 2481*0Sstevel@tonic-gate ip6_dest_t *dopts = (ip6_dest_t *)invalp; 2482*0Sstevel@tonic-gate 2483*0Sstevel@tonic-gate /* 2484*0Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 2485*0Sstevel@tonic-gate * eight bytes, and matching size passed in. 2486*0Sstevel@tonic-gate */ 2487*0Sstevel@tonic-gate if (inlen != 0 && 2488*0Sstevel@tonic-gate inlen != (8 * (dopts->ip6d_len + 1))) 2489*0Sstevel@tonic-gate return (EINVAL); 2490*0Sstevel@tonic-gate 2491*0Sstevel@tonic-gate if (checkonly) 2492*0Sstevel@tonic-gate break; 2493*0Sstevel@tonic-gate 2494*0Sstevel@tonic-gate if (inlen == 0) { 2495*0Sstevel@tonic-gate if (sticky && 2496*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS) != 0) { 2497*0Sstevel@tonic-gate kmem_free(ipp->ipp_dstopts, 2498*0Sstevel@tonic-gate ipp->ipp_dstoptslen); 2499*0Sstevel@tonic-gate ipp->ipp_dstopts = NULL; 2500*0Sstevel@tonic-gate ipp->ipp_dstoptslen = 0; 2501*0Sstevel@tonic-gate } 2502*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_DSTOPTS; 2503*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_DSTOPTS; 2504*0Sstevel@tonic-gate } else { 2505*0Sstevel@tonic-gate error = icmp_pkt_set(invalp, inlen, sticky, 2506*0Sstevel@tonic-gate (uchar_t **)&ipp->ipp_dstopts, 2507*0Sstevel@tonic-gate &ipp->ipp_dstoptslen); 2508*0Sstevel@tonic-gate if (error != 0) 2509*0Sstevel@tonic-gate return (error); 2510*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_DSTOPTS; 2511*0Sstevel@tonic-gate } 2512*0Sstevel@tonic-gate if (sticky) { 2513*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2514*0Sstevel@tonic-gate if (error != 0) 2515*0Sstevel@tonic-gate return (error); 2516*0Sstevel@tonic-gate } 2517*0Sstevel@tonic-gate break; 2518*0Sstevel@tonic-gate } 2519*0Sstevel@tonic-gate case IPV6_RTHDR: { 2520*0Sstevel@tonic-gate ip6_rthdr_t *rt = (ip6_rthdr_t *)invalp; 2521*0Sstevel@tonic-gate 2522*0Sstevel@tonic-gate /* 2523*0Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 2524*0Sstevel@tonic-gate * eight bytes, and matching size passed in. 2525*0Sstevel@tonic-gate */ 2526*0Sstevel@tonic-gate if (inlen != 0 && 2527*0Sstevel@tonic-gate inlen != (8 * (rt->ip6r_len + 1))) 2528*0Sstevel@tonic-gate return (EINVAL); 2529*0Sstevel@tonic-gate 2530*0Sstevel@tonic-gate if (checkonly) 2531*0Sstevel@tonic-gate break; 2532*0Sstevel@tonic-gate 2533*0Sstevel@tonic-gate if (inlen == 0) { 2534*0Sstevel@tonic-gate if (sticky && 2535*0Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR) != 0) { 2536*0Sstevel@tonic-gate kmem_free(ipp->ipp_rthdr, 2537*0Sstevel@tonic-gate ipp->ipp_rthdrlen); 2538*0Sstevel@tonic-gate ipp->ipp_rthdr = NULL; 2539*0Sstevel@tonic-gate ipp->ipp_rthdrlen = 0; 2540*0Sstevel@tonic-gate } 2541*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_RTHDR; 2542*0Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_RTHDR; 2543*0Sstevel@tonic-gate } else { 2544*0Sstevel@tonic-gate error = icmp_pkt_set(invalp, inlen, sticky, 2545*0Sstevel@tonic-gate (uchar_t **)&ipp->ipp_rthdr, 2546*0Sstevel@tonic-gate &ipp->ipp_rthdrlen); 2547*0Sstevel@tonic-gate if (error != 0) 2548*0Sstevel@tonic-gate return (error); 2549*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_RTHDR; 2550*0Sstevel@tonic-gate } 2551*0Sstevel@tonic-gate if (sticky) { 2552*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 2553*0Sstevel@tonic-gate if (error != 0) 2554*0Sstevel@tonic-gate return (error); 2555*0Sstevel@tonic-gate } 2556*0Sstevel@tonic-gate break; 2557*0Sstevel@tonic-gate } 2558*0Sstevel@tonic-gate 2559*0Sstevel@tonic-gate case IPV6_DONTFRAG: 2560*0Sstevel@tonic-gate if (checkonly) 2561*0Sstevel@tonic-gate break; 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate if (onoff) { 2564*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_DONTFRAG; 2565*0Sstevel@tonic-gate } else { 2566*0Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_DONTFRAG; 2567*0Sstevel@tonic-gate } 2568*0Sstevel@tonic-gate break; 2569*0Sstevel@tonic-gate 2570*0Sstevel@tonic-gate case IPV6_USE_MIN_MTU: 2571*0Sstevel@tonic-gate if (inlen != sizeof (int)) 2572*0Sstevel@tonic-gate return (EINVAL); 2573*0Sstevel@tonic-gate 2574*0Sstevel@tonic-gate if (*i1 < -1 || *i1 > 1) 2575*0Sstevel@tonic-gate return (EINVAL); 2576*0Sstevel@tonic-gate 2577*0Sstevel@tonic-gate if (checkonly) 2578*0Sstevel@tonic-gate break; 2579*0Sstevel@tonic-gate 2580*0Sstevel@tonic-gate ipp->ipp_fields |= IPPF_USE_MIN_MTU; 2581*0Sstevel@tonic-gate ipp->ipp_use_min_mtu = *i1; 2582*0Sstevel@tonic-gate break; 2583*0Sstevel@tonic-gate 2584*0Sstevel@tonic-gate /* 2585*0Sstevel@tonic-gate * This option can't be set. Its only returned via 2586*0Sstevel@tonic-gate * getsockopt() or ancillary data. 2587*0Sstevel@tonic-gate */ 2588*0Sstevel@tonic-gate case IPV6_PATHMTU: 2589*0Sstevel@tonic-gate return (EINVAL); 2590*0Sstevel@tonic-gate 2591*0Sstevel@tonic-gate case IPV6_BOUND_PIF: 2592*0Sstevel@tonic-gate case IPV6_SEC_OPT: 2593*0Sstevel@tonic-gate case IPV6_DONTFAILOVER_IF: 2594*0Sstevel@tonic-gate case IPV6_SRC_PREFERENCES: 2595*0Sstevel@tonic-gate case IPV6_V6ONLY: 2596*0Sstevel@tonic-gate /* Handled at IP level */ 2597*0Sstevel@tonic-gate return (-EINVAL); 2598*0Sstevel@tonic-gate default: 2599*0Sstevel@tonic-gate *outlenp = 0; 2600*0Sstevel@tonic-gate return (EINVAL); 2601*0Sstevel@tonic-gate } 2602*0Sstevel@tonic-gate break; 2603*0Sstevel@tonic-gate } /* end IPPROTO_IPV6 */ 2604*0Sstevel@tonic-gate 2605*0Sstevel@tonic-gate case IPPROTO_ICMPV6: 2606*0Sstevel@tonic-gate /* 2607*0Sstevel@tonic-gate * Only allow IPv6 option processing on IPv6 sockets. 2608*0Sstevel@tonic-gate */ 2609*0Sstevel@tonic-gate if (icmp->icmp_family != AF_INET6) { 2610*0Sstevel@tonic-gate *outlenp = 0; 2611*0Sstevel@tonic-gate return (ENOPROTOOPT); 2612*0Sstevel@tonic-gate } 2613*0Sstevel@tonic-gate if (icmp->icmp_proto != IPPROTO_ICMPV6) { 2614*0Sstevel@tonic-gate *outlenp = 0; 2615*0Sstevel@tonic-gate return (ENOPROTOOPT); 2616*0Sstevel@tonic-gate } 2617*0Sstevel@tonic-gate switch (name) { 2618*0Sstevel@tonic-gate case ICMP6_FILTER: 2619*0Sstevel@tonic-gate if (!checkonly) { 2620*0Sstevel@tonic-gate if ((inlen != 0) && 2621*0Sstevel@tonic-gate (inlen != sizeof (icmp6_filter_t))) 2622*0Sstevel@tonic-gate return (EINVAL); 2623*0Sstevel@tonic-gate 2624*0Sstevel@tonic-gate if (inlen == 0) { 2625*0Sstevel@tonic-gate if (icmp->icmp_filter != NULL) { 2626*0Sstevel@tonic-gate kmem_free(icmp->icmp_filter, 2627*0Sstevel@tonic-gate sizeof (icmp6_filter_t)); 2628*0Sstevel@tonic-gate icmp->icmp_filter = NULL; 2629*0Sstevel@tonic-gate } 2630*0Sstevel@tonic-gate } else { 2631*0Sstevel@tonic-gate if (icmp->icmp_filter == NULL) { 2632*0Sstevel@tonic-gate icmp->icmp_filter = kmem_alloc( 2633*0Sstevel@tonic-gate sizeof (icmp6_filter_t), 2634*0Sstevel@tonic-gate KM_NOSLEEP); 2635*0Sstevel@tonic-gate if (icmp->icmp_filter == NULL) { 2636*0Sstevel@tonic-gate *outlenp = 0; 2637*0Sstevel@tonic-gate return (ENOBUFS); 2638*0Sstevel@tonic-gate } 2639*0Sstevel@tonic-gate } 2640*0Sstevel@tonic-gate (void) bcopy(invalp, icmp->icmp_filter, 2641*0Sstevel@tonic-gate inlen); 2642*0Sstevel@tonic-gate } 2643*0Sstevel@tonic-gate } 2644*0Sstevel@tonic-gate break; 2645*0Sstevel@tonic-gate 2646*0Sstevel@tonic-gate default: 2647*0Sstevel@tonic-gate *outlenp = 0; 2648*0Sstevel@tonic-gate return (EINVAL); 2649*0Sstevel@tonic-gate } 2650*0Sstevel@tonic-gate break; 2651*0Sstevel@tonic-gate default: 2652*0Sstevel@tonic-gate *outlenp = 0; 2653*0Sstevel@tonic-gate return (EINVAL); 2654*0Sstevel@tonic-gate } 2655*0Sstevel@tonic-gate /* 2656*0Sstevel@tonic-gate * Common case of OK return with outval same as inval. 2657*0Sstevel@tonic-gate */ 2658*0Sstevel@tonic-gate if (invalp != outvalp) { 2659*0Sstevel@tonic-gate /* don't trust bcopy for identical src/dst */ 2660*0Sstevel@tonic-gate (void) bcopy(invalp, outvalp, inlen); 2661*0Sstevel@tonic-gate } 2662*0Sstevel@tonic-gate *outlenp = inlen; 2663*0Sstevel@tonic-gate return (0); 2664*0Sstevel@tonic-gate } 2665*0Sstevel@tonic-gate 2666*0Sstevel@tonic-gate /* 2667*0Sstevel@tonic-gate * Update icmp_sticky_hdrs based on icmp_sticky_ipp, icmp_v6src, icmp_ttl, 2668*0Sstevel@tonic-gate * icmp_proto, icmp_raw_checksum and icmp_no_tp_cksum. 2669*0Sstevel@tonic-gate * The headers include ip6i_t (if needed), ip6_t, and any sticky extension 2670*0Sstevel@tonic-gate * headers. 2671*0Sstevel@tonic-gate * Returns failure if can't allocate memory. 2672*0Sstevel@tonic-gate */ 2673*0Sstevel@tonic-gate static int 2674*0Sstevel@tonic-gate icmp_build_hdrs(queue_t *q, icmp_t *icmp) 2675*0Sstevel@tonic-gate { 2676*0Sstevel@tonic-gate uchar_t *hdrs; 2677*0Sstevel@tonic-gate uint_t hdrs_len; 2678*0Sstevel@tonic-gate ip6_t *ip6h; 2679*0Sstevel@tonic-gate ip6i_t *ip6i; 2680*0Sstevel@tonic-gate ip6_pkt_t *ipp = &icmp->icmp_sticky_ipp; 2681*0Sstevel@tonic-gate 2682*0Sstevel@tonic-gate hdrs_len = ip_total_hdrs_len_v6(ipp); 2683*0Sstevel@tonic-gate ASSERT(hdrs_len != 0); 2684*0Sstevel@tonic-gate if (hdrs_len != icmp->icmp_sticky_hdrs_len) { 2685*0Sstevel@tonic-gate /* Need to reallocate */ 2686*0Sstevel@tonic-gate if (hdrs_len != 0) { 2687*0Sstevel@tonic-gate hdrs = kmem_alloc(hdrs_len, KM_NOSLEEP); 2688*0Sstevel@tonic-gate if (hdrs == NULL) 2689*0Sstevel@tonic-gate return (ENOMEM); 2690*0Sstevel@tonic-gate } else { 2691*0Sstevel@tonic-gate hdrs = NULL; 2692*0Sstevel@tonic-gate } 2693*0Sstevel@tonic-gate if (icmp->icmp_sticky_hdrs_len != 0) { 2694*0Sstevel@tonic-gate kmem_free(icmp->icmp_sticky_hdrs, 2695*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs_len); 2696*0Sstevel@tonic-gate } 2697*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs = hdrs; 2698*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs_len = hdrs_len; 2699*0Sstevel@tonic-gate } 2700*0Sstevel@tonic-gate ip_build_hdrs_v6(icmp->icmp_sticky_hdrs, 2701*0Sstevel@tonic-gate icmp->icmp_sticky_hdrs_len, ipp, icmp->icmp_proto); 2702*0Sstevel@tonic-gate 2703*0Sstevel@tonic-gate /* Set header fields not in ipp */ 2704*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HAS_IP6I) { 2705*0Sstevel@tonic-gate ip6i = (ip6i_t *)icmp->icmp_sticky_hdrs; 2706*0Sstevel@tonic-gate ip6h = (ip6_t *)&ip6i[1]; 2707*0Sstevel@tonic-gate 2708*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_RAW_CKSUM) { 2709*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_RAW_CHECKSUM; 2710*0Sstevel@tonic-gate ip6i->ip6i_checksum_off = icmp->icmp_checksum_off; 2711*0Sstevel@tonic-gate } 2712*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_NO_CKSUM) { 2713*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_NO_ULP_CKSUM; 2714*0Sstevel@tonic-gate } 2715*0Sstevel@tonic-gate } else { 2716*0Sstevel@tonic-gate ip6h = (ip6_t *)icmp->icmp_sticky_hdrs; 2717*0Sstevel@tonic-gate } 2718*0Sstevel@tonic-gate 2719*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_ADDR)) 2720*0Sstevel@tonic-gate ip6h->ip6_src = icmp->icmp_v6src; 2721*0Sstevel@tonic-gate 2722*0Sstevel@tonic-gate /* 2723*0Sstevel@tonic-gate * If IPV6_HOPLIMIT was set in ipp, use that value. 2724*0Sstevel@tonic-gate * For sticky options, if it does not exist use 2725*0Sstevel@tonic-gate * the value in the icmp structure. 2726*0Sstevel@tonic-gate * All this as per RFC 2922. 2727*0Sstevel@tonic-gate */ 2728*0Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_HOPLIMIT)) 2729*0Sstevel@tonic-gate ip6h->ip6_hops = icmp->icmp_ttl; 2730*0Sstevel@tonic-gate 2731*0Sstevel@tonic-gate /* Try to get everything in a single mblk */ 2732*0Sstevel@tonic-gate if (hdrs_len > icmp->icmp_max_hdr_len) { 2733*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = hdrs_len; 2734*0Sstevel@tonic-gate (void) mi_set_sth_wroff(RD(q), icmp->icmp_max_hdr_len + 2735*0Sstevel@tonic-gate icmp_wroff_extra); 2736*0Sstevel@tonic-gate } 2737*0Sstevel@tonic-gate return (0); 2738*0Sstevel@tonic-gate } 2739*0Sstevel@tonic-gate 2740*0Sstevel@tonic-gate /* 2741*0Sstevel@tonic-gate * Set optbuf and optlen for the option. 2742*0Sstevel@tonic-gate * If sticky is set allocate memory (if not already present). 2743*0Sstevel@tonic-gate * Otherwise just point optbuf and optlen at invalp and inlen. 2744*0Sstevel@tonic-gate * Returns failure if memory can not be allocated. 2745*0Sstevel@tonic-gate */ 2746*0Sstevel@tonic-gate static int 2747*0Sstevel@tonic-gate icmp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky, 2748*0Sstevel@tonic-gate uchar_t **optbufp, uint_t *optlenp) 2749*0Sstevel@tonic-gate { 2750*0Sstevel@tonic-gate uchar_t *optbuf; 2751*0Sstevel@tonic-gate 2752*0Sstevel@tonic-gate if (!sticky) { 2753*0Sstevel@tonic-gate *optbufp = invalp; 2754*0Sstevel@tonic-gate *optlenp = inlen; 2755*0Sstevel@tonic-gate return (0); 2756*0Sstevel@tonic-gate } 2757*0Sstevel@tonic-gate if (inlen == *optlenp) { 2758*0Sstevel@tonic-gate /* Unchanged length - no need to realocate */ 2759*0Sstevel@tonic-gate bcopy(invalp, *optbufp, inlen); 2760*0Sstevel@tonic-gate return (0); 2761*0Sstevel@tonic-gate } 2762*0Sstevel@tonic-gate if (inlen != 0) { 2763*0Sstevel@tonic-gate /* Allocate new buffer before free */ 2764*0Sstevel@tonic-gate optbuf = kmem_alloc(inlen, KM_NOSLEEP); 2765*0Sstevel@tonic-gate if (optbuf == NULL) 2766*0Sstevel@tonic-gate return (ENOMEM); 2767*0Sstevel@tonic-gate } else { 2768*0Sstevel@tonic-gate optbuf = NULL; 2769*0Sstevel@tonic-gate } 2770*0Sstevel@tonic-gate /* Free old buffer */ 2771*0Sstevel@tonic-gate if (*optlenp != 0) 2772*0Sstevel@tonic-gate kmem_free(*optbufp, *optlenp); 2773*0Sstevel@tonic-gate 2774*0Sstevel@tonic-gate bcopy(invalp, optbuf, inlen); 2775*0Sstevel@tonic-gate *optbufp = optbuf; 2776*0Sstevel@tonic-gate *optlenp = inlen; 2777*0Sstevel@tonic-gate return (0); 2778*0Sstevel@tonic-gate } 2779*0Sstevel@tonic-gate 2780*0Sstevel@tonic-gate /* 2781*0Sstevel@tonic-gate * This routine retrieves the value of an ND variable in a icmpparam_t 2782*0Sstevel@tonic-gate * structure. It is called through nd_getset when a user reads the 2783*0Sstevel@tonic-gate * variable. 2784*0Sstevel@tonic-gate */ 2785*0Sstevel@tonic-gate /* ARGSUSED */ 2786*0Sstevel@tonic-gate static int 2787*0Sstevel@tonic-gate icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 2788*0Sstevel@tonic-gate { 2789*0Sstevel@tonic-gate icmpparam_t *icmppa = (icmpparam_t *)cp; 2790*0Sstevel@tonic-gate 2791*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "%d", icmppa->icmp_param_value); 2792*0Sstevel@tonic-gate return (0); 2793*0Sstevel@tonic-gate } 2794*0Sstevel@tonic-gate 2795*0Sstevel@tonic-gate /* 2796*0Sstevel@tonic-gate * Walk through the param array specified registering each element with the 2797*0Sstevel@tonic-gate * named dispatch (ND) handler. 2798*0Sstevel@tonic-gate */ 2799*0Sstevel@tonic-gate static boolean_t 2800*0Sstevel@tonic-gate icmp_param_register(icmpparam_t *icmppa, int cnt) 2801*0Sstevel@tonic-gate { 2802*0Sstevel@tonic-gate for (; cnt-- > 0; icmppa++) { 2803*0Sstevel@tonic-gate if (icmppa->icmp_param_name && icmppa->icmp_param_name[0]) { 2804*0Sstevel@tonic-gate if (!nd_load(&icmp_g_nd, icmppa->icmp_param_name, 2805*0Sstevel@tonic-gate icmp_param_get, icmp_param_set, 2806*0Sstevel@tonic-gate (caddr_t)icmppa)) { 2807*0Sstevel@tonic-gate nd_free(&icmp_g_nd); 2808*0Sstevel@tonic-gate return (B_FALSE); 2809*0Sstevel@tonic-gate } 2810*0Sstevel@tonic-gate } 2811*0Sstevel@tonic-gate } 2812*0Sstevel@tonic-gate if (!nd_load(&icmp_g_nd, "icmp_status", icmp_status_report, NULL, 2813*0Sstevel@tonic-gate NULL)) { 2814*0Sstevel@tonic-gate nd_free(&icmp_g_nd); 2815*0Sstevel@tonic-gate return (B_FALSE); 2816*0Sstevel@tonic-gate } 2817*0Sstevel@tonic-gate return (B_TRUE); 2818*0Sstevel@tonic-gate } 2819*0Sstevel@tonic-gate 2820*0Sstevel@tonic-gate /* This routine sets an ND variable in a icmpparam_t structure. */ 2821*0Sstevel@tonic-gate /* ARGSUSED */ 2822*0Sstevel@tonic-gate static int 2823*0Sstevel@tonic-gate icmp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 2824*0Sstevel@tonic-gate { 2825*0Sstevel@tonic-gate long new_value; 2826*0Sstevel@tonic-gate icmpparam_t *icmppa = (icmpparam_t *)cp; 2827*0Sstevel@tonic-gate 2828*0Sstevel@tonic-gate /* 2829*0Sstevel@tonic-gate * Fail the request if the new value does not lie within the 2830*0Sstevel@tonic-gate * required bounds. 2831*0Sstevel@tonic-gate */ 2832*0Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0 || 2833*0Sstevel@tonic-gate new_value < icmppa->icmp_param_min || 2834*0Sstevel@tonic-gate new_value > icmppa->icmp_param_max) { 2835*0Sstevel@tonic-gate return (EINVAL); 2836*0Sstevel@tonic-gate } 2837*0Sstevel@tonic-gate /* Set the new value */ 2838*0Sstevel@tonic-gate icmppa->icmp_param_value = new_value; 2839*0Sstevel@tonic-gate return (0); 2840*0Sstevel@tonic-gate } 2841*0Sstevel@tonic-gate 2842*0Sstevel@tonic-gate static void 2843*0Sstevel@tonic-gate icmp_rput(queue_t *q, mblk_t *mp) 2844*0Sstevel@tonic-gate { 2845*0Sstevel@tonic-gate struct T_unitdata_ind *tudi; 2846*0Sstevel@tonic-gate uchar_t *rptr; 2847*0Sstevel@tonic-gate struct T_error_ack *tea; 2848*0Sstevel@tonic-gate icmp_t *icmp; 2849*0Sstevel@tonic-gate sin_t *sin; 2850*0Sstevel@tonic-gate sin6_t *sin6; 2851*0Sstevel@tonic-gate ip6_t *ip6h; 2852*0Sstevel@tonic-gate ip6i_t *ip6i; 2853*0Sstevel@tonic-gate mblk_t *mp1; 2854*0Sstevel@tonic-gate int hdr_len; 2855*0Sstevel@tonic-gate ipha_t *ipha; 2856*0Sstevel@tonic-gate int udi_size; /* Size of T_unitdata_ind */ 2857*0Sstevel@tonic-gate uint_t ipvers; 2858*0Sstevel@tonic-gate ip6_pkt_t ipp; 2859*0Sstevel@tonic-gate uint8_t nexthdr; 2860*0Sstevel@tonic-gate boolean_t recvif = B_FALSE; 2861*0Sstevel@tonic-gate in_pktinfo_t *pinfo; 2862*0Sstevel@tonic-gate mblk_t *options_mp = NULL; 2863*0Sstevel@tonic-gate uint_t icmp_opt = 0; 2864*0Sstevel@tonic-gate boolean_t icmp_ipv6_recvhoplimit = B_FALSE; 2865*0Sstevel@tonic-gate 2866*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 2867*0Sstevel@tonic-gate if (icmp->icmp_restricted) { 2868*0Sstevel@tonic-gate putnext(q, mp); 2869*0Sstevel@tonic-gate return; 2870*0Sstevel@tonic-gate } 2871*0Sstevel@tonic-gate 2872*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 2873*0Sstevel@tonic-gate /* 2874*0Sstevel@tonic-gate * IP sends up the IPSEC_IN message for handling IPSEC 2875*0Sstevel@tonic-gate * policy at the TCP level. We don't need it here. 2876*0Sstevel@tonic-gate */ 2877*0Sstevel@tonic-gate if (*(uint32_t *)(mp->b_rptr) == IPSEC_IN) { 2878*0Sstevel@tonic-gate mp1 = mp->b_cont; 2879*0Sstevel@tonic-gate freeb(mp); 2880*0Sstevel@tonic-gate mp = mp1; 2881*0Sstevel@tonic-gate } else { 2882*0Sstevel@tonic-gate pinfo = (in_pktinfo_t *)mp->b_rptr; 2883*0Sstevel@tonic-gate if ((icmp->icmp_recvif != 0) && 2884*0Sstevel@tonic-gate (pinfo->in_pkt_ulp_type == IN_PKTINFO)) { 2885*0Sstevel@tonic-gate /* 2886*0Sstevel@tonic-gate * IP has passed the options in mp and the 2887*0Sstevel@tonic-gate * actual data is in b_cont. 2888*0Sstevel@tonic-gate */ 2889*0Sstevel@tonic-gate recvif = B_TRUE; 2890*0Sstevel@tonic-gate /* 2891*0Sstevel@tonic-gate * We are here bcos IP_RECVIF is set so we need 2892*0Sstevel@tonic-gate * to extract the options mblk and adjust the 2893*0Sstevel@tonic-gate * rptr 2894*0Sstevel@tonic-gate */ 2895*0Sstevel@tonic-gate options_mp = mp; 2896*0Sstevel@tonic-gate mp = mp->b_cont; 2897*0Sstevel@tonic-gate } 2898*0Sstevel@tonic-gate } 2899*0Sstevel@tonic-gate } 2900*0Sstevel@tonic-gate 2901*0Sstevel@tonic-gate rptr = mp->b_rptr; 2902*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 2903*0Sstevel@tonic-gate case M_DATA: 2904*0Sstevel@tonic-gate /* 2905*0Sstevel@tonic-gate * M_DATA messages contain IP packets. They are handled 2906*0Sstevel@tonic-gate * following the switch. 2907*0Sstevel@tonic-gate */ 2908*0Sstevel@tonic-gate break; 2909*0Sstevel@tonic-gate case M_PROTO: 2910*0Sstevel@tonic-gate case M_PCPROTO: 2911*0Sstevel@tonic-gate /* M_PROTO messages contain some type of TPI message. */ 2912*0Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (t_scalar_t)) { 2913*0Sstevel@tonic-gate freemsg(mp); 2914*0Sstevel@tonic-gate return; 2915*0Sstevel@tonic-gate } 2916*0Sstevel@tonic-gate tea = (struct T_error_ack *)rptr; 2917*0Sstevel@tonic-gate switch (tea->PRIM_type) { 2918*0Sstevel@tonic-gate case T_ERROR_ACK: 2919*0Sstevel@tonic-gate switch (tea->ERROR_prim) { 2920*0Sstevel@tonic-gate case O_T_BIND_REQ: 2921*0Sstevel@tonic-gate case T_BIND_REQ: 2922*0Sstevel@tonic-gate /* 2923*0Sstevel@tonic-gate * If our O_T_BIND_REQ/T_BIND_REQ fails, 2924*0Sstevel@tonic-gate * clear out the source address before 2925*0Sstevel@tonic-gate * passing the message upstream. 2926*0Sstevel@tonic-gate * If this was caused by a T_CONN_REQ 2927*0Sstevel@tonic-gate * revert back to bound state. 2928*0Sstevel@tonic-gate */ 2929*0Sstevel@tonic-gate if (icmp->icmp_state == TS_UNBND) { 2930*0Sstevel@tonic-gate /* 2931*0Sstevel@tonic-gate * TPI has not yet bound - bind sent by 2932*0Sstevel@tonic-gate * icmp_bind_proto. 2933*0Sstevel@tonic-gate */ 2934*0Sstevel@tonic-gate freemsg(mp); 2935*0Sstevel@tonic-gate return; 2936*0Sstevel@tonic-gate } 2937*0Sstevel@tonic-gate if (icmp->icmp_state == TS_DATA_XFER) { 2938*0Sstevel@tonic-gate /* Connect failed */ 2939*0Sstevel@tonic-gate tea->ERROR_prim = T_CONN_REQ; 2940*0Sstevel@tonic-gate icmp->icmp_v6src = 2941*0Sstevel@tonic-gate icmp->icmp_bound_v6src; 2942*0Sstevel@tonic-gate icmp->icmp_state = TS_IDLE; 2943*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) 2944*0Sstevel@tonic-gate (void) icmp_build_hdrs(q, icmp); 2945*0Sstevel@tonic-gate break; 2946*0Sstevel@tonic-gate } 2947*0Sstevel@tonic-gate 2948*0Sstevel@tonic-gate if (icmp->icmp_discon_pending) { 2949*0Sstevel@tonic-gate tea->ERROR_prim = T_DISCON_REQ; 2950*0Sstevel@tonic-gate icmp->icmp_discon_pending = 0; 2951*0Sstevel@tonic-gate } 2952*0Sstevel@tonic-gate V6_SET_ZERO(icmp->icmp_v6src); 2953*0Sstevel@tonic-gate V6_SET_ZERO(icmp->icmp_bound_v6src); 2954*0Sstevel@tonic-gate icmp->icmp_state = TS_UNBND; 2955*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) 2956*0Sstevel@tonic-gate (void) icmp_build_hdrs(q, icmp); 2957*0Sstevel@tonic-gate break; 2958*0Sstevel@tonic-gate default: 2959*0Sstevel@tonic-gate break; 2960*0Sstevel@tonic-gate } 2961*0Sstevel@tonic-gate break; 2962*0Sstevel@tonic-gate case T_BIND_ACK: 2963*0Sstevel@tonic-gate icmp_rput_bind_ack(q, mp); 2964*0Sstevel@tonic-gate return; 2965*0Sstevel@tonic-gate 2966*0Sstevel@tonic-gate case T_OPTMGMT_ACK: 2967*0Sstevel@tonic-gate case T_OK_ACK: 2968*0Sstevel@tonic-gate if (tea->PRIM_type == T_OK_ACK) { 2969*0Sstevel@tonic-gate struct T_ok_ack *toa; 2970*0Sstevel@tonic-gate toa = (struct T_ok_ack *)rptr; 2971*0Sstevel@tonic-gate if (toa->CORRECT_prim == T_UNBIND_REQ) { 2972*0Sstevel@tonic-gate /* 2973*0Sstevel@tonic-gate * If somebody sets IPSEC options, IP 2974*0Sstevel@tonic-gate * sends some IPSEC info which is used 2975*0Sstevel@tonic-gate * by the TCP for detached connections. 2976*0Sstevel@tonic-gate * We don't need it here. 2977*0Sstevel@tonic-gate */ 2978*0Sstevel@tonic-gate if ((mp1 = mp->b_cont) != NULL) { 2979*0Sstevel@tonic-gate freemsg(mp1); 2980*0Sstevel@tonic-gate mp->b_cont = NULL; 2981*0Sstevel@tonic-gate } 2982*0Sstevel@tonic-gate } 2983*0Sstevel@tonic-gate } 2984*0Sstevel@tonic-gate break; 2985*0Sstevel@tonic-gate default: 2986*0Sstevel@tonic-gate freemsg(mp); 2987*0Sstevel@tonic-gate return; 2988*0Sstevel@tonic-gate } 2989*0Sstevel@tonic-gate putnext(q, mp); 2990*0Sstevel@tonic-gate return; 2991*0Sstevel@tonic-gate case M_CTL: 2992*0Sstevel@tonic-gate if (recvif) { 2993*0Sstevel@tonic-gate /* 2994*0Sstevel@tonic-gate * IP has passed the options in mp and the actual data 2995*0Sstevel@tonic-gate * is in b_cont. Jump to normal data processing. 2996*0Sstevel@tonic-gate */ 2997*0Sstevel@tonic-gate break; 2998*0Sstevel@tonic-gate } 2999*0Sstevel@tonic-gate 3000*0Sstevel@tonic-gate /* Contains ICMP packet from IP */ 3001*0Sstevel@tonic-gate icmp_icmp_error(q, mp); 3002*0Sstevel@tonic-gate return; 3003*0Sstevel@tonic-gate default: 3004*0Sstevel@tonic-gate putnext(q, mp); 3005*0Sstevel@tonic-gate return; 3006*0Sstevel@tonic-gate } 3007*0Sstevel@tonic-gate 3008*0Sstevel@tonic-gate /* 3009*0Sstevel@tonic-gate * Discard message if it is misaligned or smaller than the IP header. 3010*0Sstevel@tonic-gate */ 3011*0Sstevel@tonic-gate if (!OK_32PTR(rptr) || (mp->b_wptr - rptr) < sizeof (ipha_t)) { 3012*0Sstevel@tonic-gate freemsg(mp); 3013*0Sstevel@tonic-gate if (options_mp != NULL) 3014*0Sstevel@tonic-gate freeb(options_mp); 3015*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 3016*0Sstevel@tonic-gate return; 3017*0Sstevel@tonic-gate } 3018*0Sstevel@tonic-gate ipvers = IPH_HDR_VERSION((ipha_t *)rptr); 3019*0Sstevel@tonic-gate 3020*0Sstevel@tonic-gate /* Handle M_DATA messages containing IP packets messages */ 3021*0Sstevel@tonic-gate if (ipvers == IPV4_VERSION) { 3022*0Sstevel@tonic-gate /* 3023*0Sstevel@tonic-gate * Special case where IP attaches 3024*0Sstevel@tonic-gate * the IRE needs to be handled so that we don't send up 3025*0Sstevel@tonic-gate * IRE to the user land. 3026*0Sstevel@tonic-gate */ 3027*0Sstevel@tonic-gate ipha = (ipha_t *)rptr; 3028*0Sstevel@tonic-gate hdr_len = IPH_HDR_LENGTH(ipha); 3029*0Sstevel@tonic-gate 3030*0Sstevel@tonic-gate if (ipha->ipha_protocol == IPPROTO_TCP) { 3031*0Sstevel@tonic-gate tcph_t *tcph = (tcph_t *)&mp->b_rptr[hdr_len]; 3032*0Sstevel@tonic-gate 3033*0Sstevel@tonic-gate if (((tcph->th_flags[0] & (TH_SYN|TH_ACK)) == 3034*0Sstevel@tonic-gate TH_SYN) && mp->b_cont != NULL) { 3035*0Sstevel@tonic-gate mp1 = mp->b_cont; 3036*0Sstevel@tonic-gate if (mp1->b_datap->db_type == IRE_DB_TYPE) { 3037*0Sstevel@tonic-gate freeb(mp1); 3038*0Sstevel@tonic-gate mp->b_cont = NULL; 3039*0Sstevel@tonic-gate } 3040*0Sstevel@tonic-gate } 3041*0Sstevel@tonic-gate } 3042*0Sstevel@tonic-gate if (icmp_bsd_compat) { 3043*0Sstevel@tonic-gate ushort_t len; 3044*0Sstevel@tonic-gate len = ntohs(ipha->ipha_length); 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate if (mp->b_datap->db_ref > 1) { 3047*0Sstevel@tonic-gate /* 3048*0Sstevel@tonic-gate * Allocate a new IP header so that we can 3049*0Sstevel@tonic-gate * modify ipha_length. 3050*0Sstevel@tonic-gate */ 3051*0Sstevel@tonic-gate mblk_t *mp1; 3052*0Sstevel@tonic-gate 3053*0Sstevel@tonic-gate mp1 = allocb(hdr_len, BPRI_MED); 3054*0Sstevel@tonic-gate if (!mp1) { 3055*0Sstevel@tonic-gate freemsg(mp); 3056*0Sstevel@tonic-gate if (options_mp != NULL) 3057*0Sstevel@tonic-gate freeb(options_mp); 3058*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 3059*0Sstevel@tonic-gate return; 3060*0Sstevel@tonic-gate } 3061*0Sstevel@tonic-gate bcopy(rptr, mp1->b_rptr, hdr_len); 3062*0Sstevel@tonic-gate mp->b_rptr = rptr + hdr_len; 3063*0Sstevel@tonic-gate rptr = mp1->b_rptr; 3064*0Sstevel@tonic-gate ipha = (ipha_t *)rptr; 3065*0Sstevel@tonic-gate mp1->b_cont = mp; 3066*0Sstevel@tonic-gate mp1->b_wptr = rptr + hdr_len; 3067*0Sstevel@tonic-gate mp = mp1; 3068*0Sstevel@tonic-gate } 3069*0Sstevel@tonic-gate len -= hdr_len; 3070*0Sstevel@tonic-gate ipha->ipha_length = htons(len); 3071*0Sstevel@tonic-gate } 3072*0Sstevel@tonic-gate } 3073*0Sstevel@tonic-gate 3074*0Sstevel@tonic-gate /* 3075*0Sstevel@tonic-gate * This is the inbound data path. Packets are passed upstream as 3076*0Sstevel@tonic-gate * T_UNITDATA_IND messages with full IP headers still attached. 3077*0Sstevel@tonic-gate */ 3078*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 3079*0Sstevel@tonic-gate ASSERT(ipvers == IPV4_VERSION); 3080*0Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin_t); 3081*0Sstevel@tonic-gate if (recvif) { 3082*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3083*0Sstevel@tonic-gate sizeof (uint_t); 3084*0Sstevel@tonic-gate } 3085*0Sstevel@tonic-gate mp1 = allocb(udi_size, BPRI_MED); 3086*0Sstevel@tonic-gate if (mp1 == NULL) { 3087*0Sstevel@tonic-gate freemsg(mp); 3088*0Sstevel@tonic-gate if (options_mp != NULL) 3089*0Sstevel@tonic-gate freeb(options_mp); 3090*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 3091*0Sstevel@tonic-gate return; 3092*0Sstevel@tonic-gate } 3093*0Sstevel@tonic-gate mp1->b_cont = mp; 3094*0Sstevel@tonic-gate mp = mp1; 3095*0Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp->b_rptr; 3096*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 3097*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)tudi + udi_size; 3098*0Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 3099*0Sstevel@tonic-gate tudi->SRC_length = sizeof (sin_t); 3100*0Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 3101*0Sstevel@tonic-gate sin = (sin_t *)&tudi[1]; 3102*0Sstevel@tonic-gate *sin = sin_null; 3103*0Sstevel@tonic-gate sin->sin_family = AF_INET; 3104*0Sstevel@tonic-gate sin->sin_addr.s_addr = ipha->ipha_src; 3105*0Sstevel@tonic-gate tudi->OPT_offset = sizeof (struct T_unitdata_ind) + 3106*0Sstevel@tonic-gate sizeof (sin_t); 3107*0Sstevel@tonic-gate udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin_t)); 3108*0Sstevel@tonic-gate tudi->OPT_length = udi_size; 3109*0Sstevel@tonic-gate 3110*0Sstevel@tonic-gate /* 3111*0Sstevel@tonic-gate * Add options if IP_RECVIF is set 3112*0Sstevel@tonic-gate */ 3113*0Sstevel@tonic-gate if (udi_size != 0) { 3114*0Sstevel@tonic-gate char *dstopt; 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate dstopt = (char *)&sin[1]; 3117*0Sstevel@tonic-gate if (recvif) { 3118*0Sstevel@tonic-gate 3119*0Sstevel@tonic-gate struct T_opthdr *toh; 3120*0Sstevel@tonic-gate uint_t *dstptr; 3121*0Sstevel@tonic-gate 3122*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3123*0Sstevel@tonic-gate toh->level = IPPROTO_IP; 3124*0Sstevel@tonic-gate toh->name = IP_RECVIF; 3125*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3126*0Sstevel@tonic-gate sizeof (uint_t); 3127*0Sstevel@tonic-gate toh->status = 0; 3128*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3129*0Sstevel@tonic-gate dstptr = (uint_t *)dstopt; 3130*0Sstevel@tonic-gate *dstptr = pinfo->in_pkt_ifindex; 3131*0Sstevel@tonic-gate dstopt += sizeof (uint_t); 3132*0Sstevel@tonic-gate freeb(options_mp); 3133*0Sstevel@tonic-gate udi_size -= toh->len; 3134*0Sstevel@tonic-gate } 3135*0Sstevel@tonic-gate 3136*0Sstevel@tonic-gate /* Consumed all of allocated space */ 3137*0Sstevel@tonic-gate ASSERT(udi_size == 0); 3138*0Sstevel@tonic-gate } 3139*0Sstevel@tonic-gate 3140*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInDatagrams); 3141*0Sstevel@tonic-gate putnext(q, mp); 3142*0Sstevel@tonic-gate return; 3143*0Sstevel@tonic-gate } 3144*0Sstevel@tonic-gate 3145*0Sstevel@tonic-gate /* 3146*0Sstevel@tonic-gate * We don't need options_mp in the IPv6 path. 3147*0Sstevel@tonic-gate */ 3148*0Sstevel@tonic-gate if (options_mp != NULL) { 3149*0Sstevel@tonic-gate freeb(options_mp); 3150*0Sstevel@tonic-gate options_mp = NULL; 3151*0Sstevel@tonic-gate } 3152*0Sstevel@tonic-gate 3153*0Sstevel@tonic-gate /* 3154*0Sstevel@tonic-gate * Discard message if it is smaller than the IPv6 header 3155*0Sstevel@tonic-gate * or if the header is malformed. 3156*0Sstevel@tonic-gate */ 3157*0Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (ip6_t) || 3158*0Sstevel@tonic-gate IPH_HDR_VERSION((ipha_t *)rptr) != IPV6_VERSION || 3159*0Sstevel@tonic-gate icmp->icmp_family != AF_INET6) { 3160*0Sstevel@tonic-gate freemsg(mp); 3161*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 3162*0Sstevel@tonic-gate return; 3163*0Sstevel@tonic-gate } 3164*0Sstevel@tonic-gate 3165*0Sstevel@tonic-gate /* Initialize */ 3166*0Sstevel@tonic-gate ipp.ipp_fields = 0; 3167*0Sstevel@tonic-gate 3168*0Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 3169*0Sstevel@tonic-gate /* 3170*0Sstevel@tonic-gate * Call on ip_find_hdr_v6 which gets the total hdr len 3171*0Sstevel@tonic-gate * as well as individual lenghts of ext hdrs (and ptrs to 3172*0Sstevel@tonic-gate * them). 3173*0Sstevel@tonic-gate */ 3174*0Sstevel@tonic-gate if (ip6h->ip6_nxt != icmp->icmp_proto) { 3175*0Sstevel@tonic-gate /* Look for ifindex information */ 3176*0Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 3177*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 3178*0Sstevel@tonic-gate if (ip6i->ip6i_flags & IP6I_IFINDEX) { 3179*0Sstevel@tonic-gate ASSERT(ip6i->ip6i_ifindex != 0); 3180*0Sstevel@tonic-gate ipp.ipp_fields |= IPPF_IFINDEX; 3181*0Sstevel@tonic-gate ipp.ipp_ifindex = ip6i->ip6i_ifindex; 3182*0Sstevel@tonic-gate } 3183*0Sstevel@tonic-gate rptr = (uchar_t *)&ip6i[1]; 3184*0Sstevel@tonic-gate mp->b_rptr = rptr; 3185*0Sstevel@tonic-gate if (rptr == mp->b_wptr) { 3186*0Sstevel@tonic-gate mp1 = mp->b_cont; 3187*0Sstevel@tonic-gate freeb(mp); 3188*0Sstevel@tonic-gate mp = mp1; 3189*0Sstevel@tonic-gate rptr = mp->b_rptr; 3190*0Sstevel@tonic-gate } 3191*0Sstevel@tonic-gate ASSERT(mp->b_wptr - rptr >= IPV6_HDR_LEN); 3192*0Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 3193*0Sstevel@tonic-gate } 3194*0Sstevel@tonic-gate hdr_len = ip_find_hdr_v6(mp, ip6h, &ipp, &nexthdr); 3195*0Sstevel@tonic-gate } else { 3196*0Sstevel@tonic-gate hdr_len = IPV6_HDR_LEN; 3197*0Sstevel@tonic-gate ip6i = NULL; 3198*0Sstevel@tonic-gate nexthdr = ip6h->ip6_nxt; 3199*0Sstevel@tonic-gate } 3200*0Sstevel@tonic-gate /* 3201*0Sstevel@tonic-gate * One special case where IP attaches the IRE needs to 3202*0Sstevel@tonic-gate * be handled so that we don't send up IRE to the user land. 3203*0Sstevel@tonic-gate */ 3204*0Sstevel@tonic-gate if (nexthdr == IPPROTO_TCP) { 3205*0Sstevel@tonic-gate tcph_t *tcph = (tcph_t *)&mp->b_rptr[hdr_len]; 3206*0Sstevel@tonic-gate 3207*0Sstevel@tonic-gate if (((tcph->th_flags[0] & (TH_SYN|TH_ACK)) == TH_SYN) && 3208*0Sstevel@tonic-gate mp->b_cont != NULL) { 3209*0Sstevel@tonic-gate mp1 = mp->b_cont; 3210*0Sstevel@tonic-gate if (mp1->b_datap->db_type == IRE_DB_TYPE) { 3211*0Sstevel@tonic-gate freeb(mp1); 3212*0Sstevel@tonic-gate mp->b_cont = NULL; 3213*0Sstevel@tonic-gate } 3214*0Sstevel@tonic-gate } 3215*0Sstevel@tonic-gate } 3216*0Sstevel@tonic-gate /* 3217*0Sstevel@tonic-gate * Check a filter for ICMPv6 types if needed. 3218*0Sstevel@tonic-gate * Verify raw checksums if needed. 3219*0Sstevel@tonic-gate */ 3220*0Sstevel@tonic-gate if (icmp->icmp_filter != NULL || icmp->icmp_raw_checksum) { 3221*0Sstevel@tonic-gate if (icmp->icmp_filter != NULL) { 3222*0Sstevel@tonic-gate int type; 3223*0Sstevel@tonic-gate 3224*0Sstevel@tonic-gate /* Assumes that IP has done the pullupmsg */ 3225*0Sstevel@tonic-gate type = mp->b_rptr[hdr_len]; 3226*0Sstevel@tonic-gate 3227*0Sstevel@tonic-gate ASSERT(mp->b_rptr + hdr_len <= mp->b_wptr); 3228*0Sstevel@tonic-gate if (ICMP6_FILTER_WILLBLOCK(type, icmp->icmp_filter)) { 3229*0Sstevel@tonic-gate freemsg(mp); 3230*0Sstevel@tonic-gate return; 3231*0Sstevel@tonic-gate } 3232*0Sstevel@tonic-gate } else { 3233*0Sstevel@tonic-gate /* Checksum */ 3234*0Sstevel@tonic-gate uint16_t *up; 3235*0Sstevel@tonic-gate uint32_t sum; 3236*0Sstevel@tonic-gate int remlen; 3237*0Sstevel@tonic-gate 3238*0Sstevel@tonic-gate up = (uint16_t *)&ip6h->ip6_src; 3239*0Sstevel@tonic-gate 3240*0Sstevel@tonic-gate remlen = msgdsize(mp) - hdr_len; 3241*0Sstevel@tonic-gate sum = htons(icmp->icmp_proto + remlen) 3242*0Sstevel@tonic-gate + up[0] + up[1] + up[2] + up[3] 3243*0Sstevel@tonic-gate + up[4] + up[5] + up[6] + up[7] 3244*0Sstevel@tonic-gate + up[8] + up[9] + up[10] + up[11] 3245*0Sstevel@tonic-gate + up[12] + up[13] + up[14] + up[15]; 3246*0Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 3247*0Sstevel@tonic-gate sum = IP_CSUM(mp, hdr_len, sum); 3248*0Sstevel@tonic-gate if (sum != 0) { 3249*0Sstevel@tonic-gate /* IPv6 RAW checksum failed */ 3250*0Sstevel@tonic-gate ip0dbg(("icmp_rput: RAW checksum " 3251*0Sstevel@tonic-gate "failed %x\n", sum)); 3252*0Sstevel@tonic-gate freemsg(mp); 3253*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInCksumErrs); 3254*0Sstevel@tonic-gate return; 3255*0Sstevel@tonic-gate } 3256*0Sstevel@tonic-gate } 3257*0Sstevel@tonic-gate } 3258*0Sstevel@tonic-gate /* Skip all the IPv6 headers per API */ 3259*0Sstevel@tonic-gate mp->b_rptr += hdr_len; 3260*0Sstevel@tonic-gate 3261*0Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t); 3262*0Sstevel@tonic-gate 3263*0Sstevel@tonic-gate /* 3264*0Sstevel@tonic-gate * We use local variables icmp_opt and icmp_ipv6_recvhoplimit to 3265*0Sstevel@tonic-gate * maintain state information, instead of relying on icmp_t 3266*0Sstevel@tonic-gate * structure, since there arent any locks protecting these members 3267*0Sstevel@tonic-gate * and there is a window where there might be a race between a 3268*0Sstevel@tonic-gate * thread setting options on the write side and a thread reading 3269*0Sstevel@tonic-gate * these options on the read size. 3270*0Sstevel@tonic-gate */ 3271*0Sstevel@tonic-gate if (ipp.ipp_fields & (IPPF_HOPOPTS|IPPF_DSTOPTS|IPPF_RTDSTOPTS| 3272*0Sstevel@tonic-gate IPPF_RTHDR|IPPF_IFINDEX)) { 3273*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvhopopts && 3274*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_HOPOPTS)) { 3275*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3276*0Sstevel@tonic-gate ipp.ipp_hopoptslen; 3277*0Sstevel@tonic-gate icmp_opt |= IPPF_HOPOPTS; 3278*0Sstevel@tonic-gate } 3279*0Sstevel@tonic-gate if ((icmp->icmp_ipv6_recvdstopts || 3280*0Sstevel@tonic-gate icmp->icmp_old_ipv6_recvdstopts) && 3281*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_DSTOPTS)) { 3282*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3283*0Sstevel@tonic-gate ipp.ipp_dstoptslen; 3284*0Sstevel@tonic-gate icmp_opt |= IPPF_DSTOPTS; 3285*0Sstevel@tonic-gate } 3286*0Sstevel@tonic-gate if (((icmp->icmp_ipv6_recvdstopts && 3287*0Sstevel@tonic-gate icmp->icmp_ipv6_recvrthdr && 3288*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR)) || 3289*0Sstevel@tonic-gate icmp->icmp_ipv6_recvrtdstopts) && 3290*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTDSTOPTS)) { 3291*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3292*0Sstevel@tonic-gate ipp.ipp_rtdstoptslen; 3293*0Sstevel@tonic-gate icmp_opt |= IPPF_RTDSTOPTS; 3294*0Sstevel@tonic-gate } 3295*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvrthdr && 3296*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR)) { 3297*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3298*0Sstevel@tonic-gate ipp.ipp_rthdrlen; 3299*0Sstevel@tonic-gate icmp_opt |= IPPF_RTHDR; 3300*0Sstevel@tonic-gate } 3301*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvpktinfo && 3302*0Sstevel@tonic-gate (ipp.ipp_fields & IPPF_IFINDEX)) { 3303*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 3304*0Sstevel@tonic-gate sizeof (struct in6_pktinfo); 3305*0Sstevel@tonic-gate icmp_opt |= IPPF_IFINDEX; 3306*0Sstevel@tonic-gate } 3307*0Sstevel@tonic-gate } 3308*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvhoplimit) { 3309*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (int); 3310*0Sstevel@tonic-gate icmp_ipv6_recvhoplimit = B_TRUE; 3311*0Sstevel@tonic-gate } 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvtclass) 3314*0Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (int); 3315*0Sstevel@tonic-gate 3316*0Sstevel@tonic-gate mp1 = allocb(udi_size, BPRI_MED); 3317*0Sstevel@tonic-gate if (mp1 == NULL) { 3318*0Sstevel@tonic-gate freemsg(mp); 3319*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInErrors); 3320*0Sstevel@tonic-gate return; 3321*0Sstevel@tonic-gate } 3322*0Sstevel@tonic-gate mp1->b_cont = mp; 3323*0Sstevel@tonic-gate mp = mp1; 3324*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 3325*0Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp->b_rptr; 3326*0Sstevel@tonic-gate mp->b_wptr = (uchar_t *)tudi + udi_size; 3327*0Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 3328*0Sstevel@tonic-gate tudi->SRC_length = sizeof (sin6_t); 3329*0Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 3330*0Sstevel@tonic-gate tudi->OPT_offset = sizeof (struct T_unitdata_ind) + sizeof (sin6_t); 3331*0Sstevel@tonic-gate udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin6_t)); 3332*0Sstevel@tonic-gate tudi->OPT_length = udi_size; 3333*0Sstevel@tonic-gate sin6 = (sin6_t *)&tudi[1]; 3334*0Sstevel@tonic-gate sin6->sin6_port = 0; 3335*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 3336*0Sstevel@tonic-gate 3337*0Sstevel@tonic-gate sin6->sin6_addr = ip6h->ip6_src; 3338*0Sstevel@tonic-gate /* No sin6_flowinfo per API */ 3339*0Sstevel@tonic-gate sin6->sin6_flowinfo = 0; 3340*0Sstevel@tonic-gate /* For link-scope source pass up scope id */ 3341*0Sstevel@tonic-gate if ((ipp.ipp_fields & IPPF_IFINDEX) && 3342*0Sstevel@tonic-gate IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) 3343*0Sstevel@tonic-gate sin6->sin6_scope_id = ipp.ipp_ifindex; 3344*0Sstevel@tonic-gate else 3345*0Sstevel@tonic-gate sin6->sin6_scope_id = 0; 3346*0Sstevel@tonic-gate 3347*0Sstevel@tonic-gate sin6->__sin6_src_id = ip_srcid_find_addr(&ip6h->ip6_dst, 3348*0Sstevel@tonic-gate icmp->icmp_zoneid); 3349*0Sstevel@tonic-gate 3350*0Sstevel@tonic-gate if (udi_size != 0) { 3351*0Sstevel@tonic-gate uchar_t *dstopt; 3352*0Sstevel@tonic-gate 3353*0Sstevel@tonic-gate dstopt = (uchar_t *)&sin6[1]; 3354*0Sstevel@tonic-gate if (icmp_opt & IPPF_IFINDEX) { 3355*0Sstevel@tonic-gate struct T_opthdr *toh; 3356*0Sstevel@tonic-gate struct in6_pktinfo *pkti; 3357*0Sstevel@tonic-gate 3358*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3359*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3360*0Sstevel@tonic-gate toh->name = IPV6_PKTINFO; 3361*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3362*0Sstevel@tonic-gate sizeof (*pkti); 3363*0Sstevel@tonic-gate toh->status = 0; 3364*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3365*0Sstevel@tonic-gate pkti = (struct in6_pktinfo *)dstopt; 3366*0Sstevel@tonic-gate pkti->ipi6_addr = ip6h->ip6_dst; 3367*0Sstevel@tonic-gate pkti->ipi6_ifindex = ipp.ipp_ifindex; 3368*0Sstevel@tonic-gate dstopt += sizeof (*pkti); 3369*0Sstevel@tonic-gate udi_size -= toh->len; 3370*0Sstevel@tonic-gate } 3371*0Sstevel@tonic-gate if (icmp_ipv6_recvhoplimit) { 3372*0Sstevel@tonic-gate struct T_opthdr *toh; 3373*0Sstevel@tonic-gate 3374*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3375*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3376*0Sstevel@tonic-gate toh->name = IPV6_HOPLIMIT; 3377*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3378*0Sstevel@tonic-gate sizeof (uint_t); 3379*0Sstevel@tonic-gate toh->status = 0; 3380*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3381*0Sstevel@tonic-gate *(uint_t *)dstopt = ip6h->ip6_hops; 3382*0Sstevel@tonic-gate dstopt += sizeof (uint_t); 3383*0Sstevel@tonic-gate udi_size -= toh->len; 3384*0Sstevel@tonic-gate } 3385*0Sstevel@tonic-gate if (icmp->icmp_ipv6_recvtclass) { 3386*0Sstevel@tonic-gate struct T_opthdr *toh; 3387*0Sstevel@tonic-gate 3388*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3389*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3390*0Sstevel@tonic-gate toh->name = IPV6_TCLASS; 3391*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3392*0Sstevel@tonic-gate sizeof (uint_t); 3393*0Sstevel@tonic-gate toh->status = 0; 3394*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3395*0Sstevel@tonic-gate *(uint_t *)dstopt = IPV6_FLOW_TCLASS(ip6h->ip6_flow); 3396*0Sstevel@tonic-gate dstopt += sizeof (uint_t); 3397*0Sstevel@tonic-gate udi_size -= toh->len; 3398*0Sstevel@tonic-gate } 3399*0Sstevel@tonic-gate if (icmp_opt & IPPF_HOPOPTS) { 3400*0Sstevel@tonic-gate struct T_opthdr *toh; 3401*0Sstevel@tonic-gate 3402*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3403*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3404*0Sstevel@tonic-gate toh->name = IPV6_HOPOPTS; 3405*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3406*0Sstevel@tonic-gate ipp.ipp_hopoptslen; 3407*0Sstevel@tonic-gate toh->status = 0; 3408*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3409*0Sstevel@tonic-gate bcopy(ipp.ipp_hopopts, dstopt, 3410*0Sstevel@tonic-gate ipp.ipp_hopoptslen); 3411*0Sstevel@tonic-gate dstopt += ipp.ipp_hopoptslen; 3412*0Sstevel@tonic-gate udi_size -= toh->len; 3413*0Sstevel@tonic-gate } 3414*0Sstevel@tonic-gate if (icmp_opt & IPPF_RTDSTOPTS) { 3415*0Sstevel@tonic-gate struct T_opthdr *toh; 3416*0Sstevel@tonic-gate 3417*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3418*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3419*0Sstevel@tonic-gate toh->name = IPV6_DSTOPTS; 3420*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3421*0Sstevel@tonic-gate ipp.ipp_rtdstoptslen; 3422*0Sstevel@tonic-gate toh->status = 0; 3423*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3424*0Sstevel@tonic-gate bcopy(ipp.ipp_rtdstopts, dstopt, 3425*0Sstevel@tonic-gate ipp.ipp_rtdstoptslen); 3426*0Sstevel@tonic-gate dstopt += ipp.ipp_rtdstoptslen; 3427*0Sstevel@tonic-gate udi_size -= toh->len; 3428*0Sstevel@tonic-gate } 3429*0Sstevel@tonic-gate if (icmp_opt & IPPF_RTHDR) { 3430*0Sstevel@tonic-gate struct T_opthdr *toh; 3431*0Sstevel@tonic-gate 3432*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3433*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3434*0Sstevel@tonic-gate toh->name = IPV6_RTHDR; 3435*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3436*0Sstevel@tonic-gate ipp.ipp_rthdrlen; 3437*0Sstevel@tonic-gate toh->status = 0; 3438*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3439*0Sstevel@tonic-gate bcopy(ipp.ipp_rthdr, dstopt, ipp.ipp_rthdrlen); 3440*0Sstevel@tonic-gate dstopt += ipp.ipp_rthdrlen; 3441*0Sstevel@tonic-gate udi_size -= toh->len; 3442*0Sstevel@tonic-gate } 3443*0Sstevel@tonic-gate if (icmp_opt & IPPF_DSTOPTS) { 3444*0Sstevel@tonic-gate struct T_opthdr *toh; 3445*0Sstevel@tonic-gate 3446*0Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 3447*0Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 3448*0Sstevel@tonic-gate toh->name = IPV6_DSTOPTS; 3449*0Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 3450*0Sstevel@tonic-gate ipp.ipp_dstoptslen; 3451*0Sstevel@tonic-gate toh->status = 0; 3452*0Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 3453*0Sstevel@tonic-gate bcopy(ipp.ipp_dstopts, dstopt, 3454*0Sstevel@tonic-gate ipp.ipp_dstoptslen); 3455*0Sstevel@tonic-gate dstopt += ipp.ipp_dstoptslen; 3456*0Sstevel@tonic-gate udi_size -= toh->len; 3457*0Sstevel@tonic-gate } 3458*0Sstevel@tonic-gate /* Consumed all of allocated space */ 3459*0Sstevel@tonic-gate ASSERT(udi_size == 0); 3460*0Sstevel@tonic-gate } 3461*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipInDatagrams); 3462*0Sstevel@tonic-gate putnext(q, mp); 3463*0Sstevel@tonic-gate } 3464*0Sstevel@tonic-gate 3465*0Sstevel@tonic-gate /* 3466*0Sstevel@tonic-gate * Process a T_BIND_ACK 3467*0Sstevel@tonic-gate */ 3468*0Sstevel@tonic-gate static void 3469*0Sstevel@tonic-gate icmp_rput_bind_ack(queue_t *q, mblk_t *mp) 3470*0Sstevel@tonic-gate { 3471*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 3472*0Sstevel@tonic-gate mblk_t *mp1; 3473*0Sstevel@tonic-gate ire_t *ire; 3474*0Sstevel@tonic-gate struct T_bind_ack *tba; 3475*0Sstevel@tonic-gate uchar_t *addrp; 3476*0Sstevel@tonic-gate ipa_conn_t *ac; 3477*0Sstevel@tonic-gate ipa6_conn_t *ac6; 3478*0Sstevel@tonic-gate 3479*0Sstevel@tonic-gate /* 3480*0Sstevel@tonic-gate * We know if headers are included or not so we can 3481*0Sstevel@tonic-gate * safely do this. 3482*0Sstevel@tonic-gate */ 3483*0Sstevel@tonic-gate if (icmp->icmp_state == TS_UNBND) { 3484*0Sstevel@tonic-gate /* 3485*0Sstevel@tonic-gate * TPI has not yet bound - bind sent by 3486*0Sstevel@tonic-gate * icmp_bind_proto. 3487*0Sstevel@tonic-gate */ 3488*0Sstevel@tonic-gate freemsg(mp); 3489*0Sstevel@tonic-gate return; 3490*0Sstevel@tonic-gate } 3491*0Sstevel@tonic-gate if (icmp->icmp_discon_pending) 3492*0Sstevel@tonic-gate icmp->icmp_discon_pending = 0; 3493*0Sstevel@tonic-gate 3494*0Sstevel@tonic-gate /* 3495*0Sstevel@tonic-gate * If a broadcast/multicast address was bound set 3496*0Sstevel@tonic-gate * the source address to 0. 3497*0Sstevel@tonic-gate * This ensures no datagrams with broadcast address 3498*0Sstevel@tonic-gate * as source address are emitted (which would violate 3499*0Sstevel@tonic-gate * RFC1122 - Hosts requirements) 3500*0Sstevel@tonic-gate * 3501*0Sstevel@tonic-gate * Note that when connecting the returned IRE is 3502*0Sstevel@tonic-gate * for the destination address and we only perform 3503*0Sstevel@tonic-gate * the broadcast check for the source address (it 3504*0Sstevel@tonic-gate * is OK to connect to a broadcast/multicast address.) 3505*0Sstevel@tonic-gate */ 3506*0Sstevel@tonic-gate mp1 = mp->b_cont; 3507*0Sstevel@tonic-gate if (mp1 != NULL && mp1->b_datap->db_type == IRE_DB_TYPE) { 3508*0Sstevel@tonic-gate ire = (ire_t *)mp1->b_rptr; 3509*0Sstevel@tonic-gate 3510*0Sstevel@tonic-gate /* 3511*0Sstevel@tonic-gate * Note: we get IRE_BROADCAST for IPv6 to "mark" a multicast 3512*0Sstevel@tonic-gate * local address. 3513*0Sstevel@tonic-gate */ 3514*0Sstevel@tonic-gate if (ire->ire_type == IRE_BROADCAST && 3515*0Sstevel@tonic-gate icmp->icmp_state != TS_DATA_XFER) { 3516*0Sstevel@tonic-gate /* This was just a local bind to a MC/broadcast addr */ 3517*0Sstevel@tonic-gate V6_SET_ZERO(icmp->icmp_v6src); 3518*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) 3519*0Sstevel@tonic-gate (void) icmp_build_hdrs(q, icmp); 3520*0Sstevel@tonic-gate } else if (V6_OR_V4_INADDR_ANY(icmp->icmp_v6src)) { 3521*0Sstevel@tonic-gate /* 3522*0Sstevel@tonic-gate * Local address not yet set - pick it from the 3523*0Sstevel@tonic-gate * T_bind_ack 3524*0Sstevel@tonic-gate */ 3525*0Sstevel@tonic-gate tba = (struct T_bind_ack *)mp->b_rptr; 3526*0Sstevel@tonic-gate addrp = &mp->b_rptr[tba->ADDR_offset]; 3527*0Sstevel@tonic-gate switch (icmp->icmp_family) { 3528*0Sstevel@tonic-gate case AF_INET: 3529*0Sstevel@tonic-gate if (tba->ADDR_length == sizeof (ipa_conn_t)) { 3530*0Sstevel@tonic-gate ac = (ipa_conn_t *)addrp; 3531*0Sstevel@tonic-gate } else { 3532*0Sstevel@tonic-gate ASSERT(tba->ADDR_length == 3533*0Sstevel@tonic-gate sizeof (ipa_conn_x_t)); 3534*0Sstevel@tonic-gate ac = &((ipa_conn_x_t *)addrp)->acx_conn; 3535*0Sstevel@tonic-gate } 3536*0Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ac->ac_laddr, 3537*0Sstevel@tonic-gate &icmp->icmp_v6src); 3538*0Sstevel@tonic-gate break; 3539*0Sstevel@tonic-gate case AF_INET6: 3540*0Sstevel@tonic-gate if (tba->ADDR_length == sizeof (ipa6_conn_t)) { 3541*0Sstevel@tonic-gate ac6 = (ipa6_conn_t *)addrp; 3542*0Sstevel@tonic-gate } else { 3543*0Sstevel@tonic-gate ASSERT(tba->ADDR_length == 3544*0Sstevel@tonic-gate sizeof (ipa6_conn_x_t)); 3545*0Sstevel@tonic-gate ac6 = &((ipa6_conn_x_t *) 3546*0Sstevel@tonic-gate addrp)->ac6x_conn; 3547*0Sstevel@tonic-gate } 3548*0Sstevel@tonic-gate icmp->icmp_v6src = ac6->ac6_laddr; 3549*0Sstevel@tonic-gate (void) icmp_build_hdrs(q, icmp); 3550*0Sstevel@tonic-gate } 3551*0Sstevel@tonic-gate } 3552*0Sstevel@tonic-gate mp1 = mp1->b_cont; 3553*0Sstevel@tonic-gate } 3554*0Sstevel@tonic-gate /* 3555*0Sstevel@tonic-gate * Look for one or more appended ACK message added by 3556*0Sstevel@tonic-gate * icmp_connect or icmp_disconnect. 3557*0Sstevel@tonic-gate * If none found just send up the T_BIND_ACK. 3558*0Sstevel@tonic-gate * icmp_connect has appended a T_OK_ACK and a 3559*0Sstevel@tonic-gate * T_CONN_CON. 3560*0Sstevel@tonic-gate * icmp_disconnect has appended a T_OK_ACK. 3561*0Sstevel@tonic-gate */ 3562*0Sstevel@tonic-gate if (mp1 != NULL) { 3563*0Sstevel@tonic-gate if (mp->b_cont == mp1) 3564*0Sstevel@tonic-gate mp->b_cont = NULL; 3565*0Sstevel@tonic-gate else { 3566*0Sstevel@tonic-gate ASSERT(mp->b_cont->b_cont == mp1); 3567*0Sstevel@tonic-gate mp->b_cont->b_cont = NULL; 3568*0Sstevel@tonic-gate } 3569*0Sstevel@tonic-gate freemsg(mp); 3570*0Sstevel@tonic-gate mp = mp1; 3571*0Sstevel@tonic-gate while (mp != NULL) { 3572*0Sstevel@tonic-gate mp1 = mp->b_cont; 3573*0Sstevel@tonic-gate mp->b_cont = NULL; 3574*0Sstevel@tonic-gate putnext(q, mp); 3575*0Sstevel@tonic-gate mp = mp1; 3576*0Sstevel@tonic-gate } 3577*0Sstevel@tonic-gate return; 3578*0Sstevel@tonic-gate } 3579*0Sstevel@tonic-gate freemsg(mp->b_cont); 3580*0Sstevel@tonic-gate mp->b_cont = NULL; 3581*0Sstevel@tonic-gate putnext(q, mp); 3582*0Sstevel@tonic-gate } 3583*0Sstevel@tonic-gate 3584*0Sstevel@tonic-gate /* 3585*0Sstevel@tonic-gate * return SNMP stuff in buffer in mpdata 3586*0Sstevel@tonic-gate */ 3587*0Sstevel@tonic-gate static int 3588*0Sstevel@tonic-gate icmp_snmp_get(queue_t *q, mblk_t *mpctl) 3589*0Sstevel@tonic-gate { 3590*0Sstevel@tonic-gate mblk_t *mpdata; 3591*0Sstevel@tonic-gate struct opthdr *optp; 3592*0Sstevel@tonic-gate 3593*0Sstevel@tonic-gate if (mpctl == NULL || 3594*0Sstevel@tonic-gate (mpdata = mpctl->b_cont) == NULL) { 3595*0Sstevel@tonic-gate return (0); 3596*0Sstevel@tonic-gate } 3597*0Sstevel@tonic-gate 3598*0Sstevel@tonic-gate /* fixed length structure for IPv4 and IPv6 counters */ 3599*0Sstevel@tonic-gate optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)]; 3600*0Sstevel@tonic-gate optp->level = EXPER_RAWIP; 3601*0Sstevel@tonic-gate optp->name = 0; 3602*0Sstevel@tonic-gate (void) snmp_append_data(mpdata, (char *)&rawip_mib, sizeof (rawip_mib)); 3603*0Sstevel@tonic-gate optp->len = msgdsize(mpdata); 3604*0Sstevel@tonic-gate qreply(q, mpctl); 3605*0Sstevel@tonic-gate 3606*0Sstevel@tonic-gate return (1); 3607*0Sstevel@tonic-gate } 3608*0Sstevel@tonic-gate 3609*0Sstevel@tonic-gate /* 3610*0Sstevel@tonic-gate * Return 0 if invalid set request, 1 otherwise, including non-rawip requests. 3611*0Sstevel@tonic-gate * TODO: If this ever actually tries to set anything, it needs to be 3612*0Sstevel@tonic-gate * to do the appropriate locking. 3613*0Sstevel@tonic-gate */ 3614*0Sstevel@tonic-gate /* ARGSUSED */ 3615*0Sstevel@tonic-gate static int 3616*0Sstevel@tonic-gate icmp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name, 3617*0Sstevel@tonic-gate uchar_t *ptr, int len) 3618*0Sstevel@tonic-gate { 3619*0Sstevel@tonic-gate switch (level) { 3620*0Sstevel@tonic-gate case EXPER_RAWIP: 3621*0Sstevel@tonic-gate return (0); 3622*0Sstevel@tonic-gate default: 3623*0Sstevel@tonic-gate return (1); 3624*0Sstevel@tonic-gate } 3625*0Sstevel@tonic-gate } 3626*0Sstevel@tonic-gate 3627*0Sstevel@tonic-gate /* Report for ndd "icmp_status" */ 3628*0Sstevel@tonic-gate /* ARGSUSED */ 3629*0Sstevel@tonic-gate static int 3630*0Sstevel@tonic-gate icmp_status_report(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 3631*0Sstevel@tonic-gate { 3632*0Sstevel@tonic-gate IDP idp; 3633*0Sstevel@tonic-gate icmp_t *icmp; 3634*0Sstevel@tonic-gate char *state; 3635*0Sstevel@tonic-gate char laddrbuf[INET6_ADDRSTRLEN]; 3636*0Sstevel@tonic-gate char faddrbuf[INET6_ADDRSTRLEN]; 3637*0Sstevel@tonic-gate 3638*0Sstevel@tonic-gate (void) mi_mpprintf(mp, 3639*0Sstevel@tonic-gate "RAWIP " MI_COL_HDRPAD_STR 3640*0Sstevel@tonic-gate /* 01234567[89ABCDEF] */ 3641*0Sstevel@tonic-gate " src addr dest addr state"); 3642*0Sstevel@tonic-gate /* xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx UNBOUND */ 3643*0Sstevel@tonic-gate 3644*0Sstevel@tonic-gate 3645*0Sstevel@tonic-gate for (idp = mi_first_ptr(&icmp_g_head); 3646*0Sstevel@tonic-gate (icmp = (icmp_t *)idp) != NULL; 3647*0Sstevel@tonic-gate idp = mi_next_ptr(&icmp_g_head, idp)) { 3648*0Sstevel@tonic-gate if (icmp->icmp_state == TS_UNBND) 3649*0Sstevel@tonic-gate state = "UNBOUND"; 3650*0Sstevel@tonic-gate else if (icmp->icmp_state == TS_IDLE) 3651*0Sstevel@tonic-gate state = "IDLE"; 3652*0Sstevel@tonic-gate else if (icmp->icmp_state == TS_DATA_XFER) 3653*0Sstevel@tonic-gate state = "CONNECTED"; 3654*0Sstevel@tonic-gate else 3655*0Sstevel@tonic-gate state = "UnkState"; 3656*0Sstevel@tonic-gate 3657*0Sstevel@tonic-gate (void) mi_mpprintf(mp, 3658*0Sstevel@tonic-gate MI_COL_PTRFMT_STR "%s %s %s", 3659*0Sstevel@tonic-gate (void *)icmp, 3660*0Sstevel@tonic-gate inet_ntop(AF_INET6, &icmp->icmp_v6dst, faddrbuf, 3661*0Sstevel@tonic-gate sizeof (faddrbuf)), 3662*0Sstevel@tonic-gate inet_ntop(AF_INET6, &icmp->icmp_v6src, laddrbuf, 3663*0Sstevel@tonic-gate sizeof (laddrbuf)), 3664*0Sstevel@tonic-gate state); 3665*0Sstevel@tonic-gate } 3666*0Sstevel@tonic-gate return (0); 3667*0Sstevel@tonic-gate } 3668*0Sstevel@tonic-gate 3669*0Sstevel@tonic-gate /* 3670*0Sstevel@tonic-gate * This routine creates a T_UDERROR_IND message and passes it upstream. 3671*0Sstevel@tonic-gate * The address and options are copied from the T_UNITDATA_REQ message 3672*0Sstevel@tonic-gate * passed in mp. This message is freed. 3673*0Sstevel@tonic-gate */ 3674*0Sstevel@tonic-gate static void 3675*0Sstevel@tonic-gate icmp_ud_err(queue_t *q, mblk_t *mp, t_scalar_t err) 3676*0Sstevel@tonic-gate { 3677*0Sstevel@tonic-gate mblk_t *mp1; 3678*0Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 3679*0Sstevel@tonic-gate struct T_unitdata_req *tudr = (struct T_unitdata_req *)rptr; 3680*0Sstevel@tonic-gate 3681*0Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&rptr[tudr->DEST_offset], 3682*0Sstevel@tonic-gate tudr->DEST_length, (char *)&rptr[tudr->OPT_offset], 3683*0Sstevel@tonic-gate tudr->OPT_length, err); 3684*0Sstevel@tonic-gate if (mp1) 3685*0Sstevel@tonic-gate qreply(q, mp1); 3686*0Sstevel@tonic-gate freemsg(mp); 3687*0Sstevel@tonic-gate } 3688*0Sstevel@tonic-gate 3689*0Sstevel@tonic-gate /* 3690*0Sstevel@tonic-gate * This routine is called by icmp_wput to handle T_UNBIND_REQ messages. 3691*0Sstevel@tonic-gate * After some error checking, the message is passed downstream to ip. 3692*0Sstevel@tonic-gate */ 3693*0Sstevel@tonic-gate static void 3694*0Sstevel@tonic-gate icmp_unbind(queue_t *q, mblk_t *mp) 3695*0Sstevel@tonic-gate { 3696*0Sstevel@tonic-gate icmp_t *icmp = (icmp_t *)q->q_ptr; 3697*0Sstevel@tonic-gate 3698*0Sstevel@tonic-gate /* If a bind has not been done, we can't unbind. */ 3699*0Sstevel@tonic-gate if (icmp->icmp_state == TS_UNBND) { 3700*0Sstevel@tonic-gate icmp_err_ack(q, mp, TOUTSTATE, 0); 3701*0Sstevel@tonic-gate return; 3702*0Sstevel@tonic-gate } 3703*0Sstevel@tonic-gate V6_SET_ZERO(icmp->icmp_v6src); 3704*0Sstevel@tonic-gate V6_SET_ZERO(icmp->icmp_bound_v6src); 3705*0Sstevel@tonic-gate icmp->icmp_state = TS_UNBND; 3706*0Sstevel@tonic-gate 3707*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET6) { 3708*0Sstevel@tonic-gate int error; 3709*0Sstevel@tonic-gate 3710*0Sstevel@tonic-gate /* Rebuild the header template */ 3711*0Sstevel@tonic-gate error = icmp_build_hdrs(q, icmp); 3712*0Sstevel@tonic-gate if (error != 0) { 3713*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, error); 3714*0Sstevel@tonic-gate return; 3715*0Sstevel@tonic-gate } 3716*0Sstevel@tonic-gate } 3717*0Sstevel@tonic-gate /* Pass the unbind to IP. */ 3718*0Sstevel@tonic-gate putnext(q, mp); 3719*0Sstevel@tonic-gate } 3720*0Sstevel@tonic-gate 3721*0Sstevel@tonic-gate /* 3722*0Sstevel@tonic-gate * Process IPv4 packets that already include an IP header. 3723*0Sstevel@tonic-gate * Used when IP_HDRINCL has been set (implicit for IPPROTO_RAW and 3724*0Sstevel@tonic-gate * IPPROTO_IGMP). 3725*0Sstevel@tonic-gate */ 3726*0Sstevel@tonic-gate static void 3727*0Sstevel@tonic-gate icmp_wput_hdrincl(queue_t *q, mblk_t *mp, icmp_t *icmp) 3728*0Sstevel@tonic-gate { 3729*0Sstevel@tonic-gate ipha_t *ipha; 3730*0Sstevel@tonic-gate int ip_hdr_length; 3731*0Sstevel@tonic-gate int tp_hdr_len; 3732*0Sstevel@tonic-gate mblk_t *mp1; 3733*0Sstevel@tonic-gate uint_t pkt_len; 3734*0Sstevel@tonic-gate 3735*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 3736*0Sstevel@tonic-gate ip_hdr_length = IP_SIMPLE_HDR_LENGTH + icmp->icmp_ip_snd_options_len; 3737*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < IP_SIMPLE_HDR_LENGTH) { 3738*0Sstevel@tonic-gate if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) { 3739*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3740*0Sstevel@tonic-gate freemsg(mp); 3741*0Sstevel@tonic-gate return; 3742*0Sstevel@tonic-gate } 3743*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 3744*0Sstevel@tonic-gate } 3745*0Sstevel@tonic-gate ipha->ipha_version_and_hdr_length = 3746*0Sstevel@tonic-gate (IP_VERSION<<4) | (ip_hdr_length>>2); 3747*0Sstevel@tonic-gate 3748*0Sstevel@tonic-gate /* 3749*0Sstevel@tonic-gate * For the socket of SOCK_RAW type, the checksum is provided in the 3750*0Sstevel@tonic-gate * pre-built packet. We set the ipha_ident field to IP_HDR_INCLUDED to 3751*0Sstevel@tonic-gate * tell IP that the application has sent a complete IP header and not 3752*0Sstevel@tonic-gate * to compute the transport checksum nor change the DF flag. 3753*0Sstevel@tonic-gate */ 3754*0Sstevel@tonic-gate ipha->ipha_ident = IP_HDR_INCLUDED; 3755*0Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 3756*0Sstevel@tonic-gate ipha->ipha_fragment_offset_and_flags &= htons(IPH_DF); 3757*0Sstevel@tonic-gate /* Insert options if any */ 3758*0Sstevel@tonic-gate if (ip_hdr_length > IP_SIMPLE_HDR_LENGTH) { 3759*0Sstevel@tonic-gate /* 3760*0Sstevel@tonic-gate * Put the IP header plus any transport header that is 3761*0Sstevel@tonic-gate * checksumed by ip_wput into the first mblk. (ip_wput assumes 3762*0Sstevel@tonic-gate * that at least the checksum field is in the first mblk.) 3763*0Sstevel@tonic-gate */ 3764*0Sstevel@tonic-gate switch (ipha->ipha_protocol) { 3765*0Sstevel@tonic-gate case IPPROTO_UDP: 3766*0Sstevel@tonic-gate tp_hdr_len = 8; 3767*0Sstevel@tonic-gate break; 3768*0Sstevel@tonic-gate case IPPROTO_TCP: 3769*0Sstevel@tonic-gate tp_hdr_len = 20; 3770*0Sstevel@tonic-gate break; 3771*0Sstevel@tonic-gate default: 3772*0Sstevel@tonic-gate tp_hdr_len = 0; 3773*0Sstevel@tonic-gate break; 3774*0Sstevel@tonic-gate } 3775*0Sstevel@tonic-gate /* 3776*0Sstevel@tonic-gate * The code below assumes that IP_SIMPLE_HDR_LENGTH plus 3777*0Sstevel@tonic-gate * tp_hdr_len bytes will be in a single mblk. 3778*0Sstevel@tonic-gate */ 3779*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < (IP_SIMPLE_HDR_LENGTH + 3780*0Sstevel@tonic-gate tp_hdr_len)) { 3781*0Sstevel@tonic-gate if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH + 3782*0Sstevel@tonic-gate tp_hdr_len)) { 3783*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3784*0Sstevel@tonic-gate freemsg(mp); 3785*0Sstevel@tonic-gate return; 3786*0Sstevel@tonic-gate } 3787*0Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 3788*0Sstevel@tonic-gate } 3789*0Sstevel@tonic-gate 3790*0Sstevel@tonic-gate /* 3791*0Sstevel@tonic-gate * if the length is larger then the max allowed IP packet, 3792*0Sstevel@tonic-gate * then send an error and abort the processing. 3793*0Sstevel@tonic-gate */ 3794*0Sstevel@tonic-gate pkt_len = ntohs(ipha->ipha_length) 3795*0Sstevel@tonic-gate + icmp->icmp_ip_snd_options_len; 3796*0Sstevel@tonic-gate if (pkt_len > IP_MAXPACKET) { 3797*0Sstevel@tonic-gate icmp_ud_err(q, mp, EMSGSIZE); 3798*0Sstevel@tonic-gate return; 3799*0Sstevel@tonic-gate } 3800*0Sstevel@tonic-gate if (!(mp1 = allocb(ip_hdr_length + icmp_wroff_extra + 3801*0Sstevel@tonic-gate tp_hdr_len, BPRI_LO))) { 3802*0Sstevel@tonic-gate icmp_ud_err(q, mp, ENOMEM); 3803*0Sstevel@tonic-gate return; 3804*0Sstevel@tonic-gate } 3805*0Sstevel@tonic-gate mp1->b_rptr += icmp_wroff_extra; 3806*0Sstevel@tonic-gate mp1->b_wptr = mp1->b_rptr + ip_hdr_length; 3807*0Sstevel@tonic-gate 3808*0Sstevel@tonic-gate ipha->ipha_length = htons((uint16_t)pkt_len); 3809*0Sstevel@tonic-gate bcopy(ipha, mp1->b_rptr, IP_SIMPLE_HDR_LENGTH); 3810*0Sstevel@tonic-gate 3811*0Sstevel@tonic-gate /* Copy transport header if any */ 3812*0Sstevel@tonic-gate bcopy(&ipha[1], mp1->b_wptr, tp_hdr_len); 3813*0Sstevel@tonic-gate mp1->b_wptr += tp_hdr_len; 3814*0Sstevel@tonic-gate 3815*0Sstevel@tonic-gate /* Add options */ 3816*0Sstevel@tonic-gate ipha = (ipha_t *)mp1->b_rptr; 3817*0Sstevel@tonic-gate bcopy(icmp->icmp_ip_snd_options, &ipha[1], 3818*0Sstevel@tonic-gate icmp->icmp_ip_snd_options_len); 3819*0Sstevel@tonic-gate 3820*0Sstevel@tonic-gate /* Drop IP header and transport header from original */ 3821*0Sstevel@tonic-gate (void) adjmsg(mp, IP_SIMPLE_HDR_LENGTH + tp_hdr_len); 3822*0Sstevel@tonic-gate 3823*0Sstevel@tonic-gate mp1->b_cont = mp; 3824*0Sstevel@tonic-gate mp = mp1; 3825*0Sstevel@tonic-gate /* 3826*0Sstevel@tonic-gate * Massage source route putting first source 3827*0Sstevel@tonic-gate * route in ipha_dst. 3828*0Sstevel@tonic-gate */ 3829*0Sstevel@tonic-gate (void) ip_massage_options(ipha); 3830*0Sstevel@tonic-gate } 3831*0Sstevel@tonic-gate putnext(q, mp); 3832*0Sstevel@tonic-gate } 3833*0Sstevel@tonic-gate 3834*0Sstevel@tonic-gate /* 3835*0Sstevel@tonic-gate * This routine handles all messages passed downstream. It either 3836*0Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 3837*0Sstevel@tonic-gate * a message. 3838*0Sstevel@tonic-gate */ 3839*0Sstevel@tonic-gate static void 3840*0Sstevel@tonic-gate icmp_wput(queue_t *q, mblk_t *mp) 3841*0Sstevel@tonic-gate { 3842*0Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 3843*0Sstevel@tonic-gate ipha_t *ipha; 3844*0Sstevel@tonic-gate mblk_t *mp1; 3845*0Sstevel@tonic-gate int ip_hdr_length; 3846*0Sstevel@tonic-gate #define tudr ((struct T_unitdata_req *)rptr) 3847*0Sstevel@tonic-gate size_t ip_len; 3848*0Sstevel@tonic-gate icmp_t *icmp; 3849*0Sstevel@tonic-gate sin6_t *sin6; 3850*0Sstevel@tonic-gate sin_t *sin; 3851*0Sstevel@tonic-gate ipaddr_t v4dst; 3852*0Sstevel@tonic-gate 3853*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 3854*0Sstevel@tonic-gate if (icmp->icmp_restricted) { 3855*0Sstevel@tonic-gate icmp_wput_restricted(q, mp); 3856*0Sstevel@tonic-gate return; 3857*0Sstevel@tonic-gate } 3858*0Sstevel@tonic-gate 3859*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 3860*0Sstevel@tonic-gate case M_DATA: 3861*0Sstevel@tonic-gate if (icmp->icmp_hdrincl) { 3862*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV4_VERSION); 3863*0Sstevel@tonic-gate icmp_wput_hdrincl(q, mp, icmp); 3864*0Sstevel@tonic-gate return; 3865*0Sstevel@tonic-gate } 3866*0Sstevel@tonic-gate freemsg(mp); 3867*0Sstevel@tonic-gate return; 3868*0Sstevel@tonic-gate case M_PROTO: 3869*0Sstevel@tonic-gate case M_PCPROTO: 3870*0Sstevel@tonic-gate ip_len = mp->b_wptr - rptr; 3871*0Sstevel@tonic-gate if (ip_len >= sizeof (struct T_unitdata_req)) { 3872*0Sstevel@tonic-gate /* Expedite valid T_UNITDATA_REQ to below the switch */ 3873*0Sstevel@tonic-gate if (((union T_primitives *)rptr)->type 3874*0Sstevel@tonic-gate == T_UNITDATA_REQ) 3875*0Sstevel@tonic-gate break; 3876*0Sstevel@tonic-gate } 3877*0Sstevel@tonic-gate /* FALLTHRU */ 3878*0Sstevel@tonic-gate default: 3879*0Sstevel@tonic-gate icmp_wput_other(q, mp); 3880*0Sstevel@tonic-gate return; 3881*0Sstevel@tonic-gate } 3882*0Sstevel@tonic-gate 3883*0Sstevel@tonic-gate /* Handle T_UNITDATA_REQ messages here. */ 3884*0Sstevel@tonic-gate 3885*0Sstevel@tonic-gate if (icmp->icmp_state == TS_UNBND) { 3886*0Sstevel@tonic-gate /* If a port has not been bound to the stream, fail. */ 3887*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3888*0Sstevel@tonic-gate icmp_ud_err(q, mp, EPROTO); 3889*0Sstevel@tonic-gate return; 3890*0Sstevel@tonic-gate } 3891*0Sstevel@tonic-gate mp1 = mp->b_cont; 3892*0Sstevel@tonic-gate if (mp1 == NULL) { 3893*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3894*0Sstevel@tonic-gate icmp_ud_err(q, mp, EPROTO); 3895*0Sstevel@tonic-gate return; 3896*0Sstevel@tonic-gate } 3897*0Sstevel@tonic-gate 3898*0Sstevel@tonic-gate if ((rptr + tudr->DEST_offset + tudr->DEST_length) > mp->b_wptr) { 3899*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3900*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 3901*0Sstevel@tonic-gate return; 3902*0Sstevel@tonic-gate } 3903*0Sstevel@tonic-gate 3904*0Sstevel@tonic-gate switch (icmp->icmp_family) { 3905*0Sstevel@tonic-gate case AF_INET6: 3906*0Sstevel@tonic-gate sin6 = (sin6_t *)&rptr[tudr->DEST_offset]; 3907*0Sstevel@tonic-gate if (!OK_32PTR((char *)sin6) || 3908*0Sstevel@tonic-gate tudr->DEST_length != sizeof (sin6_t) || 3909*0Sstevel@tonic-gate sin6->sin6_family != AF_INET6) { 3910*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3911*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 3912*0Sstevel@tonic-gate return; 3913*0Sstevel@tonic-gate } 3914*0Sstevel@tonic-gate 3915*0Sstevel@tonic-gate /* No support for mapped addresses on raw sockets */ 3916*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3917*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3918*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 3919*0Sstevel@tonic-gate return; 3920*0Sstevel@tonic-gate } 3921*0Sstevel@tonic-gate 3922*0Sstevel@tonic-gate /* 3923*0Sstevel@tonic-gate * Destination is a native IPv6 address. 3924*0Sstevel@tonic-gate * Send out an IPv6 format packet. 3925*0Sstevel@tonic-gate */ 3926*0Sstevel@tonic-gate icmp_wput_ipv6(q, mp, sin6, tudr->OPT_length); 3927*0Sstevel@tonic-gate return; 3928*0Sstevel@tonic-gate 3929*0Sstevel@tonic-gate case AF_INET: 3930*0Sstevel@tonic-gate sin = (sin_t *)&rptr[tudr->DEST_offset]; 3931*0Sstevel@tonic-gate if (!OK_32PTR((char *)sin) || 3932*0Sstevel@tonic-gate tudr->DEST_length != sizeof (sin_t) || 3933*0Sstevel@tonic-gate sin->sin_family != AF_INET) { 3934*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3935*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 3936*0Sstevel@tonic-gate return; 3937*0Sstevel@tonic-gate } 3938*0Sstevel@tonic-gate /* Extract and ipaddr */ 3939*0Sstevel@tonic-gate v4dst = sin->sin_addr.s_addr; 3940*0Sstevel@tonic-gate break; 3941*0Sstevel@tonic-gate } 3942*0Sstevel@tonic-gate 3943*0Sstevel@tonic-gate /* 3944*0Sstevel@tonic-gate * If options passed in, feed it for verification and handling 3945*0Sstevel@tonic-gate */ 3946*0Sstevel@tonic-gate if (tudr->OPT_length != 0) { 3947*0Sstevel@tonic-gate int error; 3948*0Sstevel@tonic-gate 3949*0Sstevel@tonic-gate if (icmp_unitdata_opt_process(q, mp, &error, 3950*0Sstevel@tonic-gate (uchar_t *)0) < 0) { 3951*0Sstevel@tonic-gate /* failure */ 3952*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3953*0Sstevel@tonic-gate icmp_ud_err(q, mp, error); 3954*0Sstevel@tonic-gate return; 3955*0Sstevel@tonic-gate } 3956*0Sstevel@tonic-gate /* 3957*0Sstevel@tonic-gate * Note: Success in processing options. 3958*0Sstevel@tonic-gate * mp option buffer represented by 3959*0Sstevel@tonic-gate * OPT_length/offset now potentially modified 3960*0Sstevel@tonic-gate * and contain option setting results 3961*0Sstevel@tonic-gate */ 3962*0Sstevel@tonic-gate } 3963*0Sstevel@tonic-gate 3964*0Sstevel@tonic-gate /* Protocol 255 contains full IP headers */ 3965*0Sstevel@tonic-gate if (icmp->icmp_hdrincl) { 3966*0Sstevel@tonic-gate freeb(mp); 3967*0Sstevel@tonic-gate icmp_wput_hdrincl(q, mp1, icmp); 3968*0Sstevel@tonic-gate return; 3969*0Sstevel@tonic-gate } 3970*0Sstevel@tonic-gate /* Add an IP header */ 3971*0Sstevel@tonic-gate ip_hdr_length = IP_SIMPLE_HDR_LENGTH + icmp->icmp_ip_snd_options_len; 3972*0Sstevel@tonic-gate ipha = (ipha_t *)&mp1->b_rptr[-ip_hdr_length]; 3973*0Sstevel@tonic-gate if ((uchar_t *)ipha < mp1->b_datap->db_base || 3974*0Sstevel@tonic-gate mp1->b_datap->db_ref != 1 || 3975*0Sstevel@tonic-gate !OK_32PTR(ipha)) { 3976*0Sstevel@tonic-gate if (!(mp1 = allocb(ip_hdr_length + icmp_wroff_extra, 3977*0Sstevel@tonic-gate BPRI_LO))) { 3978*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 3979*0Sstevel@tonic-gate icmp_ud_err(q, mp1, ENOMEM); 3980*0Sstevel@tonic-gate return; 3981*0Sstevel@tonic-gate } 3982*0Sstevel@tonic-gate mp1->b_cont = mp->b_cont; 3983*0Sstevel@tonic-gate ipha = (ipha_t *)mp1->b_datap->db_lim; 3984*0Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)ipha; 3985*0Sstevel@tonic-gate ipha = (ipha_t *)((uchar_t *)ipha - ip_hdr_length); 3986*0Sstevel@tonic-gate } 3987*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 3988*0Sstevel@tonic-gate /* Set version, header length, and tos */ 3989*0Sstevel@tonic-gate *(uint16_t *)&ipha->ipha_version_and_hdr_length = 3990*0Sstevel@tonic-gate ((((IP_VERSION << 4) | (ip_hdr_length>>2)) << 8) | 3991*0Sstevel@tonic-gate icmp->icmp_type_of_service); 3992*0Sstevel@tonic-gate /* Set ttl and protocol */ 3993*0Sstevel@tonic-gate *(uint16_t *)&ipha->ipha_ttl = (icmp->icmp_ttl << 8) | icmp->icmp_proto; 3994*0Sstevel@tonic-gate #else 3995*0Sstevel@tonic-gate /* Set version, header length, and tos */ 3996*0Sstevel@tonic-gate *(uint16_t *)&ipha->ipha_version_and_hdr_length = 3997*0Sstevel@tonic-gate ((icmp->icmp_type_of_service << 8) | 3998*0Sstevel@tonic-gate ((IP_VERSION << 4) | (ip_hdr_length>>2))); 3999*0Sstevel@tonic-gate /* Set ttl and protocol */ 4000*0Sstevel@tonic-gate *(uint16_t *)&ipha->ipha_ttl = (icmp->icmp_proto << 8) | icmp->icmp_ttl; 4001*0Sstevel@tonic-gate #endif 4002*0Sstevel@tonic-gate /* 4003*0Sstevel@tonic-gate * Copy our address into the packet. If this is zero, 4004*0Sstevel@tonic-gate * ip will fill in the real source address. 4005*0Sstevel@tonic-gate */ 4006*0Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&icmp->icmp_v6src, ipha->ipha_src); 4007*0Sstevel@tonic-gate ipha->ipha_fragment_offset_and_flags = 0; 4008*0Sstevel@tonic-gate 4009*0Sstevel@tonic-gate /* 4010*0Sstevel@tonic-gate * For the socket of SOCK_RAW type, the checksum is provided in the 4011*0Sstevel@tonic-gate * pre-built packet. We set the ipha_ident field to IP_HDR_INCLUDED to 4012*0Sstevel@tonic-gate * tell IP that the application has sent a complete IP header and not 4013*0Sstevel@tonic-gate * to compute the transport checksum nor change the DF flag. 4014*0Sstevel@tonic-gate */ 4015*0Sstevel@tonic-gate ipha->ipha_ident = IP_HDR_INCLUDED; 4016*0Sstevel@tonic-gate 4017*0Sstevel@tonic-gate /* Finish common formatting of the packet. */ 4018*0Sstevel@tonic-gate mp1->b_rptr = (uchar_t *)ipha; 4019*0Sstevel@tonic-gate 4020*0Sstevel@tonic-gate ip_len = mp1->b_wptr - (uchar_t *)ipha; 4021*0Sstevel@tonic-gate if (mp1->b_cont != NULL) 4022*0Sstevel@tonic-gate ip_len += msgdsize(mp1->b_cont); 4023*0Sstevel@tonic-gate 4024*0Sstevel@tonic-gate /* 4025*0Sstevel@tonic-gate * Set the length into the IP header. 4026*0Sstevel@tonic-gate * If the length is greater than the maximum allowed by IP, 4027*0Sstevel@tonic-gate * then free the message and return. Do not try and send it 4028*0Sstevel@tonic-gate * as this can cause problems in layers below. 4029*0Sstevel@tonic-gate */ 4030*0Sstevel@tonic-gate if (ip_len > IP_MAXPACKET) { 4031*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4032*0Sstevel@tonic-gate icmp_ud_err(q, mp, EMSGSIZE); 4033*0Sstevel@tonic-gate return; 4034*0Sstevel@tonic-gate } 4035*0Sstevel@tonic-gate ipha->ipha_length = htons((uint16_t)ip_len); 4036*0Sstevel@tonic-gate /* 4037*0Sstevel@tonic-gate * Copy in the destination address from the T_UNITDATA 4038*0Sstevel@tonic-gate * request 4039*0Sstevel@tonic-gate */ 4040*0Sstevel@tonic-gate if (v4dst == INADDR_ANY) 4041*0Sstevel@tonic-gate ipha->ipha_dst = htonl(INADDR_LOOPBACK); 4042*0Sstevel@tonic-gate else 4043*0Sstevel@tonic-gate ipha->ipha_dst = v4dst; 4044*0Sstevel@tonic-gate 4045*0Sstevel@tonic-gate /* 4046*0Sstevel@tonic-gate * Set ttl based on IP_MULTICAST_TTL to match IPv6 logic. 4047*0Sstevel@tonic-gate */ 4048*0Sstevel@tonic-gate if (CLASSD(v4dst)) 4049*0Sstevel@tonic-gate ipha->ipha_ttl = icmp->icmp_multicast_ttl; 4050*0Sstevel@tonic-gate 4051*0Sstevel@tonic-gate /* Copy in options if any */ 4052*0Sstevel@tonic-gate if (ip_hdr_length > IP_SIMPLE_HDR_LENGTH) { 4053*0Sstevel@tonic-gate bcopy(icmp->icmp_ip_snd_options, 4054*0Sstevel@tonic-gate &ipha[1], icmp->icmp_ip_snd_options_len); 4055*0Sstevel@tonic-gate /* 4056*0Sstevel@tonic-gate * Massage source route putting first source route in ipha_dst. 4057*0Sstevel@tonic-gate * Ignore the destination in the T_unitdata_req. 4058*0Sstevel@tonic-gate */ 4059*0Sstevel@tonic-gate (void) ip_massage_options(ipha); 4060*0Sstevel@tonic-gate } 4061*0Sstevel@tonic-gate freeb(mp); 4062*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutDatagrams); 4063*0Sstevel@tonic-gate putnext(q, mp1); 4064*0Sstevel@tonic-gate #undef ipha 4065*0Sstevel@tonic-gate #undef tudr 4066*0Sstevel@tonic-gate } 4067*0Sstevel@tonic-gate 4068*0Sstevel@tonic-gate /* 4069*0Sstevel@tonic-gate * icmp_wput_ipv6(): 4070*0Sstevel@tonic-gate * Assumes that icmp_wput did some sanity checking on the destination 4071*0Sstevel@tonic-gate * address. 4072*0Sstevel@tonic-gate */ 4073*0Sstevel@tonic-gate void 4074*0Sstevel@tonic-gate icmp_wput_ipv6(queue_t *q, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen) 4075*0Sstevel@tonic-gate { 4076*0Sstevel@tonic-gate ip6_t *ip6h; 4077*0Sstevel@tonic-gate ip6i_t *ip6i; /* mp1->b_rptr even if no ip6i_t */ 4078*0Sstevel@tonic-gate mblk_t *mp1; 4079*0Sstevel@tonic-gate int ip_hdr_len = IPV6_HDR_LEN; 4080*0Sstevel@tonic-gate size_t ip_len; 4081*0Sstevel@tonic-gate icmp_t *icmp; 4082*0Sstevel@tonic-gate ip6_pkt_t ipp_s; /* For ancillary data options */ 4083*0Sstevel@tonic-gate ip6_pkt_t *ipp = &ipp_s; 4084*0Sstevel@tonic-gate ip6_pkt_t *tipp; 4085*0Sstevel@tonic-gate uint32_t csum = 0; 4086*0Sstevel@tonic-gate uint_t ignore = 0; 4087*0Sstevel@tonic-gate uint_t option_exists = 0, is_sticky = 0; 4088*0Sstevel@tonic-gate uint8_t *cp; 4089*0Sstevel@tonic-gate uint8_t *nxthdr_ptr; 4090*0Sstevel@tonic-gate 4091*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 4092*0Sstevel@tonic-gate 4093*0Sstevel@tonic-gate /* 4094*0Sstevel@tonic-gate * If the local address is a mapped address return 4095*0Sstevel@tonic-gate * an error. 4096*0Sstevel@tonic-gate * It would be possible to send an IPv6 packet but the 4097*0Sstevel@tonic-gate * response would never make it back to the application 4098*0Sstevel@tonic-gate * since it is bound to a mapped address. 4099*0Sstevel@tonic-gate */ 4100*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6src)) { 4101*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4102*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 4103*0Sstevel@tonic-gate return; 4104*0Sstevel@tonic-gate } 4105*0Sstevel@tonic-gate 4106*0Sstevel@tonic-gate ipp->ipp_fields = 0; 4107*0Sstevel@tonic-gate ipp->ipp_sticky_ignored = 0; 4108*0Sstevel@tonic-gate 4109*0Sstevel@tonic-gate /* 4110*0Sstevel@tonic-gate * If TPI options passed in, feed it for verification and handling 4111*0Sstevel@tonic-gate */ 4112*0Sstevel@tonic-gate if (tudr_optlen != 0) { 4113*0Sstevel@tonic-gate int error; 4114*0Sstevel@tonic-gate 4115*0Sstevel@tonic-gate if (icmp_unitdata_opt_process(q, mp, &error, 4116*0Sstevel@tonic-gate (void *)ipp) < 0) { 4117*0Sstevel@tonic-gate /* failure */ 4118*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4119*0Sstevel@tonic-gate icmp_ud_err(q, mp, error); 4120*0Sstevel@tonic-gate return; 4121*0Sstevel@tonic-gate } 4122*0Sstevel@tonic-gate ignore = ipp->ipp_sticky_ignored; 4123*0Sstevel@tonic-gate ASSERT(error == 0); 4124*0Sstevel@tonic-gate } 4125*0Sstevel@tonic-gate 4126*0Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 4127*0Sstevel@tonic-gate IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 4128*0Sstevel@tonic-gate /* 4129*0Sstevel@tonic-gate * IPPF_SCOPE_ID is special. It's neither a sticky 4130*0Sstevel@tonic-gate * option nor ancillary data. It needs to be 4131*0Sstevel@tonic-gate * explicitly set in options_exists. 4132*0Sstevel@tonic-gate */ 4133*0Sstevel@tonic-gate option_exists |= IPPF_SCOPE_ID; 4134*0Sstevel@tonic-gate } 4135*0Sstevel@tonic-gate 4136*0Sstevel@tonic-gate if ((icmp->icmp_sticky_ipp.ipp_fields == 0) && 4137*0Sstevel@tonic-gate (ipp->ipp_fields == 0)) { 4138*0Sstevel@tonic-gate /* No sticky options nor ancillary data. */ 4139*0Sstevel@tonic-gate goto no_options; 4140*0Sstevel@tonic-gate } 4141*0Sstevel@tonic-gate 4142*0Sstevel@tonic-gate /* 4143*0Sstevel@tonic-gate * Go through the options figuring out where each is going to 4144*0Sstevel@tonic-gate * come from and build two masks. The first mask indicates if 4145*0Sstevel@tonic-gate * the option exists at all. The second mask indicates if the 4146*0Sstevel@tonic-gate * option is sticky or ancillary. 4147*0Sstevel@tonic-gate */ 4148*0Sstevel@tonic-gate if (!(ignore & IPPF_HOPOPTS)) { 4149*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HOPOPTS) { 4150*0Sstevel@tonic-gate option_exists |= IPPF_HOPOPTS; 4151*0Sstevel@tonic-gate ip_hdr_len += ipp->ipp_hopoptslen; 4152*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) { 4153*0Sstevel@tonic-gate option_exists |= IPPF_HOPOPTS; 4154*0Sstevel@tonic-gate is_sticky |= IPPF_HOPOPTS; 4155*0Sstevel@tonic-gate ip_hdr_len += icmp->icmp_sticky_ipp.ipp_hopoptslen; 4156*0Sstevel@tonic-gate } 4157*0Sstevel@tonic-gate } 4158*0Sstevel@tonic-gate 4159*0Sstevel@tonic-gate if (!(ignore & IPPF_RTHDR)) { 4160*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_RTHDR) { 4161*0Sstevel@tonic-gate option_exists |= IPPF_RTHDR; 4162*0Sstevel@tonic-gate ip_hdr_len += ipp->ipp_rthdrlen; 4163*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTHDR) { 4164*0Sstevel@tonic-gate option_exists |= IPPF_RTHDR; 4165*0Sstevel@tonic-gate is_sticky |= IPPF_RTHDR; 4166*0Sstevel@tonic-gate ip_hdr_len += icmp->icmp_sticky_ipp.ipp_rthdrlen; 4167*0Sstevel@tonic-gate } 4168*0Sstevel@tonic-gate } 4169*0Sstevel@tonic-gate 4170*0Sstevel@tonic-gate if (!(ignore & IPPF_RTDSTOPTS) && (option_exists & IPPF_RTHDR)) { 4171*0Sstevel@tonic-gate /* 4172*0Sstevel@tonic-gate * Need to have a router header to use these. 4173*0Sstevel@tonic-gate */ 4174*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_RTDSTOPTS) { 4175*0Sstevel@tonic-gate option_exists |= IPPF_RTDSTOPTS; 4176*0Sstevel@tonic-gate ip_hdr_len += ipp->ipp_rtdstoptslen; 4177*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) { 4178*0Sstevel@tonic-gate option_exists |= IPPF_RTDSTOPTS; 4179*0Sstevel@tonic-gate is_sticky |= IPPF_RTDSTOPTS; 4180*0Sstevel@tonic-gate ip_hdr_len += 4181*0Sstevel@tonic-gate icmp->icmp_sticky_ipp.ipp_rtdstoptslen; 4182*0Sstevel@tonic-gate } 4183*0Sstevel@tonic-gate } 4184*0Sstevel@tonic-gate 4185*0Sstevel@tonic-gate if (!(ignore & IPPF_DSTOPTS)) { 4186*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_DSTOPTS) { 4187*0Sstevel@tonic-gate option_exists |= IPPF_DSTOPTS; 4188*0Sstevel@tonic-gate ip_hdr_len += ipp->ipp_dstoptslen; 4189*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) { 4190*0Sstevel@tonic-gate option_exists |= IPPF_DSTOPTS; 4191*0Sstevel@tonic-gate is_sticky |= IPPF_DSTOPTS; 4192*0Sstevel@tonic-gate ip_hdr_len += icmp->icmp_sticky_ipp.ipp_dstoptslen; 4193*0Sstevel@tonic-gate } 4194*0Sstevel@tonic-gate } 4195*0Sstevel@tonic-gate 4196*0Sstevel@tonic-gate if (!(ignore & IPPF_IFINDEX)) { 4197*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_IFINDEX) { 4198*0Sstevel@tonic-gate option_exists |= IPPF_IFINDEX; 4199*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_IFINDEX) { 4200*0Sstevel@tonic-gate option_exists |= IPPF_IFINDEX; 4201*0Sstevel@tonic-gate is_sticky |= IPPF_IFINDEX; 4202*0Sstevel@tonic-gate } 4203*0Sstevel@tonic-gate } 4204*0Sstevel@tonic-gate 4205*0Sstevel@tonic-gate if (!(ignore & IPPF_ADDR)) { 4206*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_ADDR) { 4207*0Sstevel@tonic-gate option_exists |= IPPF_ADDR; 4208*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_ADDR) { 4209*0Sstevel@tonic-gate option_exists |= IPPF_ADDR; 4210*0Sstevel@tonic-gate is_sticky |= IPPF_ADDR; 4211*0Sstevel@tonic-gate } 4212*0Sstevel@tonic-gate } 4213*0Sstevel@tonic-gate 4214*0Sstevel@tonic-gate if (!(ignore & IPPF_DONTFRAG)) { 4215*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_DONTFRAG) { 4216*0Sstevel@tonic-gate option_exists |= IPPF_DONTFRAG; 4217*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_DONTFRAG) { 4218*0Sstevel@tonic-gate option_exists |= IPPF_DONTFRAG; 4219*0Sstevel@tonic-gate is_sticky |= IPPF_DONTFRAG; 4220*0Sstevel@tonic-gate } 4221*0Sstevel@tonic-gate } 4222*0Sstevel@tonic-gate 4223*0Sstevel@tonic-gate if (!(ignore & IPPF_USE_MIN_MTU)) { 4224*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_USE_MIN_MTU) { 4225*0Sstevel@tonic-gate option_exists |= IPPF_USE_MIN_MTU; 4226*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & 4227*0Sstevel@tonic-gate IPPF_USE_MIN_MTU) { 4228*0Sstevel@tonic-gate option_exists |= IPPF_USE_MIN_MTU; 4229*0Sstevel@tonic-gate is_sticky |= IPPF_USE_MIN_MTU; 4230*0Sstevel@tonic-gate } 4231*0Sstevel@tonic-gate } 4232*0Sstevel@tonic-gate 4233*0Sstevel@tonic-gate if (!(ignore & IPPF_NEXTHOP)) { 4234*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_NEXTHOP) { 4235*0Sstevel@tonic-gate option_exists |= IPPF_NEXTHOP; 4236*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_NEXTHOP) { 4237*0Sstevel@tonic-gate option_exists |= IPPF_NEXTHOP; 4238*0Sstevel@tonic-gate is_sticky |= IPPF_NEXTHOP; 4239*0Sstevel@tonic-gate } 4240*0Sstevel@tonic-gate } 4241*0Sstevel@tonic-gate 4242*0Sstevel@tonic-gate if (!(ignore & IPPF_HOPLIMIT)) { 4243*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HOPLIMIT) { 4244*0Sstevel@tonic-gate option_exists |= IPPF_HOPLIMIT; 4245*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT) { 4246*0Sstevel@tonic-gate option_exists |= IPPF_HOPLIMIT; 4247*0Sstevel@tonic-gate is_sticky |= IPPF_HOPLIMIT; 4248*0Sstevel@tonic-gate } 4249*0Sstevel@tonic-gate } 4250*0Sstevel@tonic-gate 4251*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_NO_CKSUM) { 4252*0Sstevel@tonic-gate /* This is a sticky socket option only */ 4253*0Sstevel@tonic-gate option_exists |= IPPF_NO_CKSUM; 4254*0Sstevel@tonic-gate is_sticky |= IPPF_NO_CKSUM; 4255*0Sstevel@tonic-gate } 4256*0Sstevel@tonic-gate 4257*0Sstevel@tonic-gate if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_RAW_CKSUM) { 4258*0Sstevel@tonic-gate /* This is a sticky socket option only */ 4259*0Sstevel@tonic-gate option_exists |= IPPF_RAW_CKSUM; 4260*0Sstevel@tonic-gate is_sticky |= IPPF_RAW_CKSUM; 4261*0Sstevel@tonic-gate } 4262*0Sstevel@tonic-gate 4263*0Sstevel@tonic-gate if (!(ignore & IPPF_TCLASS)) { 4264*0Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_TCLASS) { 4265*0Sstevel@tonic-gate option_exists |= IPPF_TCLASS; 4266*0Sstevel@tonic-gate } else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_TCLASS) { 4267*0Sstevel@tonic-gate option_exists |= IPPF_TCLASS; 4268*0Sstevel@tonic-gate is_sticky |= IPPF_TCLASS; 4269*0Sstevel@tonic-gate } 4270*0Sstevel@tonic-gate } 4271*0Sstevel@tonic-gate 4272*0Sstevel@tonic-gate no_options: 4273*0Sstevel@tonic-gate 4274*0Sstevel@tonic-gate /* 4275*0Sstevel@tonic-gate * If any options carried in the ip6i_t were specified, we 4276*0Sstevel@tonic-gate * need to account for the ip6i_t in the data we'll be sending 4277*0Sstevel@tonic-gate * down. 4278*0Sstevel@tonic-gate */ 4279*0Sstevel@tonic-gate if (option_exists & IPPF_HAS_IP6I) 4280*0Sstevel@tonic-gate ip_hdr_len += sizeof (ip6i_t); 4281*0Sstevel@tonic-gate 4282*0Sstevel@tonic-gate /* check/fix buffer config, setup pointers into it */ 4283*0Sstevel@tonic-gate mp1 = mp->b_cont; 4284*0Sstevel@tonic-gate ip6h = (ip6_t *)&mp1->b_rptr[-ip_hdr_len]; 4285*0Sstevel@tonic-gate if ((mp1->b_datap->db_ref != 1) || 4286*0Sstevel@tonic-gate ((unsigned char *)ip6h < mp1->b_datap->db_base) || 4287*0Sstevel@tonic-gate !OK_32PTR(ip6h)) { 4288*0Sstevel@tonic-gate /* Try to get everything in a single mblk next time */ 4289*0Sstevel@tonic-gate if (ip_hdr_len > icmp->icmp_max_hdr_len) { 4290*0Sstevel@tonic-gate icmp->icmp_max_hdr_len = ip_hdr_len; 4291*0Sstevel@tonic-gate (void) mi_set_sth_wroff(RD(q), 4292*0Sstevel@tonic-gate icmp->icmp_max_hdr_len + icmp_wroff_extra); 4293*0Sstevel@tonic-gate } 4294*0Sstevel@tonic-gate mp1 = allocb(ip_hdr_len + icmp_wroff_extra, BPRI_LO); 4295*0Sstevel@tonic-gate if (!mp1) { 4296*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4297*0Sstevel@tonic-gate icmp_ud_err(q, mp, ENOMEM); 4298*0Sstevel@tonic-gate return; 4299*0Sstevel@tonic-gate } 4300*0Sstevel@tonic-gate mp1->b_cont = mp->b_cont; 4301*0Sstevel@tonic-gate mp1->b_wptr = mp1->b_datap->db_lim; 4302*0Sstevel@tonic-gate ip6h = (ip6_t *)(mp1->b_wptr - ip_hdr_len); 4303*0Sstevel@tonic-gate } 4304*0Sstevel@tonic-gate mp1->b_rptr = (unsigned char *)ip6h; 4305*0Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 4306*0Sstevel@tonic-gate 4307*0Sstevel@tonic-gate #define ANCIL_OR_STICKY_PTR(f) ((is_sticky & f) ? &icmp->icmp_sticky_ipp : ipp) 4308*0Sstevel@tonic-gate if (option_exists & IPPF_HAS_IP6I) { 4309*0Sstevel@tonic-gate ip6h = (ip6_t *)&ip6i[1]; 4310*0Sstevel@tonic-gate ip6i->ip6i_flags = 0; 4311*0Sstevel@tonic-gate ip6i->ip6i_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 4312*0Sstevel@tonic-gate 4313*0Sstevel@tonic-gate /* sin6_scope_id takes precendence over IPPF_IFINDEX */ 4314*0Sstevel@tonic-gate if (option_exists & IPPF_SCOPE_ID) { 4315*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_IFINDEX; 4316*0Sstevel@tonic-gate ip6i->ip6i_ifindex = sin6->sin6_scope_id; 4317*0Sstevel@tonic-gate } else if (option_exists & IPPF_IFINDEX) { 4318*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_IFINDEX); 4319*0Sstevel@tonic-gate ASSERT(tipp->ipp_ifindex != 0); 4320*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_IFINDEX; 4321*0Sstevel@tonic-gate ip6i->ip6i_ifindex = tipp->ipp_ifindex; 4322*0Sstevel@tonic-gate } 4323*0Sstevel@tonic-gate 4324*0Sstevel@tonic-gate if (option_exists & IPPF_RAW_CKSUM) { 4325*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_RAW_CHECKSUM; 4326*0Sstevel@tonic-gate ip6i->ip6i_checksum_off = icmp->icmp_checksum_off; 4327*0Sstevel@tonic-gate } 4328*0Sstevel@tonic-gate 4329*0Sstevel@tonic-gate if (option_exists & IPPF_NO_CKSUM) { 4330*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_NO_ULP_CKSUM; 4331*0Sstevel@tonic-gate } 4332*0Sstevel@tonic-gate 4333*0Sstevel@tonic-gate if (option_exists & IPPF_ADDR) { 4334*0Sstevel@tonic-gate /* 4335*0Sstevel@tonic-gate * Enable per-packet source address verification if 4336*0Sstevel@tonic-gate * IPV6_PKTINFO specified the source address. 4337*0Sstevel@tonic-gate * ip6_src is set in the transport's _wput function. 4338*0Sstevel@tonic-gate */ 4339*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_VERIFY_SRC; 4340*0Sstevel@tonic-gate } 4341*0Sstevel@tonic-gate 4342*0Sstevel@tonic-gate if (option_exists & IPPF_DONTFRAG) { 4343*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_DONTFRAG; 4344*0Sstevel@tonic-gate } 4345*0Sstevel@tonic-gate 4346*0Sstevel@tonic-gate if (option_exists & IPPF_USE_MIN_MTU) { 4347*0Sstevel@tonic-gate ip6i->ip6i_flags = IP6I_API_USE_MIN_MTU( 4348*0Sstevel@tonic-gate ip6i->ip6i_flags, ipp->ipp_use_min_mtu); 4349*0Sstevel@tonic-gate } 4350*0Sstevel@tonic-gate 4351*0Sstevel@tonic-gate if (option_exists & IPPF_NEXTHOP) { 4352*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_NEXTHOP); 4353*0Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&tipp->ipp_nexthop)); 4354*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_NEXTHOP; 4355*0Sstevel@tonic-gate ip6i->ip6i_nexthop = tipp->ipp_nexthop; 4356*0Sstevel@tonic-gate } 4357*0Sstevel@tonic-gate 4358*0Sstevel@tonic-gate /* 4359*0Sstevel@tonic-gate * tell IP this is an ip6i_t private header 4360*0Sstevel@tonic-gate */ 4361*0Sstevel@tonic-gate ip6i->ip6i_nxt = IPPROTO_RAW; 4362*0Sstevel@tonic-gate } 4363*0Sstevel@tonic-gate 4364*0Sstevel@tonic-gate /* Initialize IPv6 header */ 4365*0Sstevel@tonic-gate ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 4366*0Sstevel@tonic-gate bzero(&ip6h->ip6_src, sizeof (ip6h->ip6_src)); 4367*0Sstevel@tonic-gate 4368*0Sstevel@tonic-gate if (option_exists & IPPF_HOPLIMIT) { 4369*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPLIMIT); 4370*0Sstevel@tonic-gate ip6h->ip6_hops = tipp->ipp_hoplimit; 4371*0Sstevel@tonic-gate } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) && 4372*0Sstevel@tonic-gate (icmp->icmp_sticky_ipp.ipp_fields & IPPF_MULTI_HOPLIMIT)) { 4373*0Sstevel@tonic-gate ip6h->ip6_hops = icmp->icmp_multicast_ttl; 4374*0Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_HOPLIMIT; 4375*0Sstevel@tonic-gate } else { 4376*0Sstevel@tonic-gate ip6h->ip6_hops = icmp->icmp_ttl; 4377*0Sstevel@tonic-gate } 4378*0Sstevel@tonic-gate 4379*0Sstevel@tonic-gate if (option_exists & IPPF_ADDR) { 4380*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_ADDR); 4381*0Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&tipp->ipp_addr)); 4382*0Sstevel@tonic-gate ip6h->ip6_src = tipp->ipp_addr; 4383*0Sstevel@tonic-gate } else { 4384*0Sstevel@tonic-gate /* 4385*0Sstevel@tonic-gate * The source address was not set using IPV6_PKTINFO. 4386*0Sstevel@tonic-gate * First look at the bound source. 4387*0Sstevel@tonic-gate * If unspecified fallback to __sin6_src_id. 4388*0Sstevel@tonic-gate */ 4389*0Sstevel@tonic-gate ip6h->ip6_src = icmp->icmp_v6src; 4390*0Sstevel@tonic-gate if (sin6->__sin6_src_id != 0 && 4391*0Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src)) { 4392*0Sstevel@tonic-gate ip_srcid_find_id(sin6->__sin6_src_id, 4393*0Sstevel@tonic-gate &ip6h->ip6_src, icmp->icmp_zoneid); 4394*0Sstevel@tonic-gate } 4395*0Sstevel@tonic-gate } 4396*0Sstevel@tonic-gate 4397*0Sstevel@tonic-gate nxthdr_ptr = (uint8_t *)&ip6h->ip6_nxt; 4398*0Sstevel@tonic-gate cp = (uint8_t *)&ip6h[1]; 4399*0Sstevel@tonic-gate 4400*0Sstevel@tonic-gate /* 4401*0Sstevel@tonic-gate * Here's where we have to start stringing together 4402*0Sstevel@tonic-gate * any extension headers in the right order: 4403*0Sstevel@tonic-gate * Hop-by-hop, destination, routing, and final destination opts. 4404*0Sstevel@tonic-gate */ 4405*0Sstevel@tonic-gate if (option_exists & IPPF_HOPOPTS) { 4406*0Sstevel@tonic-gate /* Hop-by-hop options */ 4407*0Sstevel@tonic-gate ip6_hbh_t *hbh = (ip6_hbh_t *)cp; 4408*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPOPTS); 4409*0Sstevel@tonic-gate 4410*0Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_HOPOPTS; 4411*0Sstevel@tonic-gate nxthdr_ptr = &hbh->ip6h_nxt; 4412*0Sstevel@tonic-gate 4413*0Sstevel@tonic-gate bcopy(tipp->ipp_hopopts, cp, tipp->ipp_hopoptslen); 4414*0Sstevel@tonic-gate cp += tipp->ipp_hopoptslen; 4415*0Sstevel@tonic-gate } 4416*0Sstevel@tonic-gate /* 4417*0Sstevel@tonic-gate * En-route destination options 4418*0Sstevel@tonic-gate * Only do them if there's a routing header as well 4419*0Sstevel@tonic-gate */ 4420*0Sstevel@tonic-gate if (option_exists & IPPF_RTDSTOPTS) { 4421*0Sstevel@tonic-gate ip6_dest_t *dst = (ip6_dest_t *)cp; 4422*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_RTDSTOPTS); 4423*0Sstevel@tonic-gate 4424*0Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_DSTOPTS; 4425*0Sstevel@tonic-gate nxthdr_ptr = &dst->ip6d_nxt; 4426*0Sstevel@tonic-gate 4427*0Sstevel@tonic-gate bcopy(tipp->ipp_rtdstopts, cp, tipp->ipp_rtdstoptslen); 4428*0Sstevel@tonic-gate cp += tipp->ipp_rtdstoptslen; 4429*0Sstevel@tonic-gate } 4430*0Sstevel@tonic-gate /* 4431*0Sstevel@tonic-gate * Routing header next 4432*0Sstevel@tonic-gate */ 4433*0Sstevel@tonic-gate if (option_exists & IPPF_RTHDR) { 4434*0Sstevel@tonic-gate ip6_rthdr_t *rt = (ip6_rthdr_t *)cp; 4435*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_RTHDR); 4436*0Sstevel@tonic-gate 4437*0Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_ROUTING; 4438*0Sstevel@tonic-gate nxthdr_ptr = &rt->ip6r_nxt; 4439*0Sstevel@tonic-gate 4440*0Sstevel@tonic-gate bcopy(tipp->ipp_rthdr, cp, tipp->ipp_rthdrlen); 4441*0Sstevel@tonic-gate cp += tipp->ipp_rthdrlen; 4442*0Sstevel@tonic-gate } 4443*0Sstevel@tonic-gate /* 4444*0Sstevel@tonic-gate * Do ultimate destination options 4445*0Sstevel@tonic-gate */ 4446*0Sstevel@tonic-gate if (option_exists & IPPF_DSTOPTS) { 4447*0Sstevel@tonic-gate ip6_dest_t *dest = (ip6_dest_t *)cp; 4448*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_DSTOPTS); 4449*0Sstevel@tonic-gate 4450*0Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_DSTOPTS; 4451*0Sstevel@tonic-gate nxthdr_ptr = &dest->ip6d_nxt; 4452*0Sstevel@tonic-gate 4453*0Sstevel@tonic-gate bcopy(tipp->ipp_dstopts, cp, tipp->ipp_dstoptslen); 4454*0Sstevel@tonic-gate cp += tipp->ipp_dstoptslen; 4455*0Sstevel@tonic-gate } 4456*0Sstevel@tonic-gate 4457*0Sstevel@tonic-gate /* 4458*0Sstevel@tonic-gate * Now set the last header pointer to the proto passed in 4459*0Sstevel@tonic-gate */ 4460*0Sstevel@tonic-gate ASSERT((int)(cp - (uint8_t *)ip6i) == ip_hdr_len); 4461*0Sstevel@tonic-gate *nxthdr_ptr = icmp->icmp_proto; 4462*0Sstevel@tonic-gate 4463*0Sstevel@tonic-gate /* 4464*0Sstevel@tonic-gate * Copy in the destination address 4465*0Sstevel@tonic-gate */ 4466*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) 4467*0Sstevel@tonic-gate ip6h->ip6_dst = ipv6_loopback; 4468*0Sstevel@tonic-gate else 4469*0Sstevel@tonic-gate ip6h->ip6_dst = sin6->sin6_addr; 4470*0Sstevel@tonic-gate 4471*0Sstevel@tonic-gate ip6h->ip6_vcf = 4472*0Sstevel@tonic-gate (IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) | 4473*0Sstevel@tonic-gate (sin6->sin6_flowinfo & ~IPV6_VERS_AND_FLOW_MASK); 4474*0Sstevel@tonic-gate 4475*0Sstevel@tonic-gate if (option_exists & IPPF_TCLASS) { 4476*0Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_TCLASS); 4477*0Sstevel@tonic-gate ip6h->ip6_vcf = IPV6_TCLASS_FLOW(ip6h->ip6_vcf, 4478*0Sstevel@tonic-gate tipp->ipp_tclass); 4479*0Sstevel@tonic-gate } 4480*0Sstevel@tonic-gate if (option_exists & IPPF_RTHDR) { 4481*0Sstevel@tonic-gate ip6_rthdr_t *rth; 4482*0Sstevel@tonic-gate 4483*0Sstevel@tonic-gate /* 4484*0Sstevel@tonic-gate * Perform any processing needed for source routing. 4485*0Sstevel@tonic-gate * We know that all extension headers will be in the same mblk 4486*0Sstevel@tonic-gate * as the IPv6 header. 4487*0Sstevel@tonic-gate */ 4488*0Sstevel@tonic-gate rth = ip_find_rthdr_v6(ip6h, mp1->b_wptr); 4489*0Sstevel@tonic-gate if (rth != NULL && rth->ip6r_segleft != 0) { 4490*0Sstevel@tonic-gate if (rth->ip6r_type != IPV6_RTHDR_TYPE_0) { 4491*0Sstevel@tonic-gate /* 4492*0Sstevel@tonic-gate * Drop packet - only support Type 0 routing. 4493*0Sstevel@tonic-gate * Notify the application as well. 4494*0Sstevel@tonic-gate */ 4495*0Sstevel@tonic-gate icmp_ud_err(q, mp, EPROTO); 4496*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4497*0Sstevel@tonic-gate return; 4498*0Sstevel@tonic-gate } 4499*0Sstevel@tonic-gate /* 4500*0Sstevel@tonic-gate * rth->ip6r_len is twice the number of 4501*0Sstevel@tonic-gate * addresses in the header 4502*0Sstevel@tonic-gate */ 4503*0Sstevel@tonic-gate if (rth->ip6r_len & 0x1) { 4504*0Sstevel@tonic-gate icmp_ud_err(q, mp, EPROTO); 4505*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4506*0Sstevel@tonic-gate return; 4507*0Sstevel@tonic-gate } 4508*0Sstevel@tonic-gate /* 4509*0Sstevel@tonic-gate * Shuffle the routing header and ip6_dst 4510*0Sstevel@tonic-gate * addresses, and get the checksum difference 4511*0Sstevel@tonic-gate * between the first hop (in ip6_dst) and 4512*0Sstevel@tonic-gate * the destination (in the last routing hdr entry). 4513*0Sstevel@tonic-gate */ 4514*0Sstevel@tonic-gate csum = ip_massage_options_v6(ip6h, rth); 4515*0Sstevel@tonic-gate /* 4516*0Sstevel@tonic-gate * Verify that the first hop isn't a mapped address. 4517*0Sstevel@tonic-gate * Routers along the path need to do this verification 4518*0Sstevel@tonic-gate * for subsequent hops. 4519*0Sstevel@tonic-gate */ 4520*0Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) { 4521*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 4522*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4523*0Sstevel@tonic-gate return; 4524*0Sstevel@tonic-gate } 4525*0Sstevel@tonic-gate } 4526*0Sstevel@tonic-gate } 4527*0Sstevel@tonic-gate 4528*0Sstevel@tonic-gate ip_len = mp1->b_wptr - (uchar_t *)ip6h - IPV6_HDR_LEN; 4529*0Sstevel@tonic-gate if (mp1->b_cont != NULL) 4530*0Sstevel@tonic-gate ip_len += msgdsize(mp1->b_cont); 4531*0Sstevel@tonic-gate 4532*0Sstevel@tonic-gate /* 4533*0Sstevel@tonic-gate * Set the length into the IP header. 4534*0Sstevel@tonic-gate * If the length is greater than the maximum allowed by IP, 4535*0Sstevel@tonic-gate * then free the message and return. Do not try and send it 4536*0Sstevel@tonic-gate * as this can cause problems in layers below. 4537*0Sstevel@tonic-gate */ 4538*0Sstevel@tonic-gate if (ip_len > IP_MAXPACKET) { 4539*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4540*0Sstevel@tonic-gate icmp_ud_err(q, mp1, EMSGSIZE); 4541*0Sstevel@tonic-gate return; 4542*0Sstevel@tonic-gate } 4543*0Sstevel@tonic-gate if (icmp->icmp_proto == IPPROTO_ICMPV6 || icmp->icmp_raw_checksum) { 4544*0Sstevel@tonic-gate uint_t cksum_off; /* From ip6i == mp1->b_rptr */ 4545*0Sstevel@tonic-gate uint16_t *cksum_ptr; 4546*0Sstevel@tonic-gate uint_t ext_hdrs_len; 4547*0Sstevel@tonic-gate 4548*0Sstevel@tonic-gate /* ICMPv6 must have an offset matching icmp6_cksum offset */ 4549*0Sstevel@tonic-gate ASSERT(icmp->icmp_proto != IPPROTO_ICMPV6 || 4550*0Sstevel@tonic-gate icmp->icmp_checksum_off == 2); 4551*0Sstevel@tonic-gate 4552*0Sstevel@tonic-gate /* 4553*0Sstevel@tonic-gate * We make it easy for IP to include our pseudo header 4554*0Sstevel@tonic-gate * by putting our length in uh_checksum, modified (if 4555*0Sstevel@tonic-gate * we have a routing header) by the checksum difference 4556*0Sstevel@tonic-gate * between the ultimate destination and first hop addresses. 4557*0Sstevel@tonic-gate * Note: ICMPv6 must always checksum the packet. 4558*0Sstevel@tonic-gate */ 4559*0Sstevel@tonic-gate cksum_off = ip_hdr_len + icmp->icmp_checksum_off; 4560*0Sstevel@tonic-gate if (cksum_off + sizeof (uint16_t) > mp1->b_wptr - mp1->b_rptr) { 4561*0Sstevel@tonic-gate if (!pullupmsg(mp1, cksum_off + sizeof (uint16_t))) { 4562*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutErrors); 4563*0Sstevel@tonic-gate freemsg(mp); 4564*0Sstevel@tonic-gate return; 4565*0Sstevel@tonic-gate } 4566*0Sstevel@tonic-gate ip6i = (ip6i_t *)mp1->b_rptr; 4567*0Sstevel@tonic-gate if (ip6i->ip6i_nxt == IPPROTO_RAW) 4568*0Sstevel@tonic-gate ip6h = (ip6_t *)&ip6i[1]; 4569*0Sstevel@tonic-gate else 4570*0Sstevel@tonic-gate ip6h = (ip6_t *)ip6i; 4571*0Sstevel@tonic-gate } 4572*0Sstevel@tonic-gate /* Add payload length to checksum */ 4573*0Sstevel@tonic-gate ext_hdrs_len = ip_hdr_len - IPV6_HDR_LEN - 4574*0Sstevel@tonic-gate (int)((uchar_t *)ip6h - (uchar_t *)ip6i); 4575*0Sstevel@tonic-gate csum += htons(ip_len - ext_hdrs_len); 4576*0Sstevel@tonic-gate 4577*0Sstevel@tonic-gate cksum_ptr = (uint16_t *)((uchar_t *)ip6i + cksum_off); 4578*0Sstevel@tonic-gate csum = (csum & 0xFFFF) + (csum >> 16); 4579*0Sstevel@tonic-gate *cksum_ptr = (uint16_t)csum; 4580*0Sstevel@tonic-gate } 4581*0Sstevel@tonic-gate 4582*0Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 4583*0Sstevel@tonic-gate ip_len = htons(ip_len); 4584*0Sstevel@tonic-gate #endif 4585*0Sstevel@tonic-gate ip6h->ip6_plen = (uint16_t)ip_len; 4586*0Sstevel@tonic-gate 4587*0Sstevel@tonic-gate freeb(mp); 4588*0Sstevel@tonic-gate 4589*0Sstevel@tonic-gate /* We're done. Pass the packet to IP */ 4590*0Sstevel@tonic-gate BUMP_MIB(&rawip_mib, rawipOutDatagrams); 4591*0Sstevel@tonic-gate putnext(q, mp1); 4592*0Sstevel@tonic-gate } 4593*0Sstevel@tonic-gate 4594*0Sstevel@tonic-gate static void 4595*0Sstevel@tonic-gate icmp_wput_other(queue_t *q, mblk_t *mp) 4596*0Sstevel@tonic-gate { 4597*0Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 4598*0Sstevel@tonic-gate struct iocblk *iocp; 4599*0Sstevel@tonic-gate #define tudr ((struct T_unitdata_req *)rptr) 4600*0Sstevel@tonic-gate icmp_t *icmp; 4601*0Sstevel@tonic-gate cred_t *cr; 4602*0Sstevel@tonic-gate 4603*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 4604*0Sstevel@tonic-gate 4605*0Sstevel@tonic-gate cr = DB_CREDDEF(mp, icmp->icmp_credp); 4606*0Sstevel@tonic-gate 4607*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 4608*0Sstevel@tonic-gate case M_PROTO: 4609*0Sstevel@tonic-gate case M_PCPROTO: 4610*0Sstevel@tonic-gate if (mp->b_wptr - rptr < sizeof (t_scalar_t)) { 4611*0Sstevel@tonic-gate /* 4612*0Sstevel@tonic-gate * If the message does not contain a PRIM_type, 4613*0Sstevel@tonic-gate * throw it away. 4614*0Sstevel@tonic-gate */ 4615*0Sstevel@tonic-gate freemsg(mp); 4616*0Sstevel@tonic-gate return; 4617*0Sstevel@tonic-gate } 4618*0Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 4619*0Sstevel@tonic-gate case T_ADDR_REQ: 4620*0Sstevel@tonic-gate icmp_addr_req(q, mp); 4621*0Sstevel@tonic-gate return; 4622*0Sstevel@tonic-gate case O_T_BIND_REQ: 4623*0Sstevel@tonic-gate case T_BIND_REQ: 4624*0Sstevel@tonic-gate qwriter(q, mp, icmp_bind, PERIM_OUTER); 4625*0Sstevel@tonic-gate return; 4626*0Sstevel@tonic-gate case T_CONN_REQ: 4627*0Sstevel@tonic-gate icmp_connect(q, mp); 4628*0Sstevel@tonic-gate return; 4629*0Sstevel@tonic-gate case T_CAPABILITY_REQ: 4630*0Sstevel@tonic-gate icmp_capability_req(q, mp); 4631*0Sstevel@tonic-gate return; 4632*0Sstevel@tonic-gate case T_INFO_REQ: 4633*0Sstevel@tonic-gate icmp_info_req(q, mp); 4634*0Sstevel@tonic-gate return; 4635*0Sstevel@tonic-gate case T_UNITDATA_REQ: 4636*0Sstevel@tonic-gate /* 4637*0Sstevel@tonic-gate * If a T_UNITDATA_REQ gets here, the address must 4638*0Sstevel@tonic-gate * be bad. Valid T_UNITDATA_REQs are found above 4639*0Sstevel@tonic-gate * and break to below this switch. 4640*0Sstevel@tonic-gate */ 4641*0Sstevel@tonic-gate icmp_ud_err(q, mp, EADDRNOTAVAIL); 4642*0Sstevel@tonic-gate return; 4643*0Sstevel@tonic-gate case T_UNBIND_REQ: 4644*0Sstevel@tonic-gate icmp_unbind(q, mp); 4645*0Sstevel@tonic-gate return; 4646*0Sstevel@tonic-gate 4647*0Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 4648*0Sstevel@tonic-gate if (!snmpcom_req(q, mp, icmp_snmp_set, icmp_snmp_get, 4649*0Sstevel@tonic-gate cr)) 4650*0Sstevel@tonic-gate /* Only IP can return anything meaningful */ 4651*0Sstevel@tonic-gate (void) svr4_optcom_req(q, mp, cr, 4652*0Sstevel@tonic-gate &icmp_opt_obj); 4653*0Sstevel@tonic-gate return; 4654*0Sstevel@tonic-gate 4655*0Sstevel@tonic-gate case T_OPTMGMT_REQ: 4656*0Sstevel@tonic-gate /* Only IP can return anything meaningful */ 4657*0Sstevel@tonic-gate (void) tpi_optcom_req(q, mp, cr, &icmp_opt_obj); 4658*0Sstevel@tonic-gate return; 4659*0Sstevel@tonic-gate 4660*0Sstevel@tonic-gate case T_DISCON_REQ: 4661*0Sstevel@tonic-gate icmp_disconnect(q, mp); 4662*0Sstevel@tonic-gate return; 4663*0Sstevel@tonic-gate 4664*0Sstevel@tonic-gate /* The following TPI message is not supported by icmp. */ 4665*0Sstevel@tonic-gate case O_T_CONN_RES: 4666*0Sstevel@tonic-gate case T_CONN_RES: 4667*0Sstevel@tonic-gate icmp_err_ack(q, mp, TNOTSUPPORT, 0); 4668*0Sstevel@tonic-gate return; 4669*0Sstevel@tonic-gate 4670*0Sstevel@tonic-gate /* The following 3 TPI requests are illegal for icmp. */ 4671*0Sstevel@tonic-gate case T_DATA_REQ: 4672*0Sstevel@tonic-gate case T_EXDATA_REQ: 4673*0Sstevel@tonic-gate case T_ORDREL_REQ: 4674*0Sstevel@tonic-gate freemsg(mp); 4675*0Sstevel@tonic-gate (void) putctl1(RD(q), M_ERROR, EPROTO); 4676*0Sstevel@tonic-gate return; 4677*0Sstevel@tonic-gate default: 4678*0Sstevel@tonic-gate break; 4679*0Sstevel@tonic-gate } 4680*0Sstevel@tonic-gate break; 4681*0Sstevel@tonic-gate case M_IOCTL: 4682*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 4683*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 4684*0Sstevel@tonic-gate case TI_GETPEERNAME: 4685*0Sstevel@tonic-gate if (icmp->icmp_state != TS_DATA_XFER) { 4686*0Sstevel@tonic-gate /* 4687*0Sstevel@tonic-gate * If a default destination address has not 4688*0Sstevel@tonic-gate * been associated with the stream, then we 4689*0Sstevel@tonic-gate * don't know the peer's name. 4690*0Sstevel@tonic-gate */ 4691*0Sstevel@tonic-gate iocp->ioc_error = ENOTCONN; 4692*0Sstevel@tonic-gate err_ret:; 4693*0Sstevel@tonic-gate iocp->ioc_count = 0; 4694*0Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 4695*0Sstevel@tonic-gate qreply(q, mp); 4696*0Sstevel@tonic-gate return; 4697*0Sstevel@tonic-gate } 4698*0Sstevel@tonic-gate /* FALLTHRU */ 4699*0Sstevel@tonic-gate case TI_GETMYNAME: 4700*0Sstevel@tonic-gate /* 4701*0Sstevel@tonic-gate * For TI_GETPEERNAME and TI_GETMYNAME, we first 4702*0Sstevel@tonic-gate * need to copyin the user's strbuf structure. 4703*0Sstevel@tonic-gate * Processing will continue in the M_IOCDATA case 4704*0Sstevel@tonic-gate * below. 4705*0Sstevel@tonic-gate */ 4706*0Sstevel@tonic-gate mi_copyin(q, mp, NULL, 4707*0Sstevel@tonic-gate SIZEOF_STRUCT(strbuf, iocp->ioc_flag)); 4708*0Sstevel@tonic-gate return; 4709*0Sstevel@tonic-gate case ND_SET: 4710*0Sstevel@tonic-gate /* nd_getset performs the necessary error checking */ 4711*0Sstevel@tonic-gate case ND_GET: 4712*0Sstevel@tonic-gate if (nd_getset(q, icmp_g_nd, mp)) { 4713*0Sstevel@tonic-gate qreply(q, mp); 4714*0Sstevel@tonic-gate return; 4715*0Sstevel@tonic-gate } 4716*0Sstevel@tonic-gate break; 4717*0Sstevel@tonic-gate default: 4718*0Sstevel@tonic-gate break; 4719*0Sstevel@tonic-gate } 4720*0Sstevel@tonic-gate break; 4721*0Sstevel@tonic-gate case M_IOCDATA: 4722*0Sstevel@tonic-gate icmp_wput_iocdata(q, mp); 4723*0Sstevel@tonic-gate return; 4724*0Sstevel@tonic-gate default: 4725*0Sstevel@tonic-gate break; 4726*0Sstevel@tonic-gate } 4727*0Sstevel@tonic-gate putnext(q, mp); 4728*0Sstevel@tonic-gate } 4729*0Sstevel@tonic-gate 4730*0Sstevel@tonic-gate /* 4731*0Sstevel@tonic-gate * icmp_wput_iocdata is called by icmp_wput_slow to handle all M_IOCDATA 4732*0Sstevel@tonic-gate * messages. 4733*0Sstevel@tonic-gate */ 4734*0Sstevel@tonic-gate static void 4735*0Sstevel@tonic-gate icmp_wput_iocdata(queue_t *q, mblk_t *mp) 4736*0Sstevel@tonic-gate { 4737*0Sstevel@tonic-gate mblk_t *mp1; 4738*0Sstevel@tonic-gate STRUCT_HANDLE(strbuf, sb); 4739*0Sstevel@tonic-gate icmp_t *icmp; 4740*0Sstevel@tonic-gate in6_addr_t v6addr; 4741*0Sstevel@tonic-gate ipaddr_t v4addr; 4742*0Sstevel@tonic-gate uint32_t flowinfo = 0; 4743*0Sstevel@tonic-gate int addrlen; 4744*0Sstevel@tonic-gate 4745*0Sstevel@tonic-gate /* Make sure it is one of ours. */ 4746*0Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 4747*0Sstevel@tonic-gate case TI_GETMYNAME: 4748*0Sstevel@tonic-gate case TI_GETPEERNAME: 4749*0Sstevel@tonic-gate break; 4750*0Sstevel@tonic-gate default: 4751*0Sstevel@tonic-gate putnext(q, mp); 4752*0Sstevel@tonic-gate return; 4753*0Sstevel@tonic-gate } 4754*0Sstevel@tonic-gate switch (mi_copy_state(q, mp, &mp1)) { 4755*0Sstevel@tonic-gate case -1: 4756*0Sstevel@tonic-gate return; 4757*0Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_IN, 1): 4758*0Sstevel@tonic-gate break; 4759*0Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 1): 4760*0Sstevel@tonic-gate /* 4761*0Sstevel@tonic-gate * The address has been copied out, so now 4762*0Sstevel@tonic-gate * copyout the strbuf. 4763*0Sstevel@tonic-gate */ 4764*0Sstevel@tonic-gate mi_copyout(q, mp); 4765*0Sstevel@tonic-gate return; 4766*0Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 2): 4767*0Sstevel@tonic-gate /* 4768*0Sstevel@tonic-gate * The address and strbuf have been copied out. 4769*0Sstevel@tonic-gate * We're done, so just acknowledge the original 4770*0Sstevel@tonic-gate * M_IOCTL. 4771*0Sstevel@tonic-gate */ 4772*0Sstevel@tonic-gate mi_copy_done(q, mp, 0); 4773*0Sstevel@tonic-gate return; 4774*0Sstevel@tonic-gate default: 4775*0Sstevel@tonic-gate /* 4776*0Sstevel@tonic-gate * Something strange has happened, so acknowledge 4777*0Sstevel@tonic-gate * the original M_IOCTL with an EPROTO error. 4778*0Sstevel@tonic-gate */ 4779*0Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 4780*0Sstevel@tonic-gate return; 4781*0Sstevel@tonic-gate } 4782*0Sstevel@tonic-gate /* 4783*0Sstevel@tonic-gate * Now we have the strbuf structure for TI_GETMYNAME 4784*0Sstevel@tonic-gate * and TI_GETPEERNAME. Next we copyout the requested 4785*0Sstevel@tonic-gate * address and then we'll copyout the strbuf. 4786*0Sstevel@tonic-gate */ 4787*0Sstevel@tonic-gate STRUCT_SET_HANDLE(sb, ((struct iocblk *)mp->b_rptr)->ioc_flag, 4788*0Sstevel@tonic-gate (void *)mp1->b_rptr); 4789*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 4790*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) 4791*0Sstevel@tonic-gate addrlen = sizeof (sin_t); 4792*0Sstevel@tonic-gate else 4793*0Sstevel@tonic-gate addrlen = sizeof (sin6_t); 4794*0Sstevel@tonic-gate 4795*0Sstevel@tonic-gate if (STRUCT_FGET(sb, maxlen) < addrlen) { 4796*0Sstevel@tonic-gate mi_copy_done(q, mp, EINVAL); 4797*0Sstevel@tonic-gate return; 4798*0Sstevel@tonic-gate } 4799*0Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 4800*0Sstevel@tonic-gate case TI_GETMYNAME: 4801*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 4802*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV4_VERSION); 4803*0Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&icmp->icmp_v6src) && 4804*0Sstevel@tonic-gate !IN6_IS_ADDR_UNSPECIFIED(&icmp->icmp_v6src)) { 4805*0Sstevel@tonic-gate v4addr = V4_PART_OF_V6(icmp->icmp_v6src); 4806*0Sstevel@tonic-gate } else { 4807*0Sstevel@tonic-gate /* 4808*0Sstevel@tonic-gate * INADDR_ANY 4809*0Sstevel@tonic-gate * icmp_v6src is not set, we might be bound to 4810*0Sstevel@tonic-gate * broadcast/multicast. Use icmp_bound_v6src as 4811*0Sstevel@tonic-gate * local address instead (that could 4812*0Sstevel@tonic-gate * also still be INADDR_ANY) 4813*0Sstevel@tonic-gate */ 4814*0Sstevel@tonic-gate v4addr = V4_PART_OF_V6(icmp->icmp_bound_v6src); 4815*0Sstevel@tonic-gate } 4816*0Sstevel@tonic-gate } else { 4817*0Sstevel@tonic-gate /* icmp->icmp_family == AF_INET6 */ 4818*0Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&icmp->icmp_v6src)) { 4819*0Sstevel@tonic-gate v6addr = icmp->icmp_v6src; 4820*0Sstevel@tonic-gate } else { 4821*0Sstevel@tonic-gate /* 4822*0Sstevel@tonic-gate * UNSPECIFIED 4823*0Sstevel@tonic-gate * icmp_v6src is not set, we might be bound to 4824*0Sstevel@tonic-gate * broadcast/multicast. Use icmp_bound_v6src as 4825*0Sstevel@tonic-gate * local address instead (that could 4826*0Sstevel@tonic-gate * also still be UNSPECIFIED) 4827*0Sstevel@tonic-gate */ 4828*0Sstevel@tonic-gate v6addr = icmp->icmp_bound_v6src; 4829*0Sstevel@tonic-gate } 4830*0Sstevel@tonic-gate } 4831*0Sstevel@tonic-gate break; 4832*0Sstevel@tonic-gate case TI_GETPEERNAME: 4833*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 4834*0Sstevel@tonic-gate ASSERT(icmp->icmp_ipversion == IPV4_VERSION); 4835*0Sstevel@tonic-gate v4addr = V4_PART_OF_V6(icmp->icmp_v6dst); 4836*0Sstevel@tonic-gate } else { 4837*0Sstevel@tonic-gate /* icmp->icmp_family == AF_INET6) */ 4838*0Sstevel@tonic-gate v6addr = icmp->icmp_v6dst; 4839*0Sstevel@tonic-gate flowinfo = icmp->icmp_flowinfo; 4840*0Sstevel@tonic-gate } 4841*0Sstevel@tonic-gate break; 4842*0Sstevel@tonic-gate default: 4843*0Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 4844*0Sstevel@tonic-gate return; 4845*0Sstevel@tonic-gate } 4846*0Sstevel@tonic-gate mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), addrlen, B_TRUE); 4847*0Sstevel@tonic-gate if (!mp1) 4848*0Sstevel@tonic-gate return; 4849*0Sstevel@tonic-gate 4850*0Sstevel@tonic-gate if (icmp->icmp_family == AF_INET) { 4851*0Sstevel@tonic-gate sin_t *sin; 4852*0Sstevel@tonic-gate 4853*0Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin_t)); 4854*0Sstevel@tonic-gate sin = (sin_t *)mp1->b_rptr; 4855*0Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&sin[1]; 4856*0Sstevel@tonic-gate *sin = sin_null; 4857*0Sstevel@tonic-gate sin->sin_family = AF_INET; 4858*0Sstevel@tonic-gate sin->sin_addr.s_addr = v4addr; 4859*0Sstevel@tonic-gate } else { 4860*0Sstevel@tonic-gate /* icmp->icmp_family == AF_INET6 */ 4861*0Sstevel@tonic-gate sin6_t *sin6; 4862*0Sstevel@tonic-gate 4863*0Sstevel@tonic-gate ASSERT(icmp->icmp_family == AF_INET6); 4864*0Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin6_t)); 4865*0Sstevel@tonic-gate sin6 = (sin6_t *)mp1->b_rptr; 4866*0Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&sin6[1]; 4867*0Sstevel@tonic-gate *sin6 = sin6_null; 4868*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 4869*0Sstevel@tonic-gate sin6->sin6_flowinfo = flowinfo; 4870*0Sstevel@tonic-gate sin6->sin6_addr = v6addr; 4871*0Sstevel@tonic-gate } 4872*0Sstevel@tonic-gate /* Copy out the address */ 4873*0Sstevel@tonic-gate mi_copyout(q, mp); 4874*0Sstevel@tonic-gate } 4875*0Sstevel@tonic-gate 4876*0Sstevel@tonic-gate /* 4877*0Sstevel@tonic-gate * Only allow MIB requests and M_FLUSHes to pass. 4878*0Sstevel@tonic-gate * All other messages are nacked or dropped. 4879*0Sstevel@tonic-gate */ 4880*0Sstevel@tonic-gate static void 4881*0Sstevel@tonic-gate icmp_wput_restricted(queue_t *q, mblk_t *mp) 4882*0Sstevel@tonic-gate { 4883*0Sstevel@tonic-gate cred_t *cr; 4884*0Sstevel@tonic-gate icmp_t *icmp; 4885*0Sstevel@tonic-gate 4886*0Sstevel@tonic-gate switch (DB_TYPE(mp)) { 4887*0Sstevel@tonic-gate case M_PROTO: 4888*0Sstevel@tonic-gate case M_PCPROTO: 4889*0Sstevel@tonic-gate if (MBLKL(mp) < sizeof (t_scalar_t)) { 4890*0Sstevel@tonic-gate freemsg(mp); 4891*0Sstevel@tonic-gate return; 4892*0Sstevel@tonic-gate } 4893*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 4894*0Sstevel@tonic-gate cr = DB_CREDDEF(mp, icmp->icmp_credp); 4895*0Sstevel@tonic-gate 4896*0Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 4897*0Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 4898*0Sstevel@tonic-gate if (!snmpcom_req(q, mp, 4899*0Sstevel@tonic-gate icmp_snmp_set, icmp_snmp_get, cr)) 4900*0Sstevel@tonic-gate (void) svr4_optcom_req(q, mp, cr, 4901*0Sstevel@tonic-gate &icmp_opt_obj); 4902*0Sstevel@tonic-gate return; 4903*0Sstevel@tonic-gate case T_OPTMGMT_REQ: 4904*0Sstevel@tonic-gate (void) tpi_optcom_req(q, mp, cr, &icmp_opt_obj); 4905*0Sstevel@tonic-gate return; 4906*0Sstevel@tonic-gate default: 4907*0Sstevel@tonic-gate icmp_err_ack(q, mp, TSYSERR, ENOTSUP); 4908*0Sstevel@tonic-gate return; 4909*0Sstevel@tonic-gate } 4910*0Sstevel@tonic-gate /* NOTREACHED */ 4911*0Sstevel@tonic-gate case M_IOCTL: 4912*0Sstevel@tonic-gate miocnak(q, mp, 0, ENOTSUP); 4913*0Sstevel@tonic-gate break; 4914*0Sstevel@tonic-gate case M_FLUSH: 4915*0Sstevel@tonic-gate putnext(q, mp); 4916*0Sstevel@tonic-gate break; 4917*0Sstevel@tonic-gate default: 4918*0Sstevel@tonic-gate freemsg(mp); 4919*0Sstevel@tonic-gate break; 4920*0Sstevel@tonic-gate } 4921*0Sstevel@tonic-gate } 4922*0Sstevel@tonic-gate 4923*0Sstevel@tonic-gate static int 4924*0Sstevel@tonic-gate icmp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp, 4925*0Sstevel@tonic-gate void *thisdg_attrs) 4926*0Sstevel@tonic-gate { 4927*0Sstevel@tonic-gate icmp_t *icmp; 4928*0Sstevel@tonic-gate struct T_unitdata_req *udreqp; 4929*0Sstevel@tonic-gate int is_absreq_failure; 4930*0Sstevel@tonic-gate cred_t *cr; 4931*0Sstevel@tonic-gate 4932*0Sstevel@tonic-gate icmp = (icmp_t *)q->q_ptr; 4933*0Sstevel@tonic-gate 4934*0Sstevel@tonic-gate udreqp = (struct T_unitdata_req *)mp->b_rptr; 4935*0Sstevel@tonic-gate *errorp = 0; 4936*0Sstevel@tonic-gate 4937*0Sstevel@tonic-gate cr = DB_CREDDEF(mp, icmp->icmp_credp); 4938*0Sstevel@tonic-gate 4939*0Sstevel@tonic-gate *errorp = tpi_optcom_buf(q, mp, &udreqp->OPT_length, 4940*0Sstevel@tonic-gate udreqp->OPT_offset, cr, &icmp_opt_obj, 4941*0Sstevel@tonic-gate thisdg_attrs, &is_absreq_failure); 4942*0Sstevel@tonic-gate 4943*0Sstevel@tonic-gate if (*errorp != 0) { 4944*0Sstevel@tonic-gate /* 4945*0Sstevel@tonic-gate * Note: No special action needed in this 4946*0Sstevel@tonic-gate * module for "is_absreq_failure" 4947*0Sstevel@tonic-gate */ 4948*0Sstevel@tonic-gate return (-1); /* failure */ 4949*0Sstevel@tonic-gate } 4950*0Sstevel@tonic-gate ASSERT(is_absreq_failure == 0); 4951*0Sstevel@tonic-gate return (0); /* success */ 4952*0Sstevel@tonic-gate } 4953*0Sstevel@tonic-gate 4954*0Sstevel@tonic-gate void 4955*0Sstevel@tonic-gate icmp_ddi_init(void) 4956*0Sstevel@tonic-gate { 4957*0Sstevel@tonic-gate ICMP6_MAJ = ddi_name_to_major(ICMP6); 4958*0Sstevel@tonic-gate icmp_max_optsize = 4959*0Sstevel@tonic-gate optcom_max_optsize(icmp_opt_obj.odb_opt_des_arr, 4960*0Sstevel@tonic-gate icmp_opt_obj.odb_opt_arr_cnt); 4961*0Sstevel@tonic-gate 4962*0Sstevel@tonic-gate (void) icmp_param_register(icmp_param_arr, A_CNT(icmp_param_arr)); 4963*0Sstevel@tonic-gate 4964*0Sstevel@tonic-gate rawip_kstat_init(); 4965*0Sstevel@tonic-gate } 4966*0Sstevel@tonic-gate 4967*0Sstevel@tonic-gate void 4968*0Sstevel@tonic-gate icmp_ddi_destroy(void) 4969*0Sstevel@tonic-gate { 4970*0Sstevel@tonic-gate nd_free(&icmp_g_nd); 4971*0Sstevel@tonic-gate 4972*0Sstevel@tonic-gate rawip_kstat_fini(); 4973*0Sstevel@tonic-gate } 4974*0Sstevel@tonic-gate 4975*0Sstevel@tonic-gate static void 4976*0Sstevel@tonic-gate rawip_kstat_init(void) { 4977*0Sstevel@tonic-gate 4978*0Sstevel@tonic-gate rawip_named_kstat_t template = { 4979*0Sstevel@tonic-gate { "inDatagrams", KSTAT_DATA_UINT32, 0 }, 4980*0Sstevel@tonic-gate { "inCksumErrs", KSTAT_DATA_UINT32, 0 }, 4981*0Sstevel@tonic-gate { "inErrors", KSTAT_DATA_UINT32, 0 }, 4982*0Sstevel@tonic-gate { "outDatagrams", KSTAT_DATA_UINT32, 0 }, 4983*0Sstevel@tonic-gate { "outErrors", KSTAT_DATA_UINT32, 0 }, 4984*0Sstevel@tonic-gate }; 4985*0Sstevel@tonic-gate 4986*0Sstevel@tonic-gate rawip_mibkp = kstat_create("icmp", 0, "rawip", "mib2", 4987*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, 4988*0Sstevel@tonic-gate NUM_OF_FIELDS(rawip_named_kstat_t), 4989*0Sstevel@tonic-gate 0); 4990*0Sstevel@tonic-gate if (rawip_mibkp == NULL) 4991*0Sstevel@tonic-gate return; 4992*0Sstevel@tonic-gate 4993*0Sstevel@tonic-gate bcopy(&template, rawip_mibkp->ks_data, sizeof (template)); 4994*0Sstevel@tonic-gate 4995*0Sstevel@tonic-gate rawip_mibkp->ks_update = rawip_kstat_update; 4996*0Sstevel@tonic-gate 4997*0Sstevel@tonic-gate kstat_install(rawip_mibkp); 4998*0Sstevel@tonic-gate } 4999*0Sstevel@tonic-gate 5000*0Sstevel@tonic-gate static void 5001*0Sstevel@tonic-gate rawip_kstat_fini(void) { 5002*0Sstevel@tonic-gate if (rawip_mibkp) { 5003*0Sstevel@tonic-gate kstat_delete(rawip_mibkp); 5004*0Sstevel@tonic-gate rawip_mibkp = NULL; 5005*0Sstevel@tonic-gate } 5006*0Sstevel@tonic-gate } 5007*0Sstevel@tonic-gate 5008*0Sstevel@tonic-gate static int 5009*0Sstevel@tonic-gate rawip_kstat_update(kstat_t *kp, int rw) { 5010*0Sstevel@tonic-gate rawip_named_kstat_t *rawipkp; 5011*0Sstevel@tonic-gate 5012*0Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 5013*0Sstevel@tonic-gate return (EIO); 5014*0Sstevel@tonic-gate 5015*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) 5016*0Sstevel@tonic-gate return (EACCES); 5017*0Sstevel@tonic-gate 5018*0Sstevel@tonic-gate rawipkp = (rawip_named_kstat_t *)kp->ks_data; 5019*0Sstevel@tonic-gate 5020*0Sstevel@tonic-gate rawipkp->inDatagrams.value.ui32 = rawip_mib.rawipInDatagrams; 5021*0Sstevel@tonic-gate rawipkp->inCksumErrs.value.ui32 = rawip_mib.rawipInCksumErrs; 5022*0Sstevel@tonic-gate rawipkp->inErrors.value.ui32 = rawip_mib.rawipInErrors; 5023*0Sstevel@tonic-gate rawipkp->outDatagrams.value.ui32 = rawip_mib.rawipOutDatagrams; 5024*0Sstevel@tonic-gate rawipkp->outErrors.value.ui32 = rawip_mib.rawipOutErrors; 5025*0Sstevel@tonic-gate 5026*0Sstevel@tonic-gate return (0); 5027*0Sstevel@tonic-gate } 5028