25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * CDDL HEADER START
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * The contents of this file are subject to the terms of the
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Common Development and Distribution License (the "License").
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * You may not use this file except in compliance with the License.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * See the License for the specific language governing permissions
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * and limitations under the License.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * If applicable, add the following below this CDDL HEADER, with the
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner]
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * CDDL HEADER END
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello * Copyright (c) 2015, Joyent, Inc. All rights reserved.
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipek * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Implementation overview for DHCP address detection
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The purpose of DHCP address detection is to relieve the user of having to
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * manually configure static IP addresses when ip-nospoof protection is turned
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * on. To achieve this, the mac layer needs to intercept DHCP packets to
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * determine the assigned IP addresses.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * A DHCP handshake between client and server typically requires at least
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 4 messages:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 1. DISCOVER - client attempts to locate DHCP servers via a
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * broadcast message to its subnet.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 2. OFFER - server responds to client with an IP address and
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * other parameters.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 3. REQUEST - client requests the offered address.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 4. ACK - server verifies that the requested address matches
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * the one it offered.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * DHCPv6 behaves pretty much the same way aside from different message names.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Address information is embedded in either the OFFER or REQUEST message.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * We chose to intercept REQUEST because this is at the last part of the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * handshake and it indicates that the client intends to keep the address.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Intercepting OFFERs is unreliable because the client may receive multiple
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * offers from different servers, and we can't tell which address the client
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Each DHCP message has a transaction ID. We use this transaction ID to match
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * REQUESTs with ACKs received from servers.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * For IPv4, the process to acquire a DHCP-assigned address is as follows:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 1. Client sends REQUEST. a new dhcpv4_txn_t object is created and inserted
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * in the the mci_v4_pending_txn table (keyed by xid). This object represents
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * a new transaction. It contains the xid, the client ID and requested IP
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 2. Server responds with an ACK. The xid from this ACK is used to lookup the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * pending transaction from the mci_v4_pending_txn table. Once the object is
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * found, it is removed from the pending table and inserted into the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * completed table (mci_v4_completed_txn, keyed by client ID) and the dynamic
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * IP table (mci_v4_dyn_ip, keyed by IP address).
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 3. An outgoing packet that goes through the ip-nospoof path will be checked
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * against the dynamic IP table. Packets that have the assigned DHCP address
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * as the source IP address will pass the check and be admitted onto the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * IPv4 notes:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * If the server never responds with an ACK, there is a timer that is set after
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * the insertion of the transaction into the pending table. When the timer
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * fires, it will check whether the transaction is old (by comparing current
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * time and the txn's timestamp), if so the transaction will be freed. along
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * with this, any transaction in the completed/dyn-ip tables matching the client
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * ID of this stale transaction will also be freed. If the client fails to
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * extend a lease, we want to stop the client from using any IP addresses that
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * were granted previously.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * A RELEASE message from the client will not cause a transaction to be created.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The client ID in the RELEASE message will be used for finding and removing
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * transactions in the completed and dyn-ip tables.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * For IPv6, the process to acquire a DHCPv6-assigned address is as follows:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 1. Client sends REQUEST. The DUID is extracted and stored into a dhcpv6_cid_t
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * structure. A new transaction structure (dhcpv6_txn_t) is also created and
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * it will point to the dhcpv6_cid_t. If an existing transaction with a
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * matching xid is not found, this dhcpv6_txn_t will be inserted into the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * mci_v6_pending_txn table (keyed by xid).
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 2. Server responds with a REPLY. If a pending transaction is found, the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * addresses in the reply will be placed into the dhcpv6_cid_t pointed to by
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * the transaction. The dhcpv6_cid_t will then be moved to the mci_v6_cid
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * table (keyed by cid). The associated addresses will be added to the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * mci_v6_dyn_ip table (while still being pointed to by the dhcpv6_cid_t).
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 3. IPv6 ip-nospoof will now check mci_v6_dyn_ip for matching packets.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Packets with a source address matching one of the DHCPv6-assigned
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * addresses will be allowed through.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * IPv6 notes:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The v6 code shares the same timer as v4 for scrubbing stale transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Just like v4, as part of removing an expired transaction, a RELEASE will be
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * be triggered on the cid associated with the expired transaction.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The data structures used for v6 are slightly different because a v6 client
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * may have multiple addresses associated with it.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * These are just arbitrary limits meant for preventing abuse (e.g. a user
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * flooding the network with bogus transactions). They are not meant to be
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * user-modifiable so they are not exposed as linkprops.
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipekstatic hrtime_t txn_cleanup_interval = 60 * NANOSEC;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * DHCPv4 transaction. It may be added to three different tables
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * (keyed by different fields).
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * DHCPv6 address. May be added to mci_v6_dyn_ip.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * It is always pointed to by its parent dhcpv6_cid_t structure.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * DHCPv6 client ID. May be added to mci_v6_cid.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * No dhcpv6_txn_t should be pointing to it after it is added to mci_v6_cid.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * DHCPv6 transaction. Unlike its v4 counterpart, this object gets freed up
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * as soon as the transaction completes or expires.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * Stateless address autoconfiguration (SLAAC) address. May be added to
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * mci_v6_slaac_ip.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void start_txn_cleanup_timer(mac_client_impl_t *);
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhanstatic boolean_t allowed_ips_set(mac_resource_props_t *, uint32_t);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer#define BUMP_STAT(m, s) (m)->mci_misc_stat.mms_##s++
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Comparison functions for the 3 AVL trees used:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * mci_v4_pending_txn, mci_v4_completed_txn, mci_v4_dyn_ip
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv4_xid(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv4_txn_t *txn1 = arg1, *txn2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv4_cid(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv4_txn_t *txn1 = arg1, *txn2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer else if (txn1->dt_cid_len > txn2->dt_cid_len)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ret = memcmp(txn1->dt_cid, txn2->dt_cid, txn1->dt_cid_len);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer else if (ret > 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv4_ip(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv4_txn_t *txn1 = arg1, *txn2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Find the specified DHCPv4 option.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv4_option(struct dhcp *dh4, uchar_t *end, uint8_t type,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Locate the start of a DHCPv4 header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The possible return values and associated meanings are:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 0 - packet is DHCP and has a DHCP header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * EINVAL - packet is not DHCP. the recommended action is to let it pass.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * ENOSPC - packet is a initial fragment that is DHCP or is unidentifiable.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * the recommended action is to drop it.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv4_info(ipha_t *ipha, uchar_t *end, struct dhcp **dh4)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer offset_and_flags = ntohs(ipha->ipha_fragment_offset_and_flags);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((offset_and_flags & (IPH_MF | IPH_OFFSET)) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * All non-initial fragments may pass because we cannot
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * identify their type. It's safe to let them through
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * because reassembly will fail if we decide to drop the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * initial fragment.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* drop packets without a udp header */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer udph = (struct udphdr *)((uchar_t *)ipha + IPH_HDR_LENGTH(ipha));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (udph->uh_sport != client && udph->uh_sport != server &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer udph->uh_dport != client && udph->uh_dport != server)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* drop dhcp fragments */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Wrappers for accesses to avl trees to improve readability.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Their purposes are fairly self-explanatory.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerfind_dhcpv4_pending_txn(mac_client_impl_t *mcip, uint32_t xid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (avl_find(&mcip->mci_v4_pending_txn, &tmp_txn, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerinsert_dhcpv4_pending_txn(mac_client_impl_t *mcip, dhcpv4_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v4_pending_txn, txn, &where) != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_numnodes(&mcip->mci_v4_pending_txn) >= dhcp_max_pending_txn) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_insert(&mcip->mci_v4_pending_txn, txn, where);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerremove_dhcpv4_pending_txn(mac_client_impl_t *mcip, dhcpv4_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerfind_dhcpv4_completed_txn(mac_client_impl_t *mcip, uint8_t *cid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (avl_find(&mcip->mci_v4_completed_txn, &tmp_txn, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * After a pending txn is removed from the pending table, it is inserted
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * into both the completed and dyn-ip tables. These two insertions are
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * done together because a client ID must have 1:1 correspondence with
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * an IP address and IP addresses must be unique in the dyn-ip table.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerinsert_dhcpv4_completed_txn(mac_client_impl_t *mcip, dhcpv4_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v4_completed_txn, txn, &where) != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_numnodes(&mcip->mci_v4_completed_txn) >=
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_insert(&mcip->mci_v4_completed_txn, txn, where);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v4_dyn_ip, txn, &where) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_remove(&mcip->mci_v4_completed_txn, txn);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_insert(&mcip->mci_v4_dyn_ip, txn, where);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerremove_dhcpv4_completed_txn(mac_client_impl_t *mcip, dhcpv4_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((ctxn = avl_find(&mcip->mci_v4_dyn_ip, txn, NULL)) != NULL &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_remove(&mcip->mci_v4_completed_txn, txn);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Check whether an IP address is in the dyn-ip table.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercheck_dhcpv4_dyn_ip(mac_client_impl_t *mcip, ipaddr_t ipaddr)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer txn = avl_find(&mcip->mci_v4_dyn_ip, &tmp_txn, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Create/destroy a DHCPv4 transaction.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercreate_dhcpv4_txn(uint32_t xid, uint8_t *cid, uint8_t cid_len, ipaddr_t ipaddr)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = kmem_zalloc(sizeof (*txn), KM_NOSLEEP)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Clean up all v4 tables.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((txn = avl_destroy_nodes(&mcip->mci_v4_dyn_ip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * No freeing needed here because the same txn exists
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * in the mci_v4_completed_txn table as well.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((txn = avl_destroy_nodes(&mcip->mci_v4_completed_txn,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((txn = avl_destroy_nodes(&mcip->mci_v4_pending_txn,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Cleanup stale DHCPv4 transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer dhcpv4_txn_t *txn, *ctxn, *next, *txn_list = NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Find stale pending transactions and place them on a list
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * to be removed.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (txn = avl_first(&mcip->mci_v4_pending_txn); txn != NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer txn = avl_walk(&mcip->mci_v4_pending_txn, txn, AVL_AFTER)) {
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipek if (gethrtime() - txn->dt_timestamp > txn_cleanup_interval) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Remove and free stale pending transactions and completed
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * transactions with the same client IDs as the stale transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (txn = txn_list; txn != NULL; txn = next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ctxn = find_dhcpv4_completed_txn(mcip, txn->dt_cid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(freeing__txn, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Core logic for intercepting outbound DHCPv4 packets.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerintercept_dhcpv4_outbound(mac_client_impl_t *mcip, ipha_t *ipha, uchar_t *end)
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan uint8_t opt_len, mtype, cid[DHCP_MAX_OPT_SIZE], cid_len;
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan /* ip_nospoof/allowed-ips and DHCP are mutually exclusive by default */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv4_option(dh4, end, CD_DHCP_TYPE, &opt, &opt_len) != 0 ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(mtype__not__found, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE3(ignored__mtype, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* client ID is optional for IPv4 */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv4_option(dh4, end, CD_CLIENT_ID, &opt, &opt_len) == 0 &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(release, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* flush any completed txn with this cid */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ctxn = find_dhcpv4_completed_txn(mcip, cid, cid_len);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(release__successful, mac_client_impl_t *,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * If a pending txn already exists, we'll update its timestamp so
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * it won't get flushed by the timer. We don't need to create new
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * txns for retransmissions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = find_dhcpv4_pending_txn(mcip, dh4->xid)) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv4_option(dh4, end, CD_REQUESTED_IP_ADDR,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer &opt, &opt_len) != 0 || opt_len != sizeof (ipaddr)) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(ipaddr__not__found, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = create_dhcpv4_txn(dh4->xid, cid, cid_len, ipaddr)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (insert_dhcpv4_pending_txn(mcip, txn) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__pending, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Core logic for intercepting inbound DHCPv4 packets.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellointercept_dhcpv4_inbound(mac_client_impl_t *mcip, uchar_t *end,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv4_option(dh4, end, CD_DHCP_TYPE, &opt, &opt_len) != 0 ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(mtype__not__found, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE3(ignored__mtype, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = find_dhcpv4_pending_txn(mcip, dh4->xid)) == NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__not__found, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * We're about to move a txn from the pending table to the completed/
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * dyn-ip tables. If there is an existing completed txn with the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * same cid as our txn, we need to remove and free it.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ctxn = find_dhcpv4_completed_txn(mcip, txn->dt_cid, txn->dt_cid_len);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(replacing__old__txn, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(nak__received, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (insert_dhcpv4_completed_txn(mcip, txn) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__completed, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Comparison functions for the DHCPv6 AVL trees.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv6_xid(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv6_txn_t *txn1 = arg1, *txn2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv6_ip(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv6_addr_t *ip1 = arg1, *ip2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ret = memcmp(&ip1->da_addr, &ip2->da_addr, sizeof (in6_addr_t));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer else if (ret > 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercompare_dhcpv6_cid(const void *arg1, const void *arg2)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer const dhcpv6_cid_t *cid1 = arg1, *cid2 = arg2;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer else if (cid1->dc_cid_len > cid2->dc_cid_len)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ret = memcmp(cid1->dc_cid, cid2->dc_cid, cid1->dc_cid_len);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer else if (ret > 0)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellocompare_slaac_ip(const void *arg1, const void *arg2)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello const slaac_addr_t *ip1 = arg1, *ip2 = arg2;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello ret = memcmp(&ip1->sla_addr, &ip2->sla_addr, sizeof (in6_addr_t));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello else if (ret > 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Locate the start of a DHCPv6 header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The possible return values and associated meanings are:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * 0 - packet is DHCP and has a DHCP header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * EINVAL - packet is not DHCP. the recommended action is to let it pass.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * ENOSPC - packet is a initial fragment that is DHCP or is unidentifiable.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * the recommended action is to drop it.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv6_info(ip6_t *ip6h, uchar_t *end, dhcpv6_message_t **dh6)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!mac_ip_hdr_length_v6(ip6h, end, &hdrlen, &proto, &frag))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * All non-initial fragments may pass because we cannot
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * identify their type. It's safe to let them through
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * because reassembly will fail if we decide to drop the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * initial fragment.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* drop packets without a udp header */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer udph = (struct udphdr *)((uchar_t *)ip6h + hdrlen);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (udph->uh_sport != client && udph->uh_sport != server &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer udph->uh_dport != client && udph->uh_dport != server)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* drop dhcp fragments */
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Melloget_ra_info(ip6_t *ip6h, uchar_t *end, nd_router_advert_t **ra)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (!mac_ip_hdr_length_v6(ip6h, end, &hdrlen, &proto, &frag))
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * All non-initial fragments may pass because we cannot
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * identify their type. It's safe to let them through
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * because reassembly will fail if we decide to drop the
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * initial fragment.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * Ensure that the ICMP header falls w/in packet boundaries, in case
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * we've received a malicious packet that reports incorrect lengths.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if ((hdrp + sizeof (struct icmp6_hdr)) > end) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (icmp->icmp6_type != ND_ROUTER_ADVERT ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Find the specified DHCPv6 option.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv6_option(void *buf, size_t buflen, dhcpv6_option_t *oldopt,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (d6o.d6o_code != codenum || d6o.d6o_len == 0 ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer (oldopt != NULL && bp <= (uchar_t *)oldopt)) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* LINTED : alignment */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Get the status code from a reply message.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv6_status(dhcpv6_message_t *dh6, uchar_t *end, uint16_t *status)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer d6o = get_dhcpv6_option(&dh6[1], end - (uchar_t *)&dh6[1], NULL,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* Success is implied if status code is missing */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (olen < sizeof (s))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Get the addresses from a reply message.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_dhcpv6_addrs(dhcpv6_message_t *dh6, uchar_t *end, dhcpv6_cid_t *cid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((d6o = get_dhcpv6_option(&dh6[1], end - (uchar_t *)&dh6[1],
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer obase = (uchar_t *)d6o + sizeof (dhcpv6_ia_na_t);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((d6so = get_dhcpv6_option(obase, olen, d6so,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (bcmp(&(*addrp)->da_addr, &d6ia.d6ia_addr,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (in6_addr_t)) == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((*addrp = kmem_zalloc(sizeof (dhcpv6_addr_t),
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (; cid->dc_addr != NULL; cid->dc_addr = next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer kmem_free(cid->dc_addr, sizeof (dhcpv6_addr_t));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Free a cid.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Before this gets called the caller must ensure that all the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * addresses are removed from the mci_v6_dyn_ip table.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (addr = cid->dc_addr; addr != NULL; addr = next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Extract the DUID from a message. The associated addresses will be
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * extracted later from the reply message.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercreate_dhcpv6_cid(dhcpv6_message_t *dh6, uchar_t *end)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer d6o = get_dhcpv6_option(&dh6[1], end - (uchar_t *)&dh6[1], NULL,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (d6o == NULL || (uchar_t *)d6o + olen > end)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((rawcid = kmem_zalloc(rawcidlen, KM_NOSLEEP)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((cid = kmem_zalloc(sizeof (*cid), KM_NOSLEEP)) == NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Remove a cid from mci_v6_cid. The addresses owned by the cid
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * are also removed from mci_v6_dyn_ip.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerremove_dhcpv6_cid(mac_client_impl_t *mcip, dhcpv6_cid_t *cid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (addr = cid->dc_addr; addr != NULL; addr = addr->da_next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer tmp_addr = avl_find(&mcip->mci_v6_dyn_ip, addr, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Find and remove a matching cid and associated addresses from
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * their respective tables.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerrelease_dhcpv6_cid(mac_client_impl_t *mcip, dhcpv6_cid_t *cid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((oldcid = avl_find(&mcip->mci_v6_cid, cid, NULL)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Since cid belongs to a pending txn, it can't possibly be in
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * mci_v6_cid. Anything that's found must be an existing cid.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Insert cid into mci_v6_cid.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerinsert_dhcpv6_cid(mac_client_impl_t *mcip, dhcpv6_cid_t *cid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v6_cid, cid, &where) != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_numnodes(&mcip->mci_v6_cid) >= dhcp_max_completed_txn) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (addr = cid->dc_addr; addr != NULL; addr = addr->da_next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v6_dyn_ip, addr, &where) != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_insert(&mcip->mci_v6_dyn_ip, addr, where);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Check whether an IP address is in the dyn-ip table.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercheck_dhcpv6_dyn_ip(mac_client_impl_t *mcip, in6_addr_t *addr)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer bcopy(addr, &tmp_addr.da_addr, sizeof (in6_addr_t));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer a = avl_find(&mcip->mci_v6_dyn_ip, &tmp_addr, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (a != NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerfind_dhcpv6_pending_txn(mac_client_impl_t *mcip, uint32_t xid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (avl_find(&mcip->mci_v6_pending_txn, &tmp_txn, NULL));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerremove_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercreate_dhcpv6_txn(uint32_t xid, dhcpv6_cid_t *cid)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = kmem_zalloc(sizeof (dhcpv6_txn_t), KM_NOSLEEP)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerinsert_dhcpv6_pending_txn(mac_client_impl_t *mcip, dhcpv6_txn_t *txn)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_find(&mcip->mci_v6_pending_txn, txn, &where) != NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (avl_numnodes(&mcip->mci_v6_pending_txn) >= dhcp_max_pending_txn) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_insert(&mcip->mci_v6_pending_txn, txn, where);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Clean up all v6 tables.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while (avl_destroy_nodes(&mcip->mci_v6_dyn_ip, &cookie) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((cid = avl_destroy_nodes(&mcip->mci_v6_cid, &cookie)) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((txn = avl_destroy_nodes(&mcip->mci_v6_pending_txn,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello while ((addr = avl_destroy_nodes(&mcip->mci_v6_slaac_ip, &cookie)) !=
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Cleanup stale DHCPv6 transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Find stale pending transactions and place them on a list
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * to be removed.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (txn = avl_first(&mcip->mci_v6_pending_txn); txn != NULL;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer txn = avl_walk(&mcip->mci_v6_pending_txn, txn, AVL_AFTER)) {
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipek if (gethrtime() - txn->dt_timestamp > txn_cleanup_interval) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Remove and free stale pending transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Release any existing cids matching the stale transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (txn = txn_list; txn != NULL; txn = next) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(freeing__txn, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Core logic for intercepting outbound DHCPv6 packets.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerintercept_dhcpv6_outbound(mac_client_impl_t *mcip, ip6_t *ip6h, uchar_t *end)
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan /* ip_nospoof/allowed-ips and DHCP are mutually exclusive by default */
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello * We want to act on packets that result in DHCPv6 Reply messages, or
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello * on packets that give up an IPv6 address. For example, a Request or
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello * Solicit (w/ the Rapid Commit option) will cause the server to send a
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello * Reply, ending the transaction.
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello if (mtype != DHCPV6_MSG_SOLICIT && mtype != DHCPV6_MSG_REQUEST &&
146e34b68e0380c276523b9f82600fb18f9730a9Cody Peter Mello mtype != DHCPV6_MSG_RENEW && mtype != DHCPV6_MSG_REBIND &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((cid = create_dhcpv6_cid(dh6, end)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = find_dhcpv6_pending_txn(mcip, xid)) != NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(update, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = create_dhcpv6_txn(xid, cid)) == NULL)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (insert_dhcpv6_pending_txn(mcip, txn) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__pending, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Core logic for intercepting inbound DHCPv6 packets.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellointercept_dhcpv6_inbound(mac_client_impl_t *mcip, uchar_t *end,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((txn = find_dhcpv6_pending_txn(mcip, xid)) == NULL) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__not__found, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv6_status(dh6, end, &status) != 0 ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(error__status, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv6_addrs(dh6, end, txn->dt_cid) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(no__addrs, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (insert_dhcpv6_cid(mcip, txn->dt_cid) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(insert__failed, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(txn__completed, mac_client_impl_t *, mcip,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * Check whether an IP address is in the SLAAC table.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellocheck_slaac_ip(mac_client_impl_t *mcip, in6_addr_t *addr)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello bcopy(addr, &tmp_addr.sla_addr, sizeof (in6_addr_t));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello a = avl_find(&mcip->mci_v6_slaac_ip, &tmp_addr, NULL);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello return (a != NULL);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Melloinsert_slaac_ip(avl_tree_t *tree, in6_addr_t *token, slaac_addr_t *addr)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello bcopy(prefix, in6p, sizeof (struct in6_addr));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello for (i = 0; i < 4; i++) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello DTRACE_PROBE1(generated__addr, in6_addr_t *, in6p);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Melloinsert_slaac_prefix(mac_client_impl_t *mcip, nd_opt_prefix_info_t *po)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello in6_addr_t *token = &mcip->mci_v6_mac_token;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (avl_numnodes(&mcip->mci_v6_slaac_ip) >= slaac_max_allowed) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if ((addr = kmem_zalloc(sizeof (slaac_addr_t),
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello bcopy(&po->nd_opt_pi_prefix, &addr->sla_prefix,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello sizeof (struct in6_addr));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (!insert_slaac_ip(&mcip->mci_v6_slaac_ip, token, addr)) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellointercept_prefix_info(mac_client_impl_t *mcip, nd_opt_prefix_info_t *po)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (8 * po->nd_opt_pi_len != sizeof (nd_opt_prefix_info_t)) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) == 0)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * If we receive a Router Advertisement carrying prefix information and
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * indicating that SLAAC should be performed, then track the prefix.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellointercept_ra_inbound(mac_client_impl_t *mcip, ip6_t *ip6h, uchar_t *end,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello DTRACE_PROBE1(invalid__hoplimit, uint8_t, ip6h->ip6_hlim);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello len = ip6h->ip6_plen - sizeof (nd_router_advert_t);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello while (len >= sizeof (struct nd_opt_hdr) &&
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello ((uchar_t *)opt + sizeof (struct nd_opt_hdr)) <= end) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (opt->nd_opt_type == ND_OPT_PREFIX_INFORMATION) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello opt = (struct nd_opt_hdr *)((char *)opt + optlen);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Timer for cleaning up stale transactions.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* do nothing if timer got cancelled */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Restart timer if pending transactions still exist.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!avl_is_empty(&mcip->mci_v4_pending_txn) ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE1(restarting__timer, mac_client_impl_t *, mcip);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipek drv_usectohz(txn_cleanup_interval / (NANOSEC / MICROSEC)));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstart_txn_cleanup_timer(mac_client_impl_t *mcip)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mcip->mci_txn_cleanup_tid = timeout(txn_cleanup_timer, mcip,
4d6a58d3c7586ed5866f9309d460081a9102c5e6Josef 'Jeff' Sipek drv_usectohz(txn_cleanup_interval / (NANOSEC / MICROSEC)));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyercancel_txn_cleanup_timer(mac_client_impl_t *mcip)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * This needs to be a while loop because the timer could get
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * rearmed during untimeout().
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer while ((tid = mcip->mci_txn_cleanup_tid) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Get the start/end pointers of an L3 packet and also do pullup if needed.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * pulled-up packet needs to be freed by the caller.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerget_l3_info(mblk_t *mp, size_t hdrsize, uchar_t **start, uchar_t **end,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Pullup if necessary but reject packets that do not have
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * a proper mac header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Temporarily adjust mp->b_rptr to ensure proper
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * alignment of IP header in newmp.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellomac_protect_intercept_dynamic_one(mac_client_impl_t *mcip, mblk_t *mp)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer err = mac_vlan_header_info((mac_handle_t)mip, mp, &mhi);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(invalid__header, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer err = get_l3_info(mp, mhi.mhi_hdrsize, &start, &end, &nmp);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(invalid__l3, mac_client_impl_t *, mcip,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (get_dhcpv4_info(ipha, end, &dh4) == 0) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello if (get_dhcpv6_info(ip6h, end, &dh6) == 0) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello } else if (get_ra_info(ip6h, end, &ra) == 0) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellomac_protect_intercept_dynamic(mac_client_impl_t *mcip, mblk_t *mp)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Skip checks if we are part of an aggr.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello mac_protect_intercept_dynamic_one(mcip, mp);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellomac_protect_flush_dynamic(mac_client_impl_t *mcip)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyermac_protect_cancel_timer(mac_client_impl_t *mcip)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Check if addr is in the 'allowed-ips' list.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer/* ARGSUSED */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyeripnospoof_check_v4(mac_client_impl_t *mcip, mac_protect_t *protect,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The unspecified address is allowed.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i < protect->mp_ipaddrcnt; i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_ipaddr_t *v4addr = &protect->mp_ipaddrs[i];
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi /* LINTED E_SUSPICIOUS_COMPARISON */
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi mask = 0xFFFFFFFFu << (32 - v4addr->ip_netmask);
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * Since we have a netmask we know this entry
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * signifies the entire subnet. Check if the
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * given address is on the subnet.
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi if (htonl(V4_PART_OF_V6(v4addr->ip_addr)) ==
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan check_dhcpv4_dyn_ip(mcip, *addr) : B_FALSE);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyeripnospoof_check_v6(mac_client_impl_t *mcip, mac_protect_t *protect,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * The unspecified address and the v6 link local address are allowed.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ((mcip->mci_protect_flags & MPT_FLAG_V6_LOCAL_ADDR_SET) != 0 &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer IN6_ARE_ADDR_EQUAL(&mcip->mci_v6_local_addr, addr)))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_ipaddr_t *v6addr = &protect->mp_ipaddrs[i];
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi /* LINTED E_SUSPICIOUS_COMPARISON */
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi IN6_ARE_PREFIXEDADDR_EQUAL(&v6addr->ip_addr, addr,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Checks various fields within an IPv6 NDP packet.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyeripnospoof_check_ndp(mac_client_impl_t *mcip, mac_protect_t *protect,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * NDP packets do not have extension headers so the ICMPv6 header
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * must immediately follow the IPv6 header.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* ICMPv6 header missing */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* SLLA option checking is needed for RS/RA/NS */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer nd_neighbor_advert_t *na = (nd_neighbor_advert_t *)icmp_nd;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!ipnospoof_check_v6(mcip, protect, &na->nd_na_target)) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* TLLA option for NA */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* option checking not needed for RD */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* no options, we're done */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer opt = (nd_opt_hdr_t *)((uchar_t *)icmp_nd + hdrlen);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* find the option header we need */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer addrlen = lla->nd_opt_lla_len * 8 - sizeof (nd_opt_hdr_t);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer maclen = mcip->mci_mip->mi_info.mi_addr_length;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(ndp__lla__ok, mac_client_impl_t *, mcip, ip6_t *, ip6h);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Enforce ip-nospoof protection.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyeripnospoof_check(mac_client_impl_t *mcip, mac_protect_t *protect,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer err = get_l3_info(mp, hdrsize, &start, &end, &nmp);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(invalid__l3, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!ipnospoof_check_v4(mcip, protect, &ipha->ipha_src))
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan if (!intercept_dhcpv4_outbound(mcip, ipha, end))
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng bcmp(mcip->mci_unicast->ma_addr, shaddr, maclen) != 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!ipnospoof_check_v4(mcip, protect, &spaddr))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!ipnospoof_check_v6(mcip, protect, &ip6h->ip6_src))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!ipnospoof_check_ndp(mcip, protect, ip6h, end))
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan if (!intercept_dhcpv6_outbound(mcip, ip6h, end))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerdhcpnospoof_check_cid(mac_protect_t *p, uchar_t *cid, uint_t cidlen)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i < p->mp_cidcnt; i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerdhcpnospoof_check_v4(mac_client_impl_t *mcip, mac_protect_t *p,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((err = get_dhcpv4_info(ipha, end, &dh4)) != 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer maclen = mcip->mci_mip->mi_info.mi_addr_length;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer bcmp(mcip->mci_unicast->ma_addr, dh4->chaddr, maclen) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (get_dhcpv4_option(dh4, end, CD_CLIENT_ID, &cid, &optlen) == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (*cid == ARPHRD_ETHER && cidlen - 1 == maclen &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer bcmp(mcip->mci_unicast->ma_addr, cid + 1, maclen) == 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (dhcpnospoof_check_cid(p, cid, cidlen));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerdhcpnospoof_check_v6(mac_client_impl_t *mcip, mac_protect_t *p,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((err = get_dhcpv6_info(ip6h, end, &dh6)) != 0)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * We only check client-generated messages.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (mtype == DHCPV6_MSG_ADVERTISE || mtype == DHCPV6_MSG_REPLY ||
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer d6o = get_dhcpv6_option(&dh6[1], end - (uchar_t *)&dh6[1], NULL,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (d6o == NULL || (uchar_t *)d6o + cidlen > end)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (cidtype == DHCPV6_DUID_LLT && cidlen >= sizeof (duid_llt_t)) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (cidtype == DHCPV6_DUID_LL && cidlen >= sizeof (duid_ll_t)) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer maclen = mcip->mci_mip->mi_info.mi_addr_length;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer bcmp(mcip->mci_unicast->ma_addr, lladdr, maclen) == 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (dhcpnospoof_check_cid(p, cid, cidlen));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Enforce dhcp-nospoof protection.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerdhcpnospoof_check(mac_client_impl_t *mcip, mac_protect_t *protect,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer err = get_l3_info(mp, hdrsize, &start, &end, &nmp);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer DTRACE_PROBE2(invalid__l3, mac_client_impl_t *, mcip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!dhcpnospoof_check_v4(mcip, protect, ipha, end))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (!dhcpnospoof_check_v6(mcip, protect, ip6h, end))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* increment dhcpnospoof stat here */
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * This is called whenever the mac client's mac address changes, to make sure
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * we allow use of the new link-local address.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyermac_protect_update_v6_local_addr(mac_client_impl_t *mcip)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello in6_addr_t *token = &mcip->mci_v6_mac_token;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello in6_addr_t *v6addr = &mcip->mci_v6_local_addr;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer in6_addr_t ll_template = {(uint32_t)V6_LINKLOCAL, 0x0, 0x0, 0x0};
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello for (i = 0; i < 4; i++) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello v6addr->s6_addr32[i] = token->s6_addr32[i] |
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello mcip->mci_protect_flags |= MPT_FLAG_V6_LOCAL_ADDR_SET;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * This is called whenever the mac client's mac address changes, to make sure
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * that any existing addresses gained via SLAAC are appropriately updated.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellomac_protect_update_v6_slaac_addr(mac_client_impl_t *mcip)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello avl_tree_t *ttp = &temp_tree, *sip = &mcip->mci_v6_slaac_ip;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello in6_addr_t *token = &mcip->mci_v6_mac_token;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello avl_create(ttp, compare_slaac_ip, sizeof (slaac_addr_t),
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello /* Copy everything over to the temporary tree, and fix the IP address */
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello while ((addr = avl_destroy_nodes(sip, &cookie)) != NULL) {
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello VERIFY(insert_slaac_ip(ttp, token, addr) == B_TRUE);
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * Now that the tempory tree has all of the modified addresses, we can
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * swap them over to the original tree once it's reset.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello avl_create(sip, compare_slaac_ip, sizeof (slaac_addr_t),
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * After the unicast MAC address changes, we need to update the derived token,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * and update the IPv6 addresses that use the token.
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mellomac_protect_update_mac_token(mac_client_impl_t *mcip)
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello uint_t media = mcip->mci_mip->mi_info.mi_media;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello uint8_t *p, *macaddr = mcip->mci_unicast->ma_addr;
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello in6_addr_t *token = &mcip->mci_v6_mac_token;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer ASSERT(mcip->mci_mip->mi_info.mi_addr_length == 20);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * We do not need to generate the local address for link types
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * that do not support link protection. Wifi pretends to be
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello * Ethernet so it is covered by the DL_ETHER case (note the
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * use of mi_media instead of mi_nativemedia).
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Enforce link protection on one packet.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Chengmac_protect_check_one(mac_client_impl_t *mcip, mblk_t *mp)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng err = mac_vlan_header_info((mac_handle_t)mip, mp, &mhi);
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng DTRACE_PROBE2(invalid__header, mac_client_impl_t *, mcip,
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * ETHERTYPE_VLAN packets are allowed through, provided that
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * the vid is not spoofed.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng if (vid != 0 && !mac_client_check_flow_vid(mcip, vid)) {
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng if (sap != ETHERTYPE_IP && sap != ETHERTYPE_IPV6 &&
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((err = ipnospoof_check(mcip, protect, mp, &mhi)) != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if ((err = dhcpnospoof_check(mcip, protect, mp, &mhi)) != 0) {
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Enforce link protection on a packet chain.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Packets that pass the checks are returned back to the caller.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Chengmac_protect_check(mac_client_handle_t mch, mblk_t *mp)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Skip checks if we are part of an aggr.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Check if a particular protection type is enabled.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Chengmac_protect_enabled(mac_client_handle_t mch, uint32_t type)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer return (MAC_PROTECT_ENABLED((mac_client_impl_t *)mch, type));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i < p->mp_ipaddrcnt; i++) {
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * The unspecified address is implicitly allowed so there's no
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * need to add it to the list. Also, validate that the netmask,
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * if any, is sane for the specific version of IP. A mask of
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi * some kind is always required.
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (V4_PART_OF_V6(addr->ip_addr) == INADDR_ANY)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer } else if (addr->ip_version == IPV6_VERSION) {
e03914f9208eb53e6c8a6d5a436953ad983642b0Robert Mustacchi if (IN6_IS_ADDR_V4MAPPED_ANY(&addr->ip_addr))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* invalid ip version */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (j = 0; j < p->mp_ipaddrcnt; j++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (i == j || addr->ip_version != addr1->ip_version)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* found a duplicate */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer/* ARGSUSED */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (i = 0; i < p->mp_cidcnt; i++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer for (j = 0; j < p->mp_cidcnt; j++) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer /* found a duplicate */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (bcmp(cid->dc_id, cid1->dc_id, cid->dc_len) == 0)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Sanity-checks parameters given by userland.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng /* check for invalid types */
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng if (p->mp_types != MPT_RESET && (p->mp_types & ~MPT_ALL) != 0)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng * Enable/disable link protection.
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Chengmac_protect_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng /* tunnels are not supported */
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng if (media == DL_IPV4 || media == DL_IPV6 || media == DL_6TO4)
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Cheng mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan i_mac_notify(((mcip->mci_state_flags & MCIS_IS_VNIC) != 0 ?
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan mcip->mci_upper_mip : mip), MAC_NOTE_ALLOWED_IPS);
25ec3e3dd27cc1038c10efa18ed08f064eab5fbeEric Chengmac_protect_update(mac_resource_props_t *new, mac_resource_props_t *curr)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer bcopy(np->mp_cids, cp->mp_cids, sizeof (cp->mp_cids));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mutex_init(&mcip->mci_protect_lock, NULL, MUTEX_DRIVER, NULL);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v4_pending_txn, compare_dhcpv4_xid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv4_txn_t), offsetof(dhcpv4_txn_t, dt_node));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v4_completed_txn, compare_dhcpv4_cid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv4_txn_t), offsetof(dhcpv4_txn_t, dt_node));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v4_dyn_ip, compare_dhcpv4_ip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv4_txn_t), offsetof(dhcpv4_txn_t, dt_ipnode));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v6_pending_txn, compare_dhcpv6_xid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv6_txn_t), offsetof(dhcpv6_txn_t, dt_node));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v6_cid, compare_dhcpv6_cid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv6_cid_t), offsetof(dhcpv6_cid_t, dc_node));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer avl_create(&mcip->mci_v6_dyn_ip, compare_dhcpv6_ip,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer sizeof (dhcpv6_addr_t), offsetof(dhcpv6_addr_t, da_node));
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello avl_create(&mcip->mci_v6_slaac_ip, compare_slaac_ip,
797f979d1fe26bfb1cdeb3e7a86ed24c0b654200Cody Peter Mello sizeof (slaac_addr_t), offsetof(slaac_addr_t, sla_node));
10a404923096d60a26c785c3cee15a5c364d51c0Robert Mustacchi mcip->mci_protect_flags |= MPT_FLAG_PROMISC_FILTERED;
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhanallowed_ips_set(mac_resource_props_t *mrp, uint32_t af)
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan for (i = 0; i < mrp->mrp_protect.mp_ipaddrcnt; i++) {
550b6e4083768ca350e9e7c3a1ebbf720b23dcadSowmini Varadhan if (mrp->mrp_protect.mp_ipaddrs[i].ip_version == af)