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