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