2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * CDDL HEADER START
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The contents of this file are subject to the terms of the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Common Development and Distribution License (the "License").
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * You may not use this file except in compliance with the License.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * See the License for the specific language governing permissions
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * and limitations under the License.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * When distributing Covered Code, include this CDDL HEADER in each
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If applicable, add the following below this CDDL HEADER, with the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * fields enclosed by brackets "[]" replaced with your own identifying
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * information: Portions Copyright [yyyy] [name of copyright owner]
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * CDDL HEADER END
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
854956ce2a18fd37e3f6160d38ffb87fdbc2edc4Bryan Cantrill * Copyright (c) 2016, Joyent, Inc. All rights reserved.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun - IP Tunneling Driver
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * This module is a GLDv3 driver that implements virtual datalinks over IP
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * (a.k.a, IP tunneling). The datalinks are managed through a dld ioctl
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * interface (see iptun_ctl.c), and registered with GLDv3 using
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * mac_register(). It implements the logic for various forms of IP (IPv4 or
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPv6) encapsulation within IP (IPv4 or IPv6) by interacting with the ip
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * module below it. Each virtual IP tunnel datalink has a conn_t associated
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * with it representing the "outer" IP connection.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The module implements the following locking semantics:
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Lookups and deletions in iptun_hash are synchronized using iptun_hash_lock.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * See comments above iptun_hash_lock for details.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * No locks are ever held while calling up to GLDv3. The general architecture
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * of GLDv3 requires this, as the mac perimeter (essentially a lock) for a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * given link will be held while making downcalls (iptun_m_*() callbacks).
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Because we need to hold locks while handling downcalls, holding these locks
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * while issuing upcalls results in deadlock scenarios. See the block comment
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * above iptun_task_cb() for details on how we safely issue upcalls without
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * holding any locks.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The contents of each iptun_t is protected by an iptun_mutex which is held
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * in iptun_enter() (called by iptun_enter_by_linkid()), and exited in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_exit().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * See comments in iptun_delete() and iptun_free() for details on how the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_t is deleted safely.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* Do the tunnel type and address family match? */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ((iptun_type == IPTUN_TYPE_IPV4 && family == AF_INET) || \
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (iptun_type == IPTUN_TYPE_IPV6 && family == AF_INET6) || \
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (iptun_type == IPTUN_TYPE_6TO4 && family == AF_INET))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy#define IPTUN_HASH_KEY(key) ((mod_hash_key_t)(uintptr_t)(key))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy#define IPTUN_MIN_IPV4_MTU 576 /* ip.h still uses 68 (!) */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy#define IPTUN_MAX_IPV4_MTU (IP_MAXPACKET - sizeof (ipha_t))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy#define IPTUN_MAX_IPV6_MTU (IP_MAXPACKET - sizeof (ip6_t) - \
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy#define IPTUN_IPSEC_REQ_MASK (IPSEC_PREF_REQUIRED | IPSEC_PREF_NEVER)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic iptun_encaplim_t iptun_encaplim_init = {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_DEFAULT_ENCAPLIMIT, /* filled in with actual value later */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Table containing per-iptun-type information.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Since IPv6 can run over all of these we have the IPv6 min as the min MTU.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark { IPTUN_TYPE_IPV4, MAC_PLUGIN_IDENT_IPV4, IPV4_VERSION,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark IPTUN_MIN_IPV6_MTU, IPTUN_MAX_IPV4_MTU, B_TRUE },
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark { IPTUN_TYPE_IPV6, MAC_PLUGIN_IDENT_IPV6, IPV6_VERSION,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_MIN_IPV6_MTU, IPTUN_MAX_IPV6_MTU, B_TRUE },
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark { IPTUN_TYPE_6TO4, MAC_PLUGIN_IDENT_6TO4, IPV4_VERSION,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark IPTUN_MIN_IPV6_MTU, IPTUN_MAX_IPV4_MTU, B_FALSE },
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark { IPTUN_TYPE_UNKNOWN, NULL, 0, 0, 0, B_FALSE }
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_hash is an iptun_t lookup table by link ID protected by
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_hash_lock. While the hash table's integrity is maintained via
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * internal locking in the mod_hash_*() functions, we need additional locking
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * so that an iptun_t cannot be deleted after a hash lookup has returned an
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_t and before iptun_lock has been entered. As such, we use
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_hash_lock when doing lookups and removals from iptun_hash.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic uint_t iptun_tunnelcount; /* total for all stacks */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roytypedef enum {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_TASK_MTU_UPDATE, /* tell mac about new tunnel link MTU */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_TASK_LADDR_UPDATE, /* tell mac about new local address */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_TASK_RADDR_UPDATE, /* tell mac about new remote address */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_TASK_LINK_UPDATE, /* tell mac about new link state */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_TASK_PDATA_UPDATE /* tell mac about updated plugin data */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic void iptun_task_dispatch(iptun_t *, iptun_task_t);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic void iptun_headergen(iptun_t *, boolean_t);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic void iptun_drop_pkt(mblk_t *, uint64_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_input(void *, mblk_t *, void *, ip_recv_attr_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_input_icmp(void *, mblk_t *, void *, ip_recv_attr_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic uint32_t iptun_get_maxmtu(iptun_t *, ip_xmit_attr_t *, uint32_t);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic uint32_t iptun_update_mtu(iptun_t *, ip_xmit_attr_t *, uint32_t);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic uint32_t iptun_get_dst_pmtu(iptun_t *, ip_xmit_attr_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_update_dst_pmtu(iptun_t *, ip_xmit_attr_t *);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roystatic int iptun_setladdr(iptun_t *, const struct sockaddr_storage *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_output_6to4(iptun_t *, mblk_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_output_common(iptun_t *, ip_xmit_attr_t *, mblk_t *);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic boolean_t iptun_verifyicmp(conn_t *, void *, icmph_t *, icmp6_t *,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkstatic void iptun_notify(void *, ip_xmit_attr_t *, ixa_notify_type_t,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_m_getstat(void *arg, uint_t stat, uint64_t *val)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_LINK_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_LINK_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_m_setpromisc() does nothing and always succeeds. This is because a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel data-link only ever receives packets that are destined exclusively
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * for the local address of the tunnel.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* ARGSUSED */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* ARGSUSED */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_m_unicst() sets the local address.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* ARGSUSED */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_m_unicst(void *arg, const uint8_t *addrp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy bcopy(addrp, &sin->sin_addr, sizeof (in_addr_t));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy bcopy(addrp, &sin6->sin6_addr, sizeof (in6_addr_t));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(mpchain, &iptun->iptun_noxmtbuf);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* ARGSUSED */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We need to enter this iptun_t since we'll be modifying the outer
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (value < IPTUN_MIN_HOPLIMIT || value > IPTUN_MAX_HOPLIMIT) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_typeinfo->iti_type != IPTUN_TYPE_IPV6 ||
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark uint32_t maxmtu = iptun_get_maxmtu(iptun, NULL, 0);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (value < iptun->iptun_typeinfo->iti_minmtu ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_MTU_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* ARGSUSED */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *(uint32_t *)pr_val = iptun->iptun_encaplimit;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer/* ARGSUSED */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyeriptun_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_prop_info_set_default_uint32(prh, IPTUN_DEFAULT_HOPLIMIT);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (iptun->iptun_typeinfo->iti_type != IPTUN_TYPE_IPV6)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_prop_info_set_default_uint32(prh, IPTUN_DEFAULT_ENCAPLIMIT);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Enter an iptun_t exclusively. This is essentially just a mutex, but we
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * don't allow iptun_enter() to succeed on a tunnel if it's in the process of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * being deleted.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy while (iptun->iptun_flags & IPTUN_DELETE_PENDING)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy cv_wait(&iptun->iptun_enter_cv, &iptun->iptun_lock);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Exit the tunnel entered in iptun_enter().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Enter the IP tunnel instance by datalink ID.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_enter_by_linkid(datalink_id_t linkid, iptun_t **iptun)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (mod_hash_find(iptun_hash, IPTUN_HASH_KEY(linkid),
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Handle tasks that were deferred through the iptun_taskq because they require
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * calling up to the mac module, and we can't call up to the mac module while
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * holding locks.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * This is tricky to get right without introducing race conditions and
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * deadlocks with the mac module, as we cannot issue an upcall while in the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_t. The reason is that upcalls may try and enter the mac perimeter,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * while iptun callbacks (such as iptun_m_setprop()) called from the mac
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * module will already have the perimeter held, and will then try and enter
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the iptun_t. You can see the lock ordering problem with this; this will
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The safe way to do this is to enter the iptun_t in question and copy the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * information we need out of it so that we can exit it and know that the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * information being passed up to the upcalls won't be subject to modification
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * by other threads. The problem now is that we need to exit it prior to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * issuing the upcall, but once we do this, a thread could come along and
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * delete the iptun_t and thus the mac handle required to issue the upcall.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * To prevent this, we set the IPTUN_UPCALL_PENDING flag prior to exiting the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_t. This flag is the condition associated with iptun_upcall_cv, which
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_delete() will cv_wait() on. When the upcall completes, we clear
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPTUN_UPCALL_PENDING and cv_signal() any potentially waiting
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_delete(). We can thus still safely use iptun->iptun_mh after having
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * exited the iptun_t.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Note that if the lookup fails, it's because the tunnel was deleted
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * between the time the task was dispatched and now. That isn't an
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_enter_by_linkid(linkid, &iptun) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (void) mac_maxsdu_update(iptun->iptun_mh, mtu);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac_unicst_update(iptun->iptun_mh, (uint8_t *)&addr.ia_addr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac_dst_update(iptun->iptun_mh, (uint8_t *)&addr.ia_addr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy header_size == 0 ? NULL : &header, header_size) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_task_dispatch(iptun_t *iptun, iptun_task_t iptun_task)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ddi_taskq_dispatch(iptun_taskq, iptun_task_cb, itd, DDI_NOSLEEP)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Convert an iptun_addr_t to sockaddr_storage.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_getaddr(iptun_addr_t *iptun_addr, struct sockaddr_storage *ss)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy sin->sin_addr.s_addr = iptun_addr->ia_addr.iau_addr4;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy sin6->sin6_addr = iptun_addr->ia_addr.iau_addr6;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * General purpose function to set an IP tunnel source or destination address.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_setaddr(iptun_type_t iptun_type, iptun_addr_t *iptun_addr,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!IPTUN_ADDR_MATCH(iptun_type, ss->ss_family))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy struct sockaddr_in *sin = (struct sockaddr_in *)ss;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_addr->ia_addr.iau_addr4 = sin->sin_addr.s_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_addr->ia_addr.iau_addr6 = sin6->sin6_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_setladdr(iptun_t *iptun, const struct sockaddr_storage *laddr)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return (iptun_setaddr(iptun->iptun_typeinfo->iti_type,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_setraddr(iptun_t *iptun, const struct sockaddr_storage *raddr)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return (iptun_setaddr(iptun->iptun_typeinfo->iti_type,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * A tunnel may bind when its source address has been set, and if its
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel type requires one, also its destination address.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Verify that the local address is valid, and insert in the fanout
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark * Get an exclusive ixa for this thread.
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark * We defer updating conn_ixa until later to handle any concurrent
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark * conn_ixa_cleanup thread.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We create PMTU state including for 6to4 */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Note that conn_proto can't be set since the upper protocol
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * can be both 41 and 4 when IPv6 and IPv4 are over the same tunnel.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * ipcl_iptun_classify doesn't use conn_proto.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark connp->conn_ipversion = iptun->iptun_typeinfo->iti_ipvers;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (ip_laddr_verify_v4(iptun->iptun_laddr4, IPCL_ZONEID(connp),
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We use a zero scopeid for now */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (ip_laddr_verify_v6(&iptun->iptun_laddr6, IPCL_ZONEID(connp),
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark IN6_IPADDR_TO_V4MAPPED(INADDR_ANY, &connp->conn_faddr_v6);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark switch (ip_laddr_verify_v4(iptun->iptun_laddr4,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* In case previous destination was multirt */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * When we set a tunnel's destination address, we do not
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * care if the destination is reachable. Transient routing
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * issues should not inhibit the creation of a tunnel
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * interface, for example. Thus we pass B_FALSE here.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* As long as the MTU is large we avoid fragmentation */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_flags |= IXAF_DONTFRAG | IXAF_PMTU_IPV4_DF;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We handle IPsec in iptun_output_common */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark error = ip_attr_connect(connp, ixa, &connp->conn_saddr_v6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark &connp->conn_faddr_v6, &connp->conn_faddr_v6, 0,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* saddr shouldn't change since it was already set */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ASSERT(IN6_ARE_ADDR_EQUAL(&connp->conn_laddr_v6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We set IXAF_VERIFY_PMTU to catch PMTU increases */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Allow setting new policies.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * The addresses/ports are already set, thus the IPsec policy calls
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * can handle their passed-in conn's.
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark /* Atomically update v6lastdst and conn_ixa */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Record this as the "last" send even though we haven't sent any */
e5e7971ff24064af923af2464e78fa6d2fb28deaErik Nordmark /* Done with conn_t */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Now that we're bound with ip below us, this is a good
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * time to initialize the destination path MTU and to
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * re-calculate the tunnel's link MTU.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_task_dispatch(iptun, IPTUN_TASK_LINK_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_LINK_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Re-generate the template data-link header for a given IP tunnel given the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel's current parameters.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_headergen(iptun_t *iptun, boolean_t update_mac)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We only need to use a custom IP header if the administrator
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * has supplied a non-default hoplimit.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_hoplimit == IPTUN_DEFAULT_HOPLIMIT) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_header4.ipha_version_and_hdr_length =
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_header4.ipha_fragment_offset_and_flags =
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_header4.ipha_ttl = iptun->iptun_hoplimit;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ip6_t *ip6hp = &iptun->iptun_header6.it6h_ip6h;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We only need to use a custom IPv6 header if either the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * administrator has supplied a non-default hoplimit, or we
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * need to include an encapsulation limit option in the outer
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_hoplimit == IPTUN_DEFAULT_HOPLIMIT &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_header_size = sizeof (iptun_ipv6hdrs_t);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The mac_ipv6 plugin requires ip6_plen to be in host
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * byte order and reflect the extension headers
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * present in the template. The actual network byte
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * order ip6_plen will be set on a per-packet basis on
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_PDATA_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Insert inbound and outbound IPv4 and IPv6 policy into the given policy
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_insert_simple_policies(ipsec_policy_head_t *ph, ipsec_act_t *actp,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!ipsec_polhead_insert(ph, actp, n, f, IPSEC_TYPE_INBOUND, ns) ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy !ipsec_polhead_insert(ph, actp, n, f, IPSEC_TYPE_OUTBOUND, ns))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return (ipsec_polhead_insert(ph, actp, n, f, IPSEC_TYPE_INBOUND, ns) &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ipsec_polhead_insert(ph, actp, n, f, IPSEC_TYPE_OUTBOUND, ns));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Used to set IPsec policy when policy is set through the IPTUN_CREATE or
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPTUN_MODIFY ioctls.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_set_sec_simple(iptun_t *iptun, const ipsec_req_t *ipsr)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Can't specify self-encap on a tunnel. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If it's a "clear-all" entry, unset the security flags and resume
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * normal cleartext (or inherit-from-global) policy.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy clear_all = ((ipsr->ipsr_ah_req & IPTUN_IPSEC_REQ_MASK) == 0 &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (ipsr->ipsr_esp_req & IPTUN_IPSEC_REQ_MASK) == 0);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((rc = dls_mgmt_get_linkinfo(iptun->iptun_linkid, name, NULL,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((itp = create_tunnel_policy(name, &rc, &gen, ns)) == NULL)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Allocate the actvec now, before holding itp or polhead locks. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ipsec_actvec_from_req(ipsr, &actp, &nact, ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Just write on the active polhead. Save the primary/secondary stuff
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * for spdsock operations.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Mutex because we need to write to the polhead AND flags atomically.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Other threads will acquire the polhead lock as a reader if the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * (unprotected) flag is set.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Oops, we lost a race. Let's get out of here. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy old_policy = ((itp->itp_flags & ITPF_P_ACTIVE) != 0);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy rc = ipsec_copy_polhead(itp->itp_policy, itp->itp_inactive, ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* inactive has already been cleared. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy rw_enter(&itp->itp_policy->iph_lock, RW_WRITER);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Else assume itp->itp_policy is already flushed. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy rw_enter(&itp->itp_policy->iph_lock, RW_WRITER);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(avl_numnodes(&itp->itp_policy->iph_rulebyid) == 0);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy old_policy = B_FALSE; /* Clear out the inactive one too. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_insert_simple_policies(itp->itp_policy, actp, nact, ns)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Adjust MTU and make sure the DL side knows what's up.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy old_policy = B_FALSE; /* Blank out inactive - we succeeded */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Recover policy in in active polhead. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ipsec_swap_policy(itp->itp_policy, itp->itp_inactive, ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Clear policy in inactive polhead. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy rw_enter(&itp->itp_inactive->iph_lock, RW_WRITER);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy for (i = 0; iptun_type_table[i].iti_type != IPTUN_TYPE_UNKNOWN; i++) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Set the parameters included in ik on the tunnel iptun. Parameters that can
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * only be set at creation time are set in iptun_create().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_setparams(iptun_t *iptun, const iptun_kparams_t *ik)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = iptun_setladdr(iptun, &ik->iptun_kparam_laddr)) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = iptun_setraddr(iptun, &ik->iptun_kparam_raddr)) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_SECINFO) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Set IPsec policy originating from the ifconfig(1M) command
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * line. This is traditionally called "simple" policy because
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the ipsec_req_t (iptun_kparam_secinfo) can only describe a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * simple policy of "do ESP on everything" and/or "do AH on
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * everything" (as opposed to the rich policy that can be
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * defined with ipsecconf(1M)).
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_typeinfo->iti_type == IPTUN_TYPE_6TO4) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Can't set security properties for automatic
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* If IPsec can be loaded, try and load it now. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * ipsec_loader_loadnow() returns while IPsec is
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * loaded asynchronously. While a method exists to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * wait for IPsec to load (ipsec_loader_wait()), it
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * requires use of a STREAMS queue to do a qwait().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We're not in STREAMS context here, and so we can't
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * use it. This is not a problem in practice because
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * in the vast majority of cases, key management and
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * global policy will have loaded before any tunnels
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * are plumbed, and so IPsec will already have been
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy err = iptun_set_sec_simple(iptun, &ik->iptun_kparam_secinfo);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_simple_policy = ik->iptun_kparam_secinfo;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Restore original source and destination. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR) &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(!(iptun->iptun_flags & IPTUN_MAC_REGISTERED));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac->m_type_ident = iptun->iptun_typeinfo->iti_ident;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac->m_src_addr = (uint8_t *)&iptun->iptun_laddr.ia_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac->m_dst_addr = iptun->iptun_typeinfo->iti_hasraddr ?
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (uint8_t *)&iptun->iptun_raddr.ia_addr : NULL;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy mac->m_min_sdu = iptun->iptun_typeinfo->iti_minmtu;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = mac_register(mac, &iptun->iptun_mh)) == 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(iptun->iptun_flags & IPTUN_MAC_REGISTERED);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = mac_unregister(iptun->iptun_mh)) == 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_conn_create(iptun_t *iptun, netstack_t *ns, cred_t *credp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((connp = ipcl_conn_create(IPCL_IPCCONN, KM_NOSLEEP, ns)) == NULL)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Register iptun_notify to listen to capability changes detected by IP.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * This upcall is made in the context of the call to conn_ip_output.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * For exclusive stacks we set conn_zoneid to GLOBAL_ZONEID as is done
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * for all other conn_t's.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Note that there's an important distinction between iptun_zoneid and
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * conn_zoneid. The conn_zoneid is set to GLOBAL_ZONEID in non-global
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * exclusive stack zones to make the ip module believe that the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * non-global zone is actually a global zone. Therefore, when
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * interacting with the ip module, we must always use conn_zoneid.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy connp->conn_zoneid = (ns->netstack_stackid == GLOBAL_NETSTACKID) ?
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* crfree() is done in ipcl_conn_destroy(), called by CONN_DEC_REF() */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* conn_allzones can not be set this early, hence no IPCL_ZONEID */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark connp->conn_ixa->ixa_zoneid = connp->conn_zoneid;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Cache things in ixa without an extra refhold */
be4c8f742bc67a43d01e3ea82a814b7d6503dbfdErik Nordmark ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark connp->conn_ixa->ixa_tsl = crgetlabel(connp->conn_cred);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Have conn_ip_output drop packets should our outer source
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark connp->conn_ixa->ixa_flags |= IXAF_VERIFY_SOURCE;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((iptun = kmem_cache_alloc(iptun_cache, KM_NOSLEEP)) != NULL) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_flags & IPTUN_HASH_INSERTED) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy list_remove(&iptuns->iptuns_iptunlist, iptun);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * After iptun_unregister(), there will be no threads executing a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * downcall from the mac module, including in the tx datapath.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_flags & IPTUN_MAC_REGISTERED)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Remove from the AVL tree, AND release the reference iptun_t
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * itself holds on the ITP.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy itp_unlink(iptun->iptun_itp, iptun->iptun_ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ITP_REFRELE(iptun->iptun_itp, iptun->iptun_ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * After ipcl_conn_destroy(), there will be no threads executing an
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * upcall from ip (i.e., iptun_input()), and it is then safe to free
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the iptun_t.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_create(iptun_kparams_t *ik, cred_t *credp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* The tunnel type is mandatory */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!(ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Is the linkid that the caller wishes to associate with this new
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel assigned to this zone?
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (zone_check_datalink(&zoneid, ik->iptun_kparam_linkid) != 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Make sure that we're not trying to create a tunnel that has already
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * been created.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_enter_by_linkid(ik->iptun_kparam_linkid, &iptun) == 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_linkid = ik->iptun_kparam_linkid;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_typeinfo = iptun_gettypeinfo(ik->iptun_kparam_type);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_typeinfo->iti_type == IPTUN_TYPE_UNKNOWN) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_IMPLICIT)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_hoplimit = IPTUN_DEFAULT_HOPLIMIT;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_typeinfo->iti_type == IPTUN_TYPE_IPV6)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_encaplimit = IPTUN_DEFAULT_ENCAPLIMIT;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_connp = iptun_conn_create(iptun, ns, credp);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun->iptun_mtu = iptun->iptun_typeinfo->iti_maxmtu;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Find an ITP based on linkname. If we have parms already set via
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the iptun_setparams() call above, it may have created an ITP for
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * us. We always try get_tunnel_policy() for DEBUG correctness
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * checks, and we may wish to refactor this to only check when
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_itp is NULL.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = dls_mgmt_get_linkinfo(iptun->iptun_linkid, linkname, NULL,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((itp = get_tunnel_policy(linkname, ns)) != NULL)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * See if we have the necessary IP addresses assigned to this tunnel
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * to try and bind them with ip underneath us. If we're not ready to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * bind yet, then we'll defer the bind operation until the addresses
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * are modified.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_canbind(iptun) && ((err = iptun_bind(iptun)) != 0))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy err = dls_devnet_create(iptun->iptun_mh, iptun->iptun_linkid,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We hash by link-id as that is the key used by all other iptun
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * interfaces (modify, delete, etc.).
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IPTUN_HASH_KEY(iptun->iptun_linkid), (mod_hash_val_t)iptun)) == 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy list_insert_head(&iptuns->iptuns_iptunlist, iptun);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (void) dls_devnet_destroy(iptun->iptun_mh, &tmpid,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_delete(datalink_id_t linkid, cred_t *credp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = iptun_enter_by_linkid(linkid, &iptun)) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* One cannot delete a tunnel that belongs to another zone. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_zoneid != crgetzoneid(credp)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We need to exit iptun in order to issue calls up the stack such as
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * dls_devnet_destroy(). If we call up while still in iptun, deadlock
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * with calls coming down the stack is possible. We prevent other
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * threads from entering this iptun after we've exited it by setting
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the IPTUN_DELETE_PENDING flag. This will cause callers of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_enter() to block waiting on iptun_enter_cv. The assumption
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * here is that the functions we're calling while IPTUN_DELETE_PENDING
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * is set dont resuult in an iptun_enter() call, as that would result
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * in deadlock.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Wait for any pending upcall to the mac module to complete. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy while (iptun->iptun_flags & IPTUN_UPCALL_PENDING)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy cv_wait(&iptun->iptun_upcall_cv, &iptun->iptun_lock);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = dls_devnet_destroy(iptun->iptun_mh, &linkid, B_TRUE)) == 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * mac_disable() will fail with EBUSY if there are references
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * to the iptun MAC. If there are none, then mac_disable()
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * will assure that none can be acquired until the MAC is
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * unregistered.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * XXX CR 6791335 prevents us from calling mac_disable() prior
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * to dls_devnet_destroy(), so we unfortunately need to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * attempt to re-create the devnet node if mac_disable()
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = mac_disable(iptun->iptun_mh)) != 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (void) dls_devnet_create(iptun->iptun_mh, linkid,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Now that we know the fate of this iptun_t, we need to clear
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPTUN_DELETE_PENDING, and set IPTUN_CONDEMNED if the iptun_t is
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * slated to be freed. Either way, we need to signal the threads
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * waiting in iptun_enter() so that they can either fail if
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPTUN_CONDEMNED is set, or continue if it's not.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Note that there is no danger in calling iptun_free() after having
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * dropped the iptun_lock since callers of iptun_enter() at this point
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * are doing so from iptun_enter_by_linkid() (mac_disable() got rid of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * threads entering from mac callbacks which call iptun_enter()
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * directly) which holds iptun_hash_lock, and iptun_free() grabs this
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * lock in order to remove the iptun_t from the hash table.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_modify(const iptun_kparams_t *ik, cred_t *credp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy boolean_t laddr_change = B_FALSE, raddr_change = B_FALSE;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = iptun_enter_by_linkid(ik->iptun_kparam_linkid, &iptun)) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* One cannot modify a tunnel that belongs to another zone. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_zoneid != crgetzoneid(credp)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* The tunnel type cannot be changed */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (ik->iptun_kparam_flags & IPTUN_KPARAM_TYPE) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If any of the tunnel's addresses has been modified and the tunnel
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * has the necessary addresses assigned to it, we need to try to bind
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * with ip underneath us. If we're not ready to bind yet, then we'll
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * try again when the addresses are modified later.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy laddr_change = (ik->iptun_kparam_flags & IPTUN_KPARAM_LADDR);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy raddr_change = (ik->iptun_kparam_flags & IPTUN_KPARAM_RADDR);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_canbind(iptun) && (err = iptun_bind(iptun)) != 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_LADDR_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_RADDR_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy/* Given an IP tunnel's datalink id, fill in its parameters. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Is the tunnel link visible from the caller's zone? */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!dls_devnet_islinkvisible(ik->iptun_kparam_linkid,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = iptun_enter_by_linkid(ik->iptun_kparam_linkid, &iptun)) != 0)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ik->iptun_kparam_linkid = iptun->iptun_linkid;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ik->iptun_kparam_type = iptun->iptun_typeinfo->iti_type;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_getaddr(&iptun->iptun_laddr, &ik->iptun_kparam_laddr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_getaddr(&iptun->iptun_raddr, &ik->iptun_kparam_raddr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_IMPLICIT;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_itp->itp_flags & ITPF_P_ACTIVE) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_IPSECPOL;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_flags & IPTUN_SIMPLE_POLICY) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ik->iptun_kparam_flags |= IPTUN_KPARAM_SECINFO;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_set_6to4relay(netstack_t *ns, ipaddr_t relay_addr)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (relay_addr == INADDR_BROADCAST || CLASSD(relay_addr))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ns->netstack_iptun->iptuns_relay_rtr_addr = relay_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_get_6to4relay(netstack_t *ns, ipaddr_t *relay_addr)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy *relay_addr = ns->netstack_iptun->iptuns_relay_rtr_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_set_policy(datalink_id_t linkid, ipsec_tun_pol_t *itp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun_enter_by_linkid(linkid, &iptun) != 0)
01ac885fda2ffe304eb33dd60f9b54c93d76d08bDan McDonald * IPsec policy means IPsec overhead, which means lower MTU.
01ac885fda2ffe304eb33dd60f9b54c93d76d08bDan McDonald * Refresh the MTU for this tunnel.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Obtain the path MTU to the tunnel destination.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Can return zero in some cases.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_get_dst_pmtu(iptun_t *iptun, ip_xmit_attr_t *ixa)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We only obtain the pmtu for tunnels that have a remote tunnel
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Guard against ICMP errors before we have sent, as well as against
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * and a thread which held conn_ixa.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * For both IPv4 and IPv6 we can have indication that the outer
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * header needs fragmentation.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Must allow fragmentation in ip_output */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark } else if (iptun->iptun_typeinfo->iti_type != IPTUN_TYPE_6TO4) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* ip_get_pmtu might have set this - we don't want it */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Update the ip_xmit_attr_t to capture the current lower path mtu as known
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_update_dst_pmtu(iptun_t *iptun, ip_xmit_attr_t *ixa)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* IXAF_VERIFY_PMTU is not set if we don't have a fixed destination */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Guard against ICMP errors before we have sent, as well as against
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * and a thread which held conn_ixa.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Update ixa_fragsize and ixa_pmtu.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * For both IPv4 and IPv6 we can have indication that the outer
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * header needs fragmentation.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Must allow fragmentation in ip_output */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark } else if (iptun->iptun_typeinfo->iti_type != IPTUN_TYPE_6TO4) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* ip_get_pmtu might have set this - we don't want it */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * There is nothing that iptun can verify in addition to IP having
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * verified the IP addresses in the fanout.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark/* ARGSUSED */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_verifyicmp(conn_t *connp, void *arg2, icmph_t *icmph, icmp6_t *icmp6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Notify function registered with ip_xmit_attr_t.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_notify(void *arg, ip_xmit_attr_t *ixa, ixa_notify_type_t ntype,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Returns the max of old_ovhd and the overhead associated with pol.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_max_policy_overhead(ipsec_policy_t *pol, uint32_t old_ovhd)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (itp == NULL || !(itp->itp_flags & ITPF_P_ACTIVE)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Consult global policy, just in case. This will only work
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * if we have both source and destination addresses to work
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((iptun->iptun_flags & (IPTUN_LADDR|IPTUN_RADDR)) !=
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (iptun->iptun_typeinfo->iti_ipvers == IPV4_VERSION);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Check for both IPv4 and IPv6. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy pol = ipsec_find_policy_head(NULL, iph, IPSEC_TYPE_OUTBOUND,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ipsec_ovhd = ipsec_act_ovhd(&pol->ipsp_act->ipa_act);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy pol = ipsec_find_policy_head(NULL, iph, IPSEC_TYPE_OUTBOUND,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Look through all of the possible IPsec actions for the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel, and find the largest potential IPsec overhead.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Calculate and return the maximum possible upper MTU for the given tunnel.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * If new_pmtu is set then we also need to update the lower path MTU information
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * in the ip_xmit_attr_t. That is needed since we set IXAF_VERIFY_PMTU so that
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * we are notified by conn_ip_output() when the path MTU increases.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_get_maxmtu(iptun_t *iptun, ip_xmit_attr_t *ixa, uint32_t new_pmtu)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Start with the path-MTU to the remote address, which is either
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * provided as the new_pmtu argument, or obtained using
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_get_dst_pmtu().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy } else if (iptun->iptun_flags & IPTUN_RADDR) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if ((pmtu = iptun_get_dst_pmtu(iptun, ixa)) == 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We weren't able to obtain the path-MTU of the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * destination. Use the previous value.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We have no path-MTU information to go on, use the maximum
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * possible value.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Now calculate tunneling overhead and subtract that from the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * path-MTU information obtained above.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ipsec_overhead = iptun_get_ipsec_overhead(iptun);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy maxmtu = pmtu - (header_size + ipsec_overhead);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return (max(maxmtu, iptun->iptun_typeinfo->iti_minmtu));
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Re-calculate the tunnel's MTU as seen from above and notify the MAC layer
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * of any change in MTU. The new_pmtu argument is the new lower path MTU to
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * the tunnel destination to be used in the tunnel MTU calculation. Passing
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * in 0 for new_pmtu causes the lower path MTU to be dynamically updated using
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * ip_get_pmtu().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the calculated tunnel MTU is different than its previous value, then we
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * notify the MAC layer above us of this change using mac_maxsdu_update().
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_update_mtu(iptun_t *iptun, ip_xmit_attr_t *ixa, uint32_t new_pmtu)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We always update the ixa since we might have set IXAF_VERIFY_PMTU */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We return the current MTU without updating it if it was pegged to a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * static value using the MAC_PROP_MTU link property.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* If the MTU isn't fixed, then use the maximum possible value. */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark newmtu = iptun_get_maxmtu(iptun, ixa, new_pmtu);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We only dynamically adjust the tunnel MTU for tunnels with
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * destinations because dynamic MTU calculations are based on the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * destination path-MTU.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((iptun->iptun_flags & IPTUN_RADDR) && newmtu != iptun->iptun_mtu) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_flags & IPTUN_MAC_REGISTERED)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_task_dispatch(iptun, IPTUN_TASK_MTU_UPDATE);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Frees a packet or packet chain and bumps stat for each freed packet.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Allocate and return a new mblk to hold an IP and ICMP header, and chain the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * original packet to its b_cont. Returns NULL on failure.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_build_icmperr(size_t hdrs_size, mblk_t *orig_pkt)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if ((icmperr_mp = allocb(hdrs_size, BPRI_MED)) != NULL) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* tack on the offending packet */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Transmit an ICMP error. mp->b_rptr points at the packet to be included in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the ICMP error.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_sendicmp_v4(iptun_t *iptun, icmph_t *icmp, ipha_t *orig_ipha, mblk_t *mp,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy hdrs_size = sizeof (ipha_t) + sizeof (icmph_t);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((icmperr_mp = iptun_build_icmperr(hdrs_size, mp)) == NULL) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy new_ipha->ipha_version_and_hdr_length = IP_SIMPLE_HDR_VERSION;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy new_ipha->ipha_hdr_checksum = 0; /* will be computed by ip */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy new_ipha->ipha_length = htons(hdrs_size + orig_pktsize);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy new_icmp->icmph_checksum = IP_CSUM(icmperr_mp, sizeof (ipha_t), 0);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixas.ixa_ipst = connp->conn_netstack->netstack_ip;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixas.ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_sendicmp_v6(iptun_t *iptun, icmp6_t *icmp6, ip6_t *orig_ip6h, mblk_t *mp,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy hdrs_size = sizeof (ip6_t) + sizeof (icmp6_t);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((icmp6err_mp = iptun_build_icmperr(hdrs_size, mp)) == NULL) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy new_ip6h->ip6_plen = htons(sizeof (icmp6_t) + orig_pktsize);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* The checksum is calculated in ip_output_simple and friends. */
3e87ae1286f5b1197022556087b75e516d68b22bSowmini Varadhan if (IN6_IS_ADDR_UNSPECIFIED(&new_ip6h->ip6_src)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixas.ixa_ipst = connp->conn_netstack->netstack_ip;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixas.ixa_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_icmp_error_v4(iptun_t *iptun, ipha_t *orig_ipha, mblk_t *mp,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_sendicmp_v4(iptun, &icmp, orig_ipha, mp, tsl);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_icmp_fragneeded_v4(iptun_t *iptun, uint32_t newmtu, ipha_t *orig_ipha,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_sendicmp_v4(iptun, &icmp, orig_ipha, mp, tsl);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_icmp_error_v6(iptun_t *iptun, ip6_t *orig_ip6h, mblk_t *mp,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark uint8_t type, uint8_t code, uint32_t offset, ts_label_t *tsl)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_sendicmp_v6(iptun, &icmp6, orig_ip6h, mp, tsl);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_icmp_toobig_v6(iptun_t *iptun, uint32_t newmtu, ip6_t *orig_ip6h,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_sendicmp_v6(iptun, &icmp6, orig_ip6h, mp, tsl);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Determines if the packet pointed to by ipha or ip6h is an ICMP error. The
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * mp argument is only used to do bounds checking.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royis_icmp_error(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hlen, &nexthdrp) ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Find inner and outer IP headers from a tunneled packet as setup for calls
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * into ipsec_tun_{in,out}bound().
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Note that we need to allow the outer header to be in a separate mblk from
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * the inner header.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * If the caller knows the outer_hlen, the caller passes it in. Otherwise zero.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_find_headers(mblk_t *mp, size_t outer_hlen, ipha_t **outer4,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ipha_t **inner4, ip6_t **outer6, ip6_t **inner6)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Don't bother handling packets that don't have a full IP header in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the fist mblk. For the input path, the ip module ensures that this
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * won't happen, and on the output path, the IP tunneling MAC-type
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * plugins ensure that this also won't happen.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer_hlen = ip_hdr_length_v6(mp, (ip6_t *)ipha);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (first_mblkl == outer_hlen && mp->b_cont == NULL))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We don't bother doing a pullup here since the outer header will
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * just get stripped off soon on input anyway. We just want to ensure
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that the inner* pointer points to a full header.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (inner_mp->b_wptr - (uint8_t *)ipha < sizeof (ipha_t))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (inner_mp->b_wptr - (uint8_t *)ipha < sizeof (ip6_t))
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Received ICMP error in response to an X over IPv4 packet that we
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * transmitted.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * NOTE: "outer" refers to what's inside the ICMP payload. We will get one of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the following:
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * [IPv4(0)][ICMPv4][IPv4(1)][IPv4(2)][ULP]
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * [IPv4(0)][ICMPv4][IPv4(1)][IPv6][ULP]
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * And "outer4" will get set to IPv4(1), and inner[46] will correspond to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * whatever the very-inner packet is (IPv4(2) or IPv6).
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_input_icmp_v4(iptun_t *iptun, mblk_t *data_mp, icmph_t *icmph,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Temporarily move b_rptr forward so that iptun_find_headers() can
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * find headers in the ICMP packet payload.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The ip module ensures that ICMP errors contain at least the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * original IP header (otherwise, the error would never have made it
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer_hlen = iptun_find_headers(data_mp, 0, &outer4, &inner4, &outer6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_drop_pkt(data_mp, &iptun->iptun_ierrors);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Only ICMP errors due to tunneled packets should reach here. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(outer4->ipha_protocol == IPPROTO_ENCAP ||
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark data_mp = ipsec_tun_inbound(ira, data_mp, iptun->iptun_itp,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark inner4, inner6, outer4, outer6, -outer_hlen, iptun->iptun_ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Callee did all of the freeing. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* We should never see reassembled fragment here. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy data_mp->b_rptr = (uint8_t *)outer4 + outer_hlen;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the original packet being transmitted was itself an ICMP error,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * then drop this packet. We don't want to generate an ICMP error in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * response to an ICMP error.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_norcvbuf);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy type = (inner4 != NULL ? icmph->icmph_type : ICMP6_DST_UNREACH);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We reconcile this with the fact that the tunnel may
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * also have IPsec policy by letting iptun_update_mtu
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * take care of it.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_icmp_fragneeded_v4(iptun, newmtu, inner4,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy code = (inner4 != NULL ? ICMP_DEST_NET_UNREACH_ADMIN :
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy code = (inner4 != NULL ? ICMP_HOST_UNREACHABLE :
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy } /* else we're already set. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * This is a problem with the outer header we transmitted.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Treat this as an output error.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_oerrors);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_norcvbuf);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_icmp_error_v4(iptun, inner4, data_mp, type, code,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_icmp_error_v6(iptun, inner6, data_mp, type, code, 0,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Return B_TRUE if the IPv6 packet pointed to by ip6h contains a Tunnel
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Encapsulation Limit destination option. If there is one, set encaplim_ptr
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * to point to the option value.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_find_encaplimit(mblk_t *mp, ip6_t *ip6h, uint8_t **encaplim_ptr)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark (void) ip_find_hdr_v6(mp, ip6h, B_FALSE, &pkt, NULL);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark } else if ((pkt.ipp_fields & IPPF_RTHDRDSTOPTS) != 0) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy endptr = (uint8_t *)destp + 8 * (destp->ip6d_len + 1);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy while (endptr - (uint8_t *)optp > sizeof (*optp)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy optp = (struct ip6_opt *)((uint8_t *)optp + optp->ip6o_len + 2);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Received ICMPv6 error in response to an X over IPv6 packet that we
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * transmitted.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * NOTE: "outer" refers to what's inside the ICMP payload. We will get one of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the following:
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * [IPv6(0)][ICMPv6][IPv6(1)][IPv4][ULP]
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * [IPv6(0)][ICMPv6][IPv6(1)][IPv6(2)][ULP]
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * And "outer6" will get set to IPv6(1), and inner[46] will correspond to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * whatever the very-inner packet is (IPv4 or IPv6(2)).
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_input_icmp_v6(iptun_t *iptun, mblk_t *data_mp, icmp6_t *icmp6h,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Temporarily move b_rptr forward so that iptun_find_headers() can
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * find IP headers in the ICMP packet payload.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The ip module ensures that ICMP errors contain at least the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * original IP header (otherwise, the error would never have made it
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer_hlen = iptun_find_headers(data_mp, 0, &outer4, &inner4, &outer6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_drop_pkt(data_mp, &iptun->iptun_ierrors);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark data_mp = ipsec_tun_inbound(ira, data_mp, iptun->iptun_itp,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark inner4, inner6, outer4, outer6, -outer_hlen, iptun->iptun_ns);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Callee did all of the freeing. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* We should never see reassembled fragment here. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy data_mp->b_rptr = (uint8_t *)outer6 + outer_hlen;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the original packet being transmitted was itself an ICMP error,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * then drop this packet. We don't want to generate an ICMP error in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * response to an ICMP error.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_norcvbuf);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the ICMPv6 error points to a valid Tunnel Encapsulation
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Limit option and the limit value is 0, then fall through
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * and send a host unreachable message. Otherwise, treat the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * error as an output error, as there must have been a problem
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * with a packet we sent.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!iptun_find_encaplimit(data_mp, outer6, &encaplim_ptr) ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ((ptrdiff_t)encaplim_ptr - (ptrdiff_t)outer6)) ||
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_oerrors);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* FALLTHRU */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy type = (inner4 != NULL ? ICMP_DEST_UNREACHABLE :
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy code = (inner4 != NULL ? ICMP_HOST_UNREACHABLE :
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We reconcile this with the fact that the tunnel may also
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * have IPsec policy by letting iptun_update_mtu take care of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_icmp_fragneeded_v4(iptun, newmtu, inner4,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_icmp_toobig_v6(iptun, newmtu, inner6, data_mp,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_drop_pkt(data_mp, &iptun->iptun_norcvbuf);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_icmp_error_v4(iptun, inner4, data_mp, type, code,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_icmp_error_v6(iptun, inner6, data_mp, type, code, 0,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Called as conn_recvicmp from IP for ICMP errors.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark/* ARGSUSED2 */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_input_icmp(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *ira)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Since ICMP error processing necessitates access to bits
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that are within the ICMP error payload (the original packet
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that caused the error), pull everything up into a single
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * block for convenience.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The outer IP header coming up from IP is always ipha_t
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * alligned (otherwise, we would have crashed in ip).
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_input_icmp_v4(iptun, mp, (icmph_t *)(mp->b_rptr + hlen),
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_input_icmp_v6(iptun, mp, (icmp6_t *)(mp->b_rptr + hlen),
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_in_6to4_ok(iptun_t *iptun, ipha_t *outer4, ip6_t *inner6)
d501bbfebe95a313ee5e78368177b1667a71c628Sebastien Roy * It's possible that someone sent us an IPv4-in-IPv4 packet with the
d501bbfebe95a313ee5e78368177b1667a71c628Sebastien Roy * IPv4 address of a 6to4 tunnel as the destination.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Make sure that the IPv6 destination is within the site that this
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * 6to4 tunnel is routing for. We don't want people bouncing random
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunneled IPv6 packets through this 6to4 router.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IN6_6TO4_TO_V4ADDR(&inner6->ip6_dst, (struct in_addr *)&v4addr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Section 9 of RFC 3056 (security considerations) suggests
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that when a packet is from a 6to4 site (i.e., it's not a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * global address being forwarded froma relay router), make
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * sure that the packet was tunneled by that site's 6to4
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IN6_6TO4_TO_V4ADDR(&inner6->ip6_src, (struct in_addr *)&v4addr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Only accept packets from a relay router if we've configured
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * outbound relay router functionality.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_iptuns->iptuns_relay_rtr_addr == INADDR_ANY)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Input function for everything that comes up from the ip module below us.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * This is called directly from the ip module via connp->conn_recv().
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We receive M_DATA messages with IP-in-IP tunneled packets.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark/* ARGSUSED2 */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_input(void *arg, mblk_t *data_mp, void *arg2, ip_recv_attr_t *ira)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer_hlen = iptun_find_headers(data_mp, ira->ira_ip_hdr_length,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the system is labeled, we call tsol_check_dest() on the packet
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * destination (our local tunnel address) to ensure that the packet as
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * labeled should be allowed to be sent to us. We don't need to call
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the more involved tsol_receive_local() since the tunnel link itself
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * cannot be assigned to shared-stack non-global zones.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (tsol_check_dest(ira->ira_tsl, (outer4 != NULL ?
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (void *)&outer4->ipha_dst : (void *)&outer6->ip6_dst),
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (outer4 != NULL ? IPV4_VERSION : IPV6_VERSION),
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark data_mp = ipsec_tun_inbound(ira, data_mp, iptun->iptun_itp,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark inner4, inner6, outer4, outer6, outer_hlen, iptun->iptun_ns);
5eaa089e4e87b623f0a6f9a67f61986cb4188e2fDan McDonald /* Callee did all of the freeing. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_typeinfo->iti_type == IPTUN_TYPE_6TO4 &&
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * We need to statistically account for each packet individually, so
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * we might as well split up any b_next chains here.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy atomic_add_64(&iptun->iptun_rbytes, msgdsize(data_mp));
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark iptun_drop_pkt(data_mp, &iptun->iptun_ierrors);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Do 6to4-specific header-processing on output. Return B_TRUE if the packet
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * was processed without issue, or B_FALSE if the packet had issues and should
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * be dropped.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_out_process_6to4(iptun_t *iptun, ipha_t *outer4, ip6_t *inner6)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPv6 source must be a 6to4 address. This is because a conscious
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * decision was made to not allow a Solaris system to be used as a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * relay router (for security reasons) when 6to4 was initially
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * integrated. If this decision is ever reversed, the following check
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * can be removed.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * RFC3056 mandates that the IPv4 source MUST be set to the IPv4
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * portion of the 6to4 IPv6 source address. In other words, make sure
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that we're tunneling packets from our own 6to4 site.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy IN6_6TO4_TO_V4ADDR(&inner6->ip6_src, (struct in_addr *)&v4addr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Automatically set the destination of the outer IPv4 header as
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * described in RFC3056. There are two possibilities:
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * a. If the IPv6 destination is a 6to4 address, set the IPv4 address
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * to the IPv4 portion of the 6to4 address.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * b. If the IPv6 destination is a native IPv6 address, set the IPv4
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * destination to the address of a relay router.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Design Note: b shouldn't be necessary here, and this is a flaw in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the design of the 6to4relay command. Instead of setting a 6to4
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * relay address in this module via an ioctl, the 6to4relay command
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * could simply add a IPv6 route for native IPv6 addresses (such as a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * default route) in the forwarding table that uses a 6to4 destination
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * as its next hop, and the IPv4 portion of that address could be a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * 6to4 relay address. In order for this to work, IP would have to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * resolve the next hop address, which would necessitate a link-layer
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * address resolver for 6to4 links, which doesn't exist today.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * In fact, if a resolver existed for 6to4 links, then setting the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPv4 destination in the outer header could be done as part of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * link-layer address resolution and fast-path header generation, and
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* destination is a 6to4 router */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Reject attempts to send to INADDR_ANY */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The destination is a native IPv6 address. If output to a
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * relay-router is enabled, use the relay-router's IPv4
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * address as the destination.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (iptun->iptun_iptuns->iptuns_relay_rtr_addr == INADDR_ANY)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy outer4->ipha_dst = iptun->iptun_iptuns->iptuns_relay_rtr_addr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If the outer source and destination are equal, this means that the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * 6to4 router somehow forwarded an IPv6 packet destined for its own
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * 6to4 site to its 6to4 tunnel interface, which will result in this
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * packet infinitely bouncing between ip and iptun.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy return (outer4->ipha_src != outer4->ipha_dst);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Process output packets with outer IPv4 headers. Frees mp and bumps stat on
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_out_process_ipv4(iptun_t *iptun, mblk_t *mp, ipha_t *outer4,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ipha_t *inner4, ip6_t *inner6, ip_xmit_attr_t *ixa)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark size_t minmtu = iptun->iptun_typeinfo->iti_minmtu;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(outer4->ipha_protocol == IPPROTO_ENCAP);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Copy the tos from the inner IPv4 header. We mask off ECN
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * bits (bits 6 and 7) because there is currently no
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * tunnel-tunnel communication to determine if both sides
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * support ECN. We opt for the safe choice: don't copy the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * ECN bits when doing encapsulation.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(outer4->ipha_protocol == IPPROTO_IPV6 &&
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer4->ipha_fragment_offset_and_flags |= IPH_DF_HTONS;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer4->ipha_fragment_offset_and_flags &= ~IPH_DF_HTONS;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * As described in section 3.2.2 of RFC4213, if the packet payload is
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * less than or equal to the minimum MTU size, then we need to allow
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * IPv4 to fragment the packet. The reason is that even if we end up
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * receiving an ICMP frag-needed, the interface above this tunnel
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * won't be allowed to drop its MTU as a result, since the packet was
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * already smaller than the smallest allowable MTU for that interface.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark } else if (!(ixa->ixa_flags & IXAF_PMTU_TOO_SMALL) &&
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark (iptun->iptun_typeinfo->iti_type != IPTUN_TYPE_6TO4)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_ip_hdr_length = IPH_HDR_LENGTH(outer4);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Insert an encapsulation limit destination option in the packet provided.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Always consumes the mp argument and returns a new mblk pointer.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Royiptun_insert_encaplimit(iptun_t *iptun, mblk_t *mp, ip6_t *outer6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark newmp = allocb(sizeof (iptun_ipv6hdrs_t) + MBLKL(mp), BPRI_MED);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Copy the payload (Starting with the inner IPv6 header). */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy newouter6 = (iptun_ipv6hdrs_t *)newmp->b_rptr;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Now copy the outer IPv6 header. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy bcopy(outer6, &newouter6->it6h_ip6h, sizeof (ip6_t));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy newouter6->it6h_ip6h.ip6_nxt = IPPROTO_DSTOPTS;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy newouter6->it6h_encaplim = iptun_encaplim_init;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy newouter6->it6h_encaplim.iel_destopt.ip6d_nxt = outer6->ip6_nxt;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy newouter6->it6h_encaplim.iel_telopt.ip6ot_encap_limit = limit;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The payload length will be set at the end of
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * iptun_out_process_ipv6().
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Process output packets with outer IPv6 headers. Frees mp and bumps stats
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_out_process_ipv6(iptun_t *iptun, mblk_t *mp, ip6_t *outer6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ipha_t *inner4, ip6_t *inner6, ip_xmit_attr_t *ixa)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark size_t minmtu = iptun->iptun_typeinfo->iti_minmtu;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (inner6 != NULL && iptun_find_encaplimit(mp, inner6, &limit)) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The inner packet is an IPv6 packet which itself contains an
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * encapsulation limit option. The limit variable points to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the value in the embedded option. Process the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * encapsulation limit option as specified in RFC 2473.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If limit is 0, then we've exceeded the limit and we need to
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * send back an ICMPv6 parameter problem message.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If limit is > 0, then we decrement it by 1 and make sure
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * that the encapsulation limit option in the outer header
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * reflects that (adding an option if one isn't already
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy ASSERT(limit > mp->b_rptr && limit < mp->b_wptr);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy iptun_icmp_error_v6(iptun, inner6, mp, ICMP6_PARAM_PROB,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The outer header requires an encapsulation limit option.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * If there isn't one already, add one.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((mp = iptun_insert_encaplimit(iptun, mp, outer6,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * There is an existing encapsulation limit option in
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * the outer header. If the inner encapsulation limit
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * is less than the configured encapsulation limit,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * update the outer encapsulation limit to reflect
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * this lesser value.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy &v6hdrs->it6h_encaplim.iel_telopt.ip6ot_encap_limit;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_ip_hdr_length = sizeof (iptun_ipv6hdrs_t);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_protocol = v6hdrs->it6h_encaplim.iel_destopt.ip6d_nxt;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * See iptun_output_process_ipv4() why we allow fragmentation for
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * small packets
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark else if (!(ixa->ixa_flags & IXAF_PMTU_TOO_SMALL))
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer6->ip6_plen = htons(ixa->ixa_pktlen - sizeof (ip6_t));
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The IP tunneling MAC-type plugins have already done most of the header
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * processing and validity checks. We are simply responsible for multiplexing
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * down to the ip module below us.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (iptun->iptun_typeinfo->iti_type == IPTUN_TYPE_6TO4) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Since the label can be different meaning a potentially
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * different IRE,we always use a unique ip_xmit_attr_t.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * If no other thread is using conn_ixa this just gets a
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * reference to conn_ixa. Otherwise we get a safe copy of
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * In case we got a safe copy of conn_ixa, then we need
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * to fill in any pointers in it.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark error = ip_attr_connect(connp, ixa, &connp->conn_saddr_v6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark &connp->conn_faddr_v6, &connp->conn_faddr_v6, 0,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark (error == EHOSTUNREACH || error == ENETUNREACH)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * the error and send any local ICMP error.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We use an ixa based on the last destination.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ASSERT(mp->b_cont == NULL); /* Verified by iptun_output */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Make sure we set ipha_dst before we look at ipha_dst */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark (void) iptun_find_headers(mp, 0, &outer4, &inner4, &outer6, &inner6);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (!iptun_out_process_6to4(iptun, outer4, inner6)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Since the label can be different meaning a potentially
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * different IRE,we always use a unique ip_xmit_attr_t.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * If no other thread is using conn_ixa this just gets a
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * reference to conn_ixa. Otherwise we get a safe copy of
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (connp->conn_v4lastdst == outer4->ipha_dst) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* In case previous destination was multirt */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We later update conn_ixa when we update conn_v4lastdst
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * which enables subsequent packets to avoid redoing
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * ip_attr_connect
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * In case we got a safe copy of conn_ixa, or otherwise we don't
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * have a current ixa_ire, then we need to fill in any pointers in
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark IN6_IPADDR_TO_V4MAPPED(outer4->ipha_dst, &v6dst);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* We handle IPsec in iptun_output_common */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark error = ip_attr_connect(connp, ixa, &connp->conn_saddr_v6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark (error == EHOSTUNREACH || error == ENETUNREACH)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * the error and send any local ICMP error.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Atomically replace conn_ixa and conn_v4lastdst */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark if (connp->conn_v4lastdst != outer4->ipha_dst) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Remember the dst which corresponds to conn_ixa */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Check the destination/label. Modifies *mpp by adding/removing CIPSO.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We get the label from the message in order to honor the
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * ULPs/IPs choice of label. This will be NULL for forwarded
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * packets, neighbor discovery packets and some others.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_output_check_label(mblk_t **mpp, ip_xmit_attr_t *ixa)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * We need to start with a label based on the IP/ULP above us
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Need to update packet with any CIPSO option since
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * conn_ip_output doesn't do that.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_zoneid, mpp, CONN_MAC_DEFAULT, B_FALSE,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark adjust = (int)ntohs(ipha->ipha_length) - iplen;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark ixa->ixa_zoneid, mpp, CONN_MAC_DEFAULT, B_FALSE,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* Update the label */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmarkiptun_output_common(iptun_t *iptun, ip_xmit_attr_t *ixa, mblk_t *mp)
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark outer_hlen = iptun_find_headers(mp, 0, &outer4, &inner4, &outer6,
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau /* Save IXAF_DONTFRAG value */
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau iaflags_t dontfrag = ixa->ixa_flags & IXAF_DONTFRAG;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Perform header processing. */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark mp = iptun_out_process_ipv4(iptun, mp, outer4, inner4, inner6,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark mp = iptun_out_process_ipv6(iptun, mp, outer6, inner4, inner6,
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * Let's hope the compiler optimizes this with "branch taken".
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (itp != NULL && (itp->itp_flags & ITPF_P_ACTIVE)) {
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* This updates the ip_xmit_attr_t */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark mp = ipsec_tun_outbound(mp, iptun, inner4, inner6, outer4,
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Might change the packet by adding/removing CIPSO.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * After this caller inner* and outer* and outer_hlen
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * might be invalid.
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * ipsec_tun_outbound() returns a chain of tunneled IP
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * fragments linked with b_next (or a single message if the
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * tunneled packet wasn't a fragment).
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * If fragcache returned a list then we need to update
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * ixa_pktlen for all packets in the list.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Otherwise, we're good to go. The ixa has been updated with
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * instructions for outbound IPsec processing.
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau size_t minmtu = iptun->iptun_typeinfo->iti_minmtu;
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark atomic_add_64(&iptun->iptun_obytes, ixa->ixa_pktlen);
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * The IXAF_DONTFRAG flag is global, but there is
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * a chain here. Check if we're really already
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * smaller than the minimum allowed MTU and reset here
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * appropriately. Otherwise one small packet can kill
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * the whole chain's path mtu discovery.
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * In addition, update the pktlen to the length of
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau * the actual packet being processed.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark atomic_add_64(&iptun->iptun_obytes, ixa->ixa_pktlen);
d1a98e54c39b20b053009684438e5f3b1cdfeb82Paul Wernau /* Restore IXAF_DONTFRAG value */
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* IPsec policy might have changed */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * The ip module will potentially apply global policy to the
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy * packet in its output path if there's no active tunnel
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark mp = ip_output_attach_policy(mp, outer4, outer6, NULL, ixa);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * Might change the packet by adding/removing CIPSO.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * After this caller inner* and outer* and outer_hlen
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark * might be invalid.
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark atomic_add_64(&iptun->iptun_obytes, ixa->ixa_pktlen);
bd670b35a010421b6e1a5536c34453a827007c81Erik Nordmark /* IPsec policy might have changed */