icmp.c revision 5f9878b0212a5bc5924a85d227160bf7f43712f1
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * CDDL HEADER START
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * The contents of this file are subject to the terms of the
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Common Development and Distribution License (the "License").
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * You may not use this file except in compliance with the License.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * See the License for the specific language governing permissions
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * and limitations under the License.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * When distributing Covered Code, include this CDDL HEADER in each
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * If applicable, add the following below this CDDL HEADER, with the
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * fields enclosed by brackets "[]" replaced with your own identifying
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * information: Portions Copyright [yyyy] [name of copyright owner]
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * CDDL HEADER END
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Use is subject to license terms.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew/* Copyright (c) 1990 Mentat Inc. */
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Synchronization notes:
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * RAWIP is MT and uses the usual kernel synchronization primitives. There is
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * locks, which is icmp_rwlock. We also use conn_lock when updating things
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * which affect the IP classifier lookup.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * The lock order is icmp_rwlock -> conn_lock.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * The icmp_rwlock:
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * This protects most of the other fields in the icmp_t. The exact list of
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * fields which are protected by each of the above locks is documented in
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * the icmp_t structure definition.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * Plumbing notes:
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * ICMP is always a device driver. For compatibility with mibopen() code
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * it is possible to I_PUSH "icmp", but that results in pushing a passthrough
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * dummy module.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_capability_req(queue_t *q, mblk_t *mp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_tpi_connect(queue_t *q, mblk_t *mp);
888938a60e4bae0b6451778c6c073f6bb775cff5matthewstatic void icmp_tpi_disconnect(queue_t *q, mblk_t *mp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error,
888938a60e4bae0b6451778c6c073f6bb775cff5matthewstatic void icmp_err_ack_prim(queue_t *q, mblk_t *mp, t_scalar_t primitive,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_icmp_error(conn_t *connp, mblk_t *mp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_icmp_error_ipv6(conn_t *connp, mblk_t *mp);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic conn_t *icmp_open(int family, cred_t *credp, int *err, int flags);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic int icmp_openv4(queue_t *q, dev_t *devp, int flag, int sflag,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int icmp_openv6(queue_t *q, dev_t *devp, int flag, int sflag,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int icmp_unitdata_opt_process(queue_t *q, mblk_t *mp,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic boolean_t icmp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewint icmp_opt_set(conn_t *connp, uint_t optset_context,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic boolean_t icmp_param_register(IDP *ndp, icmpparam_t *icmppa, int cnt);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic int icmp_param_set(queue_t *q, mblk_t *mp, char *value,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int icmp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_ud_err(queue_t *q, mblk_t *mp, t_scalar_t err);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int icmp_update_label(icmp_t *icmp, mblk_t *mp, ipaddr_t dst);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_wput_fallback(queue_t *q, mblk_t *mp);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic int raw_ip_send_data_v6(queue_t *q, conn_t *connp, mblk_t *mp,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int raw_ip_send_data_v4(queue_t *q, conn_t *connp, mblk_t *mp,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_wput_iocdata(queue_t *q, mblk_t *mp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void icmp_wput_restricted(queue_t *q, mblk_t *mp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void *rawip_stack_init(netstackid_t stackid, netstack_t *ns);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void rawip_stack_fini(netstackid_t stackid, void *arg);
23eb77b39ca6681d8faf95760389dfeb913f3238matthewstatic void rawip_kstat_fini(netstackid_t stackid, kstat_t *ksp);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic void rawip_stack_shutdown(netstackid_t stackid, void *arg);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int rawip_do_getsockname(icmp_t *icmp, struct sockaddr *sa,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewstatic int rawip_do_getpeername(icmp_t *icmp, struct sockaddr *sa,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewint rawip_getsockname(sock_lower_handle_t, struct sockaddr *,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewint rawip_getpeername(sock_lower_handle_t, struct sockaddr *,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * Entry points for ICMP as a device.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * We have separate open functions for the /dev/icmp and /dev/icmp6 devices.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew NULL, NULL, icmp_openv4, icmp_close, NULL, &icmp_mod_info
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew NULL, NULL, icmp_openv6, icmp_close, NULL, &icmp_mod_info
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew (pfi_t)icmp_wput, NULL, NULL, NULL, NULL, &icmp_mod_info
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew/* ICMP entry point during fallback */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew (pfi_t)icmp_wput_fallback, NULL, NULL, NULL, NULL, &icmp_mod_info
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew/* For AF_INET aka /dev/icmp */
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew/* For AF_INET6 aka /dev/icmp6 */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewstatic sin_t sin_null; /* Zero address for quick clears */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewstatic sin6_t sin6_null; /* Zero address for quick clears */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew/* Default structure copied into T_INFO_ACK messages */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew IP_MAXPACKET, /* TSDU_size. icmp allows maximum size messages. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew T_INVALID, /* ETSDU_size. icmp does not support expedited data. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew T_INVALID, /* CDATA_size. icmp does not support connect data. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew T_INVALID, /* DDATA_size. icmp does not support disconnect data. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew 0, /* ADDR_size - filled in later. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew 0, /* OPT_size - not initialized here */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew IP_MAXPACKET, /* TIDU_size. icmp allows maximum size messages. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew T_CLTS, /* SERV_type. icmp supports connection-less. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew TS_UNBND, /* CURRENT_state. This is set from icmp_state. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Table of ND variables supported by icmp. These are loaded into is_nd
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * when the stack instance is created.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * All of these are alterable, within the min/max values given, at run time.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* min max value name */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew { 0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS, "icmp_ipv6_hoplimit"},
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_wroff_extra is_param_arr[0].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_ipv6_hoplimit is_param_arr[2].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_bsd_compat is_param_arr[3].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_xmit_hiwat is_param_arr[4].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_xmit_lowat is_param_arr[5].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew#define is_recv_hiwat is_param_arr[6].icmp_param_value
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewstatic int rawip_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len);
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewstatic int rawip_do_connect(conn_t *connp, const struct sockaddr *sa,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewstatic void rawip_post_ip_bind_connect(icmp_t *icmp, mblk_t *ire_mp, int error);
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * This routine is called to handle each O_T_BIND_REQ/T_BIND_REQ message
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * passed to icmp_wput.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * The O_T_BIND_REQ/T_BIND_REQ is passed downstream to ip with the ICMP
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * protocol type placed in the message following the address. A T_BIND_ACK
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * message is returned by ip_bind_v4/v6.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * All Solaris components should pass a db_credp
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * for this TPI message, hence we ASSERT.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * But in case there is some other M_PROTO that looks
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * like a TPI message sent by some other kernel
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * component, we check and return an error.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew "icmp_bind: bad req, len %u",
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Reallocate the message to make sure we have enough room for an
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * address and the protocol type.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew mp1 = reallocb(mp, sizeof (struct T_bind_ack) + sizeof (sin6_t) + 1, 1);
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* Reset the message type in preparation for shipping it back. */
734b33576ba7e4711930d6a86f5dc506a1573e8fmatthew case 0: /* request for a generic port */
734b33576ba7e4711930d6a86f5dc506a1573e8fmatthew sa = (struct sockaddr *)mi_offset_param(mp, tbr->ADDR_offset,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (error != 0) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewrawip_do_bind(conn_t *connp, struct sockaddr *sa, socklen_t len)
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * The state must be TS_UNBND. TPI mandates that users must send
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * TPI primitives only 1 at a time and wait for the response before
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * sending the next primitive.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (icmp->icmp_state != TS_UNBND || icmp->icmp_pending_op != -1) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* TSYSERR, EAFNOSUPPORT */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* TSYSERR, EAFNOSUPPORT */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* No support for mapped addresses on raw sockets */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* TSYSERR, EADDRNOTAVAIL */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* TBADADDR */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Copy the source address into our icmp structure. This address
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * may still be zero; if so, ip will fill in the correct address
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * each time an outbound packet is passed to it.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * If we are binding to a broadcast or multicast address then
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * rawip_post_ip_bind_connect will clear the source address.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew icmp->icmp_max_hdr_len = icmp->icmp_sticky_hdrs_len;
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* Rebuild the header template */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (error != 0) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * request an IRE if src not 0 (INADDR_ANY)
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew error = ip_proto_bind_laddr_v6(connp, &ire_mp, icmp->icmp_proto,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew error = ip_proto_bind_laddr_v4(connp, &ire_mp, icmp->icmp_proto,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewrawip_post_ip_bind_connect(icmp_t *icmp, mblk_t *ire_mp, int error)
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * not yet bound - bind sent by icmp_bind_proto.
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew if (error != 0) {
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew /* Connect failed */
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew /* Revert back to the bound source */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (ire_mp != NULL && ire_mp->b_datap->db_type == IRE_DB_TYPE) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * If a broadcast/multicast address was bound set
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * the source address to 0.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * This ensures no datagrams with broadcast address
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * as source address are emitted (which would violate
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * RFC1122 - Hosts requirements)
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Note: we get IRE_BROADCAST for IPv6
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * to "mark" a multicast local address.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * This was just a local bind to a
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Send message to IP to just bind to the protocol.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew error = ip_proto_bind_laddr_v6(connp, NULL, icmp->icmp_proto,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew error = ip_proto_bind_laddr_v4(connp, NULL, icmp->icmp_proto,
45b63b5c99c8f6ac146a5850fecbc0af269bf562matthew * All Solaris components should pass a db_credp
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * for this TPI message, hence we ASSERT.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * But in case there is some other M_PROTO that looks
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * like a TPI message sent by some other kernel
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * component, we check and return an error.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* Sanity checks */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_conn_req)) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew case sizeof (sin_t):
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew sa = (struct sockaddr *)mi_offset_param(mp, tcr->DEST_offset,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew case sizeof (sin6_t):
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew error = proto_verify_ip_addr(icmp->icmp_family, sa, len);
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (error != 0) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (error != 0) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * We have to send a connection confirmation to
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * keep TLI happy.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Send ok_ack for T_CONN_REQ
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* Unable to reuse the T_CONN_REQ for the ack. */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew icmp_err_ack_prim(q, mp1, T_CONN_REQ, TSYSERR, ENOMEM);
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewrawip_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (icmp->icmp_state == TS_UNBND || icmp->icmp_pending_op != -1) {
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew case sizeof (sin_t):
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Interpret a zero destination to mean loopback.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * Update the T_CONN_REQ (sin/sin6) since it is used to
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * generate the T_CONN_CON.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * If the destination address is multicast and
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * an outgoing multicast interface has been set,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * use the address of that interface as our
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * source address if no source address has been set.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew if (V4_PART_OF_V6(icmp->icmp_v6src) == INADDR_ANY &&
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew IN6_IPADDR_TO_V4MAPPED(icmp->icmp_multicast_if_addr,
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew case sizeof (sin6_t):
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew /* No support for mapped addresses on raw sockets */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew icmp->icmp_max_hdr_len = icmp->icmp_sticky_hdrs_len;
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Interpret a zero destination to mean loopback.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Update the T_CONN_REQ (sin/sin6) since it is used to
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * generate the T_CONN_CON.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (IN6_IS_ADDR_UNSPECIFIED(&icmp->icmp_v6dst.sin6_addr)) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * If the destination address is multicast and
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * an outgoing multicast interface has been set,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * then the ip bind logic will pick the correct source
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * address (i.e. matching the outgoing multicast interface).
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Already connected - clear out state */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew icmp->icmp_proto, &V4_PART_OF_V6(icmp->icmp_v6src), 0,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew V4_PART_OF_V6(icmp->icmp_v6dst.sin6_addr), sin->sin_port,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* If there are any options associated with the stream, free them. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew kmem_free(icmp->icmp_filter, sizeof (icmp6_filter_t));
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Free memory associated with sticky options */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Clear any fields which the kmem_cache constructor clears.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Only icmp_connp needs to be preserved.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * TBD: We should make this more efficient to avoid clearing
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * everything.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew ASSERT(connp->conn_icmp->icmp_fallback_queue_head == NULL &&
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew connp->conn_icmp->icmp_fallback_queue_tail == NULL);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Now we are truly single threaded on this stream, and can
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * delete the things hanging off the connp, and finally the connp.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * We removed this connp from the fanout list, it cannot be
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * accessed thru the fanouts, and we already waited for the
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * conn_ref to drop to 0. We are already in close, so
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * there cannot be any other thread from the top. qprocsoff
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * has completed, and service has completed or won't run in
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew inet_minor_free(connp->conn_minor_arena, connp->conn_dev);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew return (0);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * stream is being closed while in fallback
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * simply free the resources that were allocated
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew inet_minor_free(WR(q)->q_ptr, (dev_t)(RD(q)->q_ptr));
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew return (0);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * This routine handles each T_DISCON_REQ message passed to icmp
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * as an indicating that ICMP is no longer connected. This results
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * in sending a T_BIND_REQ to IP to restore the binding to just
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * the local address.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * The disconnect completes in rawip_post_ip_bind_connect.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (icmp->icmp_state != TS_DATA_XFER || icmp->icmp_pending_op != -1) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Rebuild the header template */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (error != 0) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew error = ip_proto_bind_laddr_v6(connp, &ire_mp, icmp->icmp_proto,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew error = ip_proto_bind_laddr_v4(connp, &ire_mp, icmp->icmp_proto,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Allocate the largest primitive we need to send back
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * T_error_ack is > than T_ok_ack
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Unable to reuse the T_DISCON_REQ for the ack. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew icmp_err_ack_prim(q, mp, T_DISCON_REQ, TSYSERR, ENOMEM);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (error != 0) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew/* This routine creates a T_ERROR_ACK message and passes it upstream. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthewicmp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error)
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew/* Shorthand to generate and send TPI error acks to our client */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthewicmp_err_ack_prim(queue_t *q, mblk_t *mp, t_scalar_t primitive,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack),
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * icmp_icmp_error is called by icmp_input to process ICMP
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * messages passed up by IP.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Generates the appropriate permanent (non-transient) errors.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Assumes that IP has pulled up everything up to and including
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * the ICMP header.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * icmp does not support v4 mapped addresses
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * so we can never be here for a V6 socket
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * i.e. icmp_family == AF_INET6
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Skip past the outer IP and ICMP headers */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * IP has already adjusted the path MTU.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Transient errors */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Transient errors */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (error == 0) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Deliver T_UDERROR_IND when the application has asked for it.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * The socket layer enables this automatically when connected.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew mp1 = mi_tpi_uderror_ind((char *)&sin, sizeof (sin_t), NULL,
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * icmp_icmp_error_ipv6 is called by icmp_icmp_error to process ICMPv6
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * for IPv6 packets.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Send permanent (non-transient) errors upstream.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * Assumes that IP has pulled up all the extension headers as well
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * as the ICMPv6 header.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &iph_hdr_length, &nexthdrp)) {
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Transient errors */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew sizeof (struct ip6_mtuinfo);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * If the application has requested to receive path mtu
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * information, send up an empty message containing an
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * IPV6_PATHMTU ancillary data item.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t) +
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew BUMP_MIB(&icmp->icmp_is->is_rawip_mib, rawipInErrors);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * newmp->b_cont is left to NULL on purpose. This is an
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * empty message containing only ancillary data.
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew tudi->OPT_offset = tudi->SRC_offset + sizeof (sin6_t);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * We've consumed everything we need from the original
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * message. Free it, then send our empty message.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* Transient errors */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* If this corresponds to an ICMP_PROTOCOL_UNREACHABLE */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew if (icmp6->icmp6_code == ICMP6_PARAMPROB_NEXTHEADER &&
888938a60e4bae0b6451778c6c073f6bb775cff5matthew if (error == 0) {
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Deliver T_UDERROR_IND when the application has asked for it.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * The socket layer enables this automatically when connected.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK;
888938a60e4bae0b6451778c6c073f6bb775cff5matthew mp1 = mi_tpi_uderror_ind((char *)&sin6, sizeof (sin6_t),
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * This routine responds to T_ADDR_REQ messages. It is called by icmp_wput.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * The local address is filled in if endpoint is bound. The remote address
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * is filled in if remote address has been precified ("connected endpoint")
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * (The concept of connected CLTS sockets is alien to published TPI
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * but we support it anyway).
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* Make it large enough for worst case */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Note: Following code assumes 32 bit alignment of basic
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * data structures like sin_t and struct T_addr_ack.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Fill in local address
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* Fill zeroes and then intialize non-zero fields */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * INADDR_ANY
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * icmp_v6src is not set, we might be bound to
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * broadcast/multicast. Use icmp_bound_v6src as
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * local address instead (that could
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * also still be INADDR_ANY)
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* Fill zeroes and then intialize non-zero fields */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * UNSPECIFIED
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * icmp_v6src is not set, we might be bound to
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * broadcast/multicast. Use icmp_bound_v6src as
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * local address instead (that could
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * also still be UNSPECIFIED)
888938a60e4bae0b6451778c6c073f6bb775cff5matthewicmp_do_capability_ack(icmp_t *icmp, struct T_capability_ack *tcap,
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * This routine responds to T_CAPABILITY_REQ messages. It is called by
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * icmp_wput. Much of the T_CAPABILITY_ACK information is copied from
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * icmp_g_t_info_ack. The current state of the stream is copied from
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * icmp_state.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
888938a60e4bae0b6451778c6c073f6bb775cff5matthew mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * This routine responds to T_INFO_REQ messages. It is called by icmp_wput.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Most of the T_INFO_ACK information is copied from icmp_g_t_info_ack.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * The current state of the stream is copied from icmp_state.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
888938a60e4bae0b6451778c6c073f6bb775cff5matthew icmp_copy_info((struct T_info_ack *)mp->b_rptr, icmp);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew/* For /dev/icmp aka AF_INET open */
888938a60e4bae0b6451778c6c073f6bb775cff5matthewicmp_tpi_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp,
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* If the stream is already open, return immediately. */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew return (0);
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Since ICMP is not used so heavily, allocating from the small
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * arena should be sufficient.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew if ((conn_dev = inet_minor_alloc(ip_minor_arena_sa)) == 0) {
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * Non streams socket needs a stream to fallback to
23eb77b39ca6681d8faf95760389dfeb913f3238matthew return (0);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew inet_minor_free(ip_minor_arena_sa, connp->conn_dev);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew *devp = makedevice(getemajor(*devp), (minor_t)conn_dev);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Initialize the icmp_t structure for this stream.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew /* Build initial header template for transmit */
23eb77b39ca6681d8faf95760389dfeb913f3238matthew rw_enter(&connp->conn_icmp->icmp_rwlock, RW_WRITER);
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew if ((error = icmp_build_hdrs(connp->conn_icmp)) != 0) {
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew inet_minor_free(ip_minor_arena_sa, connp->conn_dev);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew /* Set the Stream head write offset. */
888938a60e4bae0b6451778c6c073f6bb775cff5matthew connp->conn_icmp->icmp_max_hdr_len + is->is_wroff_extra);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew (void) proto_set_rx_hiwat(connp->conn_rq, connp, q->q_hiwat);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew return (0);
23eb77b39ca6681d8faf95760389dfeb913f3238matthew/* For /dev/icmp4 aka AF_INET open */
23eb77b39ca6681d8faf95760389dfeb913f3238matthewicmp_openv4(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
23eb77b39ca6681d8faf95760389dfeb913f3238matthew return (icmp_tpi_open(q, devp, flag, sflag, credp, AF_INET));
23eb77b39ca6681d8faf95760389dfeb913f3238matthew/* For /dev/icmp6 aka AF_INET6 open */
23eb77b39ca6681d8faf95760389dfeb913f3238matthewicmp_openv6(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
23eb77b39ca6681d8faf95760389dfeb913f3238matthew return (icmp_tpi_open(q, devp, flag, sflag, credp, AF_INET6));
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * This is the open routine for icmp. It allocates a icmp_t structure for
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * the stream and, on the first open of the module, creates an ND table.
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew/* ARGSUSED */
23eb77b39ca6681d8faf95760389dfeb913f3238matthewicmp_open(int family, cred_t *credp, int *err, int flags)
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * For exclusive stacks we set the zoneid to zero
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * to make ICMP operate as if in the global zone.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew connp = ipcl_conn_create(IPCL_RAWIPCONN, flags, ns);
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * ipcl_conn_create did a netstack_hold. Undo the hold that was
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * done by netstack_find_by_cred()
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Set the initial state of the stream and the privilege status. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* May be changed by a SO_PROTOTYPE socket option. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew icmp->icmp_checksum_off = 2; /* Offset for icmp6_cksum */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* May be changed by a SO_PROTOTYPE socket option. */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew icmp->icmp_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew connp->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * If the caller has the process-wide flag set, then default to MAC
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * exempt mode. This allows read-down to unlabeled hosts.
888938a60e4bae0b6451778c6c073f6bb775cff5matthew * Which ICMP options OK to set through T_UNITDATA_REQ...
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew/* ARGSUSED */
ddfdace22c6a477b537a8834fb9d96d75f93af91matthewicmp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name)
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * This routine gets default values of certain options whose default
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * values are maintained by protcol specific code
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew/* ARGSUSED */
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewicmp_opt_default(queue_t *q, int level, int name, uchar_t *ptr)
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew return (sizeof (uchar_t));
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew return (sizeof (uchar_t));
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew return (sizeof (int));
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew return (sizeof (int));
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew return (sizeof (int));
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew /* Make it look like "pass all" */
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew return (sizeof (icmp6_filter_t));
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew return (-1);
e26d10aecce16fb398a031cd0259eb48dbc01b9fmatthew * This routine retrieves the current status of socket options.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthew * It returns the size of the option retrieved.
1ec68df4f77eebb993e03a23e14a4a7472d9fb1cmatthewicmp_opt_get(conn_t *connp, int level, int name, uchar_t *ptr)
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * The following three items are available here,
ddfdace22c6a477b537a8834fb9d96d75f93af91matthew * but are only meaningful to IP.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Following four not meaningful for icmp
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * Action is same as "default" to which we fallthrough
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * so we keep them in comments.
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * case SO_LINGER:
23eb77b39ca6681d8faf95760389dfeb913f3238matthew * case SO_KEEPALIVE:
goto done;
case IPPROTO_IP:
goto done;
switch (name) {
case IP_OPTIONS:
case T_IP_OPTIONS:
ret = 0;
goto done;
case IP_HDRINCL:
case IP_TOS:
case T_IP_TOS:
case IP_TTL:
case IP_MULTICAST_IF:
goto done;
case IP_MULTICAST_TTL:
goto done;
case IP_MULTICAST_LOOP:
goto done;
case IP_BOUND_IF:
case IP_UNSPEC_SRC:
case IP_RECVIF:
case IP_BROADCAST_TTL:
return (sizeof (uchar_t));
case IP_RECVPKTINFO:
goto done;
goto done;
case IPPROTO_IPV6:
goto done;
switch (name) {
case IPV6_UNICAST_HOPS:
case IPV6_MULTICAST_IF:
case IPV6_MULTICAST_HOPS:
case IPV6_MULTICAST_LOOP:
case IPV6_BOUND_IF:
case IPV6_UNSPEC_SRC:
case IPV6_CHECKSUM:
goto done;
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
goto done;
case IPV6_RECVPKTINFO:
case IPV6_RECVTCLASS:
case IPV6_RECVPATHMTU:
case IPV6_V6ONLY:
case IPV6_RECVHOPLIMIT:
case IPV6_RECVHOPOPTS:
case IPV6_RECVDSTOPTS:
case _OLD_IPV6_RECVDSTOPTS:
case IPV6_RECVRTHDRDSTOPTS:
case IPV6_RECVRTHDR:
case IPV6_PKTINFO: {
goto done;
case IPV6_NEXTHOP: {
goto done;
case IPV6_HOPOPTS:
goto done;
case IPV6_RTHDRDSTOPTS:
goto done;
case IPV6_RTHDR:
goto done;
case IPV6_DSTOPTS:
ret = 0;
goto done;
goto done;
case IPV6_PATHMTU:
ret = 0;
goto done;
case IPV6_TCLASS:
goto done;
case IPPROTO_ICMPV6:
switch (name) {
case ICMP6_FILTER:
sizeof (icmp6_filter_t));
goto done;
goto done;
goto done;
ret = sizeof (int);
done:
return (ret);
int err;
return (err);
int error;
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_DEBUG:
if (!checkonly)
case SO_PROTOTYPE:
*outlenp = 0;
return (EACCES);
*outlenp = 0;
return (EPROTONOSUPPORT);
if (checkonly) {
sizeof (icmp6_filter_t));
if (error != 0) {
*outlenp = 0;
return (error);
*outlenp = sizeof (int);
case SO_REUSEADDR:
if (!checkonly) {
case SO_DONTROUTE:
if (!checkonly) {
case SO_USELOOPBACK:
if (!checkonly) {
case SO_BROADCAST:
if (!checkonly) {
case SO_SNDBUF:
*outlenp = 0;
return (ENOBUFS);
if (!checkonly) {
case SO_RCVBUF:
*outlenp = 0;
return (ENOBUFS);
if (!checkonly) {
*i1);
case SO_DGRAM_ERRIND:
if (!checkonly)
case SO_ALLZONES:
return (-EINVAL);
case SO_TIMESTAMP:
if (!checkonly) {
case SO_MAC_EXEMPT:
return (-EINVAL);
case SO_RCVTIMEO:
case SO_SNDTIMEO:
*outlenp = 0;
return (EINVAL);
case IPPROTO_IP:
*outlenp = 0;
return (ENOPROTOOPT);
switch (name) {
case IP_OPTIONS:
case T_IP_OPTIONS:
*outlenp = 0;
return (EINVAL);
if (checkonly)
*outlenp = 0;
return (ENOMEM);
case IP_HDRINCL:
if (!checkonly)
case IP_TOS:
case T_IP_TOS:
if (!checkonly) {
case IP_TTL:
if (!checkonly) {
case IP_MULTICAST_IF:
if (!checkonly) {
case IP_MULTICAST_TTL:
if (!checkonly)
case IP_MULTICAST_LOOP:
if (!checkonly) {
case IP_BOUND_IF:
if (!checkonly) {
case IP_UNSPEC_SRC:
if (!checkonly) {
case IP_BROADCAST_TTL:
if (!checkonly)
case IP_RECVIF:
if (!checkonly) {
return (-EINVAL);
case IP_PKTINFO: {
if (checkonly)
if (inlen == sizeof (int)) {
return (-EINVAL);
return (EINVAL);
== NULL) {
return (EINVAL);
return (EINVAL);
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
case IP_BLOCK_SOURCE:
case IP_UNBLOCK_SOURCE:
case IP_ADD_SOURCE_MEMBERSHIP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
case MRT_INIT:
case MRT_DONE:
case MRT_ADD_VIF:
case MRT_DEL_VIF:
case MRT_ADD_MFC:
case MRT_DEL_MFC:
case MRT_VERSION:
case MRT_ASSERT:
case IP_SEC_OPT:
case IP_NEXTHOP:
return (-EINVAL);
*outlenp = 0;
return (EINVAL);
case IPPROTO_IPV6: {
*outlenp = 0;
return (ENOPROTOOPT);
switch (name) {
case IPV6_MULTICAST_IF:
if (!checkonly) {
case IPV6_UNICAST_HOPS:
*outlenp = 0;
return (EINVAL);
if (!checkonly) {
if (error != 0) {
*outlenp = 0;
return (error);
case IPV6_MULTICAST_HOPS:
*outlenp = 0;
return (EINVAL);
if (!checkonly) {
case IPV6_MULTICAST_LOOP:
*outlenp = 0;
return (EINVAL);
if (!checkonly) {
case IPV6_CHECKSUM:
*outlenp = 0;
return (EINVAL);
*outlenp = 0;
return (EINVAL);
if (checkonly)
if (error != 0) {
*outlenp = 0;
return (error);
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
return (-EINVAL);
case IPV6_BOUND_IF:
if (!checkonly) {
case IPV6_UNSPEC_SRC:
if (!checkonly) {
case IPV6_RECVTCLASS:
if (!checkonly) {
case IPV6_RECVPKTINFO:
if (!checkonly) {
case IPV6_RECVPATHMTU:
if (!checkonly) {
case IPV6_RECVHOPLIMIT:
if (!checkonly) {
case IPV6_RECVHOPOPTS:
if (!checkonly) {
case IPV6_RECVDSTOPTS:
if (!checkonly) {
case _OLD_IPV6_RECVDSTOPTS:
if (!checkonly)
case IPV6_RECVRTHDRDSTOPTS:
if (!checkonly) {
case IPV6_RECVRTHDR:
if (!checkonly) {
case IPV6_PKTINFO:
sizeof (struct in6_pktinfo)) {
return (EINVAL);
if (checkonly)
if (inlen == 0) {
if (!IN6_IS_ADDR_UNSPECIFIED(
if (sticky) {
if (error != 0)
return (error);
case IPV6_HOPLIMIT:
if (sticky)
return (EINVAL);
return (EINVAL);
if (checkonly)
if (inlen == 0) {
return (EINVAL);
case IPV6_TCLASS:
return (EINVAL);
if (checkonly)
if (inlen == 0) {
return (EINVAL);
if (sticky) {
if (error != 0)
return (error);
case IPV6_NEXTHOP:
return (EINVAL);
if (checkonly)
if (inlen == 0) {
return (EAFNOSUPPORT);
return (EADDRNOTAVAIL);
if (!IN6_IS_ADDR_UNSPECIFIED(
if (sticky) {
if (error != 0)
return (error);
case IPV6_HOPOPTS: {
if (inlen != 0 &&
return (EINVAL);
if (checkonly)
if (error != 0)
return (error);
if (sticky) {
if (error != 0)
return (error);
case IPV6_RTHDRDSTOPTS: {
if (inlen != 0 &&
return (EINVAL);
if (checkonly)
if (inlen == 0) {
if (sticky &&
if (error != 0)
return (error);
if (sticky) {
if (error != 0)
return (error);
case IPV6_DSTOPTS: {
if (inlen != 0 &&
return (EINVAL);
if (checkonly)
if (inlen == 0) {
if (sticky &&
if (error != 0)
return (error);
if (sticky) {
if (error != 0)
return (error);
case IPV6_RTHDR: {
if (inlen != 0 &&
return (EINVAL);
if (checkonly)
if (inlen == 0) {
if (sticky &&
if (error != 0)
return (error);
if (sticky) {
if (error != 0)
return (error);
case IPV6_DONTFRAG:
if (checkonly)
if (onoff) {
case IPV6_USE_MIN_MTU:
if (inlen != sizeof (int))
return (EINVAL);
return (EINVAL);
if (checkonly)
case IPV6_PATHMTU:
return (EINVAL);
case IPV6_SEC_OPT:
case IPV6_SRC_PREFERENCES:
case IPV6_V6ONLY:
return (-EINVAL);
*outlenp = 0;
return (EINVAL);
case IPPROTO_ICMPV6:
*outlenp = 0;
return (ENOPROTOOPT);
*outlenp = 0;
return (ENOPROTOOPT);
switch (name) {
case ICMP6_FILTER:
if (!checkonly) {
if ((inlen != 0) &&
return (EINVAL);
if (inlen == 0) {
sizeof (icmp6_filter_t));
sizeof (icmp6_filter_t),
*outlenp = 0;
return (ENOBUFS);
inlen);
*outlenp = 0;
return (EINVAL);
*outlenp = 0;
return (EINVAL);
int error;
error = 0;
switch (optset_context) {
case SETFN_OPTCOM_CHECKONLY:
if (inlen == 0) {
*outlenp = 0;
error = 0;
goto done;
case SETFN_OPTCOM_NEGOTIATE:
case SETFN_UD_NEGOTIATE:
case SETFN_CONN_NEGOTIATE:
*outlenp = 0;
goto done;
*outlenp = 0;
goto done;
done:
return (error);
int error;
return (error);
if (hdrs_len != 0) {
return (ENOMEM);
static boolean_t
return (B_FALSE);
return (B_TRUE);
long new_value;
return (EINVAL);
static mblk_t *
return (NULL);
return (mp);
int error;
NULL) < 0) {
int hdr_len;
IN_PKTINFO) {
if (!mp1) {
sizeof (uint_t);
sizeof (struct in_pktinfo);
sizeof (sin_t);
if (udi_size != 0) {
char *dstopt;
sizeof (uint_t);
sizeof (intptr_t));
sizeof (in_pktinfo_t);
goto deliver;
hopstrip = 0;
while (remlen > 0) {
remlen--;
ucp++;
int type;
int remlen;
if (sum != 0) {
sizeof (struct in6_pktinfo);
if (udi_size != 0) {
sizeof (*pkti);
if (icmp_ipv6_recvhoplimit) {
sizeof (uint_t);
sizeof (uint_t);
sizeof (intptr_t));
if (hopstrip > 0) {
mblk_t *
return (mp2ctl);
switch (level) {
case EXPER_RAWIP:
if (mp1)
return (-TOUTSTATE);
int error;
if (error) {
if (error < 0) {
int ip_hdr_length;
int tp_hdr_len;
int error;
if (is_system_labeled()) {
if (error != 0) {
return (error);
case IPPROTO_UDP:
case IPPROTO_TCP:
tp_hdr_len = 0;
tp_hdr_len)) {
tp_hdr_len)) {
return (EMSGSIZE);
return (ENOMEM);
int err;
return (EINVAL);
goto done;
goto done;
opt_storage)) != 0)
goto done;
done:
if (err != 0) {
return (err);
int error;
case M_DATA:
if (error != 0)
case M_PROTO:
case M_PCPROTO:
== T_UNITDATA_REQ)
case AF_INET6:
int error;
error = 0;
(void *)ipp) < 0) {
goto done;
case AF_INET:
ASSERT(0);
int error;
error = 0;
(void *)pktinfop) < 0) {
* OPT_length/offset now potentially modified
done:
if (error != 0) {
#ifdef DEBUG
int ip_hdr_length;
return (EPROTO);
if (is_system_labeled()) {
if (error != 0) {
return (error);
BPRI_LO))) {
return (ENOMEM);
#ifdef _BIG_ENDIAN
return (EMSGSIZE);
int err;
return (EINVAL);
goto done;
goto done;
goto done;
done:
if (err != 0) {
return (err);
return (EADDRNOTAVAIL);
if (is_system_labeled()) {
int error = 0;
if (error != 0) {
return (error);
goto no_options;
return (ENOMEM);
ip_hdr_len +=
if (!mp1) {
return (ENOMEM);
if (hopoptslen == 0) {
return (EPROTO);
return (EPROTO);
return (EADDRNOTAVAIL);
return (EMSGSIZE);
#ifdef _LITTLE_ENDIAN
case M_PROTO:
case M_PCPROTO:
case T_ADDR_REQ:
case O_T_BIND_REQ:
case T_BIND_REQ:
case T_CONN_REQ:
case T_CAPABILITY_REQ:
case T_INFO_REQ:
case T_UNITDATA_REQ:
case T_UNBIND_REQ:
case T_SVR4_OPTMGMT_REQ:
cr)) {
case T_OPTMGMT_REQ:
case T_DISCON_REQ:
case O_T_CONN_RES:
case T_CONN_RES:
case T_DATA_REQ:
case T_EXDATA_REQ:
case T_ORDREL_REQ:
case M_IOCTL:
case TI_GETPEERNAME:
err_ret:;
case TI_GETMYNAME:
case ND_SET:
case ND_GET:
case _SIOCSOCKFALLBACK:
case M_IOCDATA:
case TI_GETMYNAME:
case TI_GETPEERNAME:
case TI_GETMYNAME:
&addrlen);
case TI_GETPEERNAME:
&addrlen);
if (error != 0) {
void *thisdg_attrs)
int is_absreq_failure;
*errorp = 0;
if (*errorp != 0) {
icmp_ddi_g_init(void)
icmp_ddi_g_destroy(void)
int error = 0;
return (is);
0, stackid);
return (NULL);
return (ksp);
return (EIO);
return (EACCES);
return (EOPNOTSUPP);
int error;
if (error < 0) {
return (error);
int error;
int error;
if (error < 0) {
return (error);
return (EOPNOTSUPP);
int error;
return (EINVAL);
return (error);
if (error != 0)
return (error);
return (error);
int unbind_err;
if (error == 0) {
*id = 0;
} else if (error < 0) {
return (error);
short opts;
int error;
if (error != 0)
faddrlen = 0;
opts = 0;
return (NULL);
if ((*errorp =
return (NULL);
return (NULL);
case AF_INET:
return (EINVAL);
case AF_INET6:
return (EINVAL);
return (ENOTCONN);
case AF_INET:
return (EINVAL);
case AF_INET6:
return (EINVAL);
int error;
return (error);
int error;
return (error);
int error;
if (error != 0) {
if (error < 0) {
return (error);
if (error < 0) {
return (error);
int error;
void *optvalp_buf;
int len;
if (error != 0) {
if (error < 0) {
return (error);
if (len < 0) {
SOCK_OPCTL_SHUT_SEND, 0);
SOCK_OPCTL_SHUT_RECV, 0);
int error;
switch (cmd) {
case ND_SET:
case ND_GET:
case _SIOCSOCKFALLBACK:
case TI_GETPEERNAME:
case TI_GETMYNAME:
#ifdef DEBUG
return (error);
int error = 0;
return (error);
goto done_lock;
case AF_INET6: {
if (error != 0) {
goto done_lock;
goto done_lock;
goto done_lock;
goto done_lock;
if (error != 0) {
goto done_lock;
ipp);
case AF_INET: {
if (error != 0) {
goto done_lock;
goto done_lock;
goto done_lock;
if (error != 0) {
goto done_lock;
ASSERT(0);
goto done;
if (error != 0) {
done:
if (bypass_dgram_errind)
return (error);
NULL,
NULL,
NULL,