summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/io/dld/dld_proto.c11
-rw-r--r--usr/src/uts/common/io/dld/dld_str.c4
-rw-r--r--usr/src/uts/common/io/dls/dls_link.c85
-rw-r--r--usr/src/uts/common/io/mac/mac.c2
-rw-r--r--usr/src/uts/common/io/mac/mac_client.c96
-rw-r--r--usr/src/uts/common/io/mac/mac_flow.c8
-rw-r--r--usr/src/uts/common/io/mac/mac_protect.c340
-rw-r--r--usr/src/uts/common/sys/dls_impl.h2
-rw-r--r--usr/src/uts/common/sys/mac.h1
-rw-r--r--usr/src/uts/common/sys/mac_client_priv.h1
-rw-r--r--usr/src/uts/common/sys/mac_flow.h19
-rw-r--r--usr/src/uts/common/sys/mac_impl.h6
13 files changed, 484 insertions, 93 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 5980ccc097..6f6cb4863e 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -613,7 +613,7 @@ GLD_OBJS += gld.o gldutil.o
MAC_OBJS += mac.o mac_bcast.o mac_client.o mac_datapath_setup.o mac_flow.o \
mac_hio.o mac_mod.o mac_ndd.o mac_provider.o mac_sched.o \
- mac_soft_ring.o mac_stat.o mac_util.o
+ mac_protect.o mac_soft_ring.o mac_stat.o mac_util.o
MAC_6TO4_OBJS += mac_6to4.o
diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c
index 03ddb6542f..ecf8e27afd 100644
--- a/usr/src/uts/common/io/dld/dld_proto.c
+++ b/usr/src/uts/common/io/dld/dld_proto.c
@@ -913,6 +913,17 @@ proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
goto failed2;
}
+ /*
+ * If mac-nospoof is enabled and the link is owned by a
+ * non-global zone, changing the mac address is not allowed.
+ */
+ if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
+ mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
+ dls_active_clear(dsp, B_FALSE);
+ err = EACCES;
+ goto failed2;
+ }
+
err = mac_unicast_primary_set(dsp->ds_mh,
mp->b_rptr + dlp->dl_addr_offset);
if (err != 0) {
diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c
index 50443b2a06..75845f3df0 100644
--- a/usr/src/uts/common/io/dld/dld_str.c
+++ b/usr/src/uts/common/io/dld/dld_str.c
@@ -934,7 +934,7 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
size += MBLKL(bp);
}
- if (dls_link_header_info(dsp->ds_dlp, mp, &mhi) != 0)
+ if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
goto discard;
mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
@@ -1450,7 +1450,7 @@ str_unitdata_ind(dld_str_t *dsp, mblk_t *mp, boolean_t strip_vlan)
/*
* Get the packet header information.
*/
- if (dls_link_header_info(dsp->ds_dlp, mp, &mhi) != 0)
+ if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
return (NULL);
/*
diff --git a/usr/src/uts/common/io/dls/dls_link.c b/usr/src/uts/common/io/dls/dls_link.c
index 41bd104c31..ed2746954f 100644
--- a/usr/src/uts/common/io/dls/dls_link.c
+++ b/usr/src/uts/common/io/dls/dls_link.c
@@ -100,17 +100,17 @@ i_dls_link_destructor(void *buf, void *arg)
* - Strip the padding and skip over the header. Note that because some
* DLS consumers only check the db_ref count of the first mblk, we
* pullup the message into a single mblk. Because the original message
- * is freed as the result of message pulling up, dls_link_header_info()
+ * is freed as the result of message pulling up, mac_vlan_header_info()
* is called again to update the mhi_saddr and mhi_daddr pointers in the
- * mhip. Further, the dls_link_header_info() function ensures that the
+ * mhip. Further, the mac_vlan_header_info() function ensures that the
* size of the pulled message is greater than the MAC header size,
* therefore we can directly advance b_rptr to point at the payload.
*
* We choose to use a macro for performance reasons.
*/
-#define DLS_PREPARE_PKT(dlp, mp, mhip, err) { \
+#define DLS_PREPARE_PKT(mh, mp, mhip, err) { \
mblk_t *nextp = (mp)->b_next; \
- if (((err) = dls_link_header_info((dlp), (mp), (mhip))) == 0) { \
+ if (((err) = mac_vlan_header_info((mh), (mp), (mhip))) == 0) { \
DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \
if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \
mblk_t *newmp; \
@@ -120,7 +120,7 @@ i_dls_link_destructor(void *buf, void *arg)
(mp)->b_next = NULL; \
freemsg((mp)); \
(mp) = newmp; \
- VERIFY(dls_link_header_info((dlp), \
+ VERIFY(mac_vlan_header_info((mh), \
(mp), (mhip)) == 0); \
(mp)->b_next = nextp; \
(mp)->b_rptr += (mhip)->mhi_hdrsize; \
@@ -160,7 +160,7 @@ i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, const mac_header_info_t *mhip,
uint16_t cvid, cpri;
int err;
- DLS_PREPARE_PKT(dlp, mp, &cmhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &cmhi, err);
if (err != 0)
break;
@@ -361,7 +361,7 @@ i_dls_link_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
*/
accepted = B_FALSE;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0) {
atomic_add_32(&(dlp->dl_unknowns), 1);
nextp = mp->b_next;
@@ -510,7 +510,7 @@ dls_rx_vlan_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
void *ds_rx_arg;
int err;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0)
goto drop;
@@ -555,7 +555,7 @@ dls_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
dls_head_t *dhp;
mod_hash_key_t key;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0)
goto drop;
@@ -1035,70 +1035,3 @@ dls_link_remove(dls_link_t *dlp, dld_str_t *dsp)
mutex_exit(&dhp->dh_lock);
}
}
-
-int
-dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip)
-{
- boolean_t is_ethernet = (dlp->dl_mip->mi_media == DL_ETHER);
- uint16_t pvid = mac_get_pvid(dlp->dl_mh);
- int err = 0;
-
- /*
- * Packets should always be at least 16 bit aligned.
- */
- ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
-
- if ((err = mac_header_info(dlp->dl_mh, mp, mhip)) != 0)
- return (err);
-
- /*
- * If this is a VLAN-tagged Ethernet packet, then the SAP in the
- * mac_header_info_t as returned by mac_header_info() is
- * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
- */
- mhip->mhi_ispvid = B_FALSE;
- if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
- struct ether_vlan_header *evhp;
- uint16_t sap;
- mblk_t *tmp = NULL;
- size_t size;
-
- size = sizeof (struct ether_vlan_header);
- if (MBLKL(mp) < size) {
- /*
- * Pullup the message in order to get the MAC header
- * infomation. Note that this is a read-only function,
- * we keep the input packet intact.
- */
- if ((tmp = msgpullup(mp, size)) == NULL)
- return (EINVAL);
-
- mp = tmp;
- }
- evhp = (struct ether_vlan_header *)mp->b_rptr;
- sap = ntohs(evhp->ether_type);
- (void) mac_sap_verify(dlp->dl_mh, sap, &mhip->mhi_bindsap);
- mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
- mhip->mhi_tci = ntohs(evhp->ether_tci);
- mhip->mhi_istagged = B_TRUE;
- freemsg(tmp);
-
- /*
- * If this port has a non-zero PVID, then we have to lie to the
- * caller about the VLAN ID. It's always zero on receive for
- * that VLAN.
- */
- if (pvid != VLAN_ID_NONE && VLAN_ID(mhip->mhi_tci) == pvid) {
- mhip->mhi_tci &= ~(VLAN_ID_MASK << VLAN_ID_SHIFT);
- mhip->mhi_ispvid = B_TRUE;
- }
-
- if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
- return (EINVAL);
- } else {
- mhip->mhi_istagged = B_FALSE;
- mhip->mhi_tci = 0;
- }
-
- return (0);
-}
diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c
index e55f079ba4..bb9f2ea62a 100644
--- a/usr/src/uts/common/io/mac/mac.c
+++ b/usr/src/uts/common/io/mac/mac.c
@@ -2729,6 +2729,7 @@ mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
switch (macprop->mp_id) {
case MAC_PROP_MAXBW:
case MAC_PROP_PRIO:
+ case MAC_PROP_PROTECT:
case MAC_PROP_BIND_CPU: {
mac_resource_props_t mrp;
@@ -2808,6 +2809,7 @@ mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize,
switch (macprop->mp_id) {
case MAC_PROP_MAXBW:
case MAC_PROP_PRIO:
+ case MAC_PROP_PROTECT:
case MAC_PROP_BIND_CPU: {
mac_resource_props_t mrp;
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c
index f67b112cc2..0d1669b40e 100644
--- a/usr/src/uts/common/io/mac/mac_client.c
+++ b/usr/src/uts/common/io/mac/mac_client.c
@@ -2791,7 +2791,7 @@ mac_tx_cookie_t
mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
uint16_t flag, mblk_t **ret_mp)
{
- mac_tx_cookie_t cookie;
+ mac_tx_cookie_t cookie = NULL;
int error;
mac_tx_percpu_t *mytx;
mac_soft_ring_set_t *srs;
@@ -2812,6 +2812,15 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
}
}
+ /*
+ * If mac protection is enabled, only the permissible packets will be
+ * returned by mac_protect_check().
+ */
+ if ((mcip->mci_flent->
+ fe_resource_props.mrp_mask & MRP_PROTECT) != 0 &&
+ (mp_chain = mac_protect_check(mch, mp_chain)) == NULL)
+ goto done;
+
if (mcip->mci_subflow_tab != NULL &&
mcip->mci_subflow_tab->ft_flow_count > 0 &&
mac_flow_lookup(mcip->mci_subflow_tab, mp_chain,
@@ -2836,11 +2845,10 @@ mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
* of the mac datapath is required to remove this limitation.
*/
if (srs == NULL) {
- if (!(flag & MAC_TX_NO_HOLD))
- MAC_TX_RELE(mcip, mytx);
freemsgchain(mp_chain);
- return (NULL);
+ goto done;
}
+
srs_tx = &srs->srs_tx;
if (srs_tx->st_mode == SRS_TX_DEFAULT &&
(srs->srs_state & SRS_ENQUEUED) == 0 &&
@@ -3225,15 +3233,20 @@ mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp)
if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) {
err = mac_resource_ctl_set(mch, mrp);
- if (err != 0) {
- i_mac_perim_exit(mip);
- return (err);
- }
+ if (err != 0)
+ goto done;
}
- if (mrp->mrp_mask & MRP_CPUS)
+ if (mrp->mrp_mask & MRP_CPUS) {
err = mac_cpu_set(mch, mrp);
+ if (err != 0)
+ goto done;
+ }
+
+ if (mrp->mrp_mask & MRP_PROTECT)
+ err = mac_protect_set(mch, mrp);
+done:
i_mac_perim_exit(mip);
return (err);
}
@@ -3558,6 +3571,62 @@ mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
mhip));
}
+int
+mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER);
+ int err = 0;
+
+ /*
+ * Packets should always be at least 16 bit aligned.
+ */
+ ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
+
+ if ((err = mac_header_info(mh, mp, mhip)) != 0)
+ return (err);
+
+ /*
+ * If this is a VLAN-tagged Ethernet packet, then the SAP in the
+ * mac_header_info_t as returned by mac_header_info() is
+ * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
+ */
+ if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
+ struct ether_vlan_header *evhp;
+ uint16_t sap;
+ mblk_t *tmp = NULL;
+ size_t size;
+
+ size = sizeof (struct ether_vlan_header);
+ if (MBLKL(mp) < size) {
+ /*
+ * Pullup the message in order to get the MAC header
+ * infomation. Note that this is a read-only function,
+ * we keep the input packet intact.
+ */
+ if ((tmp = msgpullup(mp, size)) == NULL)
+ return (EINVAL);
+
+ mp = tmp;
+ }
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ sap = ntohs(evhp->ether_type);
+ (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap);
+ mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
+ mhip->mhi_tci = ntohs(evhp->ether_tci);
+ mhip->mhi_istagged = B_TRUE;
+ freemsg(tmp);
+
+ if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
+ return (EINVAL);
+ } else {
+ mhip->mhi_istagged = B_FALSE;
+ mhip->mhi_tci = 0;
+ }
+
+ return (0);
+}
+
mblk_t *
mac_header_cook(mac_handle_t mh, mblk_t *mp)
{
@@ -3648,6 +3717,9 @@ mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp,
}
if (nmrp->mrp_mask & MRP_CPUS)
MAC_COPY_CPUS(nmrp, cmrp);
+
+ if (nmrp->mrp_mask & MRP_PROTECT)
+ mac_protect_update(nmrp, cmrp);
}
}
@@ -4149,6 +4221,12 @@ mac_validate_props(mac_resource_props_t *mrp)
if (fanout < 0 || fanout > MCM_CPUS)
return (EINVAL);
}
+
+ if (mrp->mrp_mask & MRP_PROTECT) {
+ int err = mac_protect_validate(mrp);
+ if (err != 0)
+ return (err);
+ }
return (0);
}
diff --git a/usr/src/uts/common/io/mac/mac_flow.c b/usr/src/uts/common/io/mac/mac_flow.c
index b3ed893bfb..8196b73bc0 100644
--- a/usr/src/uts/common/io/mac/mac_flow.c
+++ b/usr/src/uts/common/io/mac/mac_flow.c
@@ -2354,7 +2354,10 @@ flow_transport_match_fe(flow_tab_t *ft, flow_entry_t *f1, flow_entry_t *f2)
if ((fd1->fd_mask & FLOW_ULP_PORT_LOCAL) != 0)
return (fd1->fd_local_port == fd2->fd_local_port);
- return (fd1->fd_remote_port == fd2->fd_remote_port);
+ if ((fd1->fd_mask & FLOW_ULP_PORT_REMOTE) != 0)
+ return (fd1->fd_remote_port == fd2->fd_remote_port);
+
+ return (B_TRUE);
}
static flow_ops_t flow_l2_ops = {
@@ -2398,7 +2401,8 @@ static flow_tab_info_t flow_tab_info_list[] = {
{&flow_ip_ops, FLOW_IP_VERSION | FLOW_IP_REMOTE, 2},
{&flow_ip_ops, FLOW_IP_DSFIELD, 1},
{&flow_ip_proto_ops, FLOW_IP_PROTOCOL, 256},
- {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_LOCAL, 1024}
+ {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_LOCAL, 1024},
+ {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_REMOTE, 1024}
};
#define FLOW_MAX_TAB_INFO \
diff --git a/usr/src/uts/common/io/mac/mac_protect.c b/usr/src/uts/common/io/mac/mac_protect.c
new file mode 100644
index 0000000000..8bd527c8d5
--- /dev/null
+++ b/usr/src/uts/common/io/mac/mac_protect.c
@@ -0,0 +1,340 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+#include <sys/mac.h>
+#include <sys/mac_impl.h>
+#include <sys/mac_client_impl.h>
+#include <sys/mac_client_priv.h>
+#include <sys/ethernet.h>
+#include <sys/vlan.h>
+#include <sys/dlpi.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/arp.h>
+
+/*
+ * Check if ipaddr is in the 'allowed-ips' list.
+ */
+static boolean_t
+ipnospoof_check_ips(mac_protect_t *protect, ipaddr_t ipaddr)
+{
+ uint_t i;
+
+ /*
+ * unspecified addresses are harmless and are used by ARP,DHCP..etc.
+ */
+ if (ipaddr == INADDR_ANY)
+ return (B_TRUE);
+
+ for (i = 0; i < protect->mp_ipaddrcnt; i++) {
+ if (protect->mp_ipaddrs[i] == ipaddr)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Enforce ip-nospoof protection. Only IPv4 is supported for now.
+ */
+static int
+ipnospoof_check(mac_client_impl_t *mcip, mac_protect_t *protect,
+ mblk_t *mp, mac_header_info_t *mhip)
+{
+ uint32_t sap = mhip->mhi_bindsap;
+ uchar_t *start = mp->b_rptr + mhip->mhi_hdrsize;
+ int err = EINVAL;
+
+ /*
+ * This handles the case where the mac header is not in
+ * the same mblk as the IP header.
+ */
+ if (start == mp->b_wptr) {
+ mp = mp->b_cont;
+
+ /*
+ * IP header missing. Let the packet through.
+ */
+ if (mp == NULL)
+ return (0);
+
+ start = mp->b_rptr;
+ }
+
+ switch (sap) {
+ case ETHERTYPE_IP: {
+ ipha_t *ipha = (ipha_t *)start;
+
+ if (start + sizeof (ipha_t) > mp->b_wptr || !OK_32PTR(start))
+ goto fail;
+
+ if (!ipnospoof_check_ips(protect, ipha->ipha_src))
+ goto fail;
+
+ break;
+ }
+ case ETHERTYPE_ARP: {
+ arh_t *arh = (arh_t *)start;
+ uint32_t maclen, hlen, plen, arplen;
+ ipaddr_t spaddr;
+ uchar_t *shaddr;
+
+ if (start + sizeof (arh_t) > mp->b_wptr)
+ goto fail;
+
+ maclen = mcip->mci_mip->mi_info.mi_addr_length;
+ hlen = arh->arh_hlen;
+ plen = arh->arh_plen;
+ if ((hlen != 0 && hlen != maclen) ||
+ plen != sizeof (ipaddr_t))
+ goto fail;
+
+ arplen = sizeof (arh_t) + 2 * hlen + 2 * plen;
+ if (start + arplen > mp->b_wptr)
+ goto fail;
+
+ shaddr = start + sizeof (arh_t);
+ if (hlen != 0 &&
+ bcmp(mcip->mci_unicast->ma_addr, shaddr, maclen) != 0)
+ goto fail;
+
+ bcopy(shaddr + hlen, &spaddr, sizeof (spaddr));
+ if (!ipnospoof_check_ips(protect, spaddr))
+ goto fail;
+ break;
+ }
+ default:
+ break;
+ }
+ return (0);
+
+fail:
+ /* increment ipnospoof stat here */
+ return (err);
+}
+
+/*
+ * Enforce link protection on one packet.
+ */
+static int
+mac_protect_check_one(mac_client_impl_t *mcip, mblk_t *mp)
+{
+ mac_impl_t *mip = mcip->mci_mip;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
+ mac_protect_t *protect;
+ mac_header_info_t mhi;
+ uint32_t types;
+ int err;
+
+ ASSERT(mp->b_next == NULL);
+ ASSERT(mrp != NULL);
+
+ err = mac_vlan_header_info((mac_handle_t)mip, mp, &mhi);
+ if (err != 0) {
+ DTRACE_PROBE2(invalid__header, mac_client_impl_t *, mcip,
+ mblk_t *, mp);
+ return (err);
+ }
+
+ protect = &mrp->mrp_protect;
+ types = protect->mp_types;
+
+ if ((types & MPT_MACNOSPOOF) != 0) {
+ if (mhi.mhi_saddr != NULL &&
+ bcmp(mcip->mci_unicast->ma_addr, mhi.mhi_saddr,
+ mip->mi_info.mi_addr_length) != 0) {
+ DTRACE_PROBE2(mac__nospoof__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+ }
+
+ if ((types & MPT_RESTRICTED) != 0) {
+ uint32_t vid = VLAN_ID(mhi.mhi_tci);
+ uint32_t sap = mhi.mhi_bindsap;
+
+ /*
+ * ETHERTYPE_VLAN packets are allowed through, provided that
+ * the vid is not spoofed.
+ */
+ if (vid != 0 && !mac_client_check_flow_vid(mcip, vid)) {
+ DTRACE_PROBE2(restricted__vid__invalid,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+
+ if (sap != ETHERTYPE_IP && sap != ETHERTYPE_IPV6 &&
+ sap != ETHERTYPE_ARP) {
+ DTRACE_PROBE2(restricted__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+ }
+
+ if ((types & MPT_IPNOSPOOF) != 0) {
+ if ((err = ipnospoof_check(mcip, protect,
+ mp, &mhi)) != 0) {
+ DTRACE_PROBE2(ip__nospoof__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (err);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Enforce link protection on a packet chain.
+ * Packets that pass the checks are returned back to the caller.
+ */
+mblk_t *
+mac_protect_check(mac_client_handle_t mch, mblk_t *mp)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mblk_t *ret_mp = NULL, **tailp = &ret_mp, *next;
+
+ /*
+ * Skip checks if we are part of an aggr.
+ */
+ if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0)
+ return (mp);
+
+ for (; mp != NULL; mp = next) {
+ next = mp->b_next;
+ mp->b_next = NULL;
+
+ if (mac_protect_check_one(mcip, mp) == 0) {
+ *tailp = mp;
+ tailp = &mp->b_next;
+ } else {
+ freemsg(mp);
+ }
+ }
+ return (ret_mp);
+}
+
+/*
+ * Check if a particular protection type is enabled.
+ */
+boolean_t
+mac_protect_enabled(mac_client_handle_t mch, uint32_t type)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
+
+ ASSERT(mrp != NULL);
+ return ((mrp->mrp_protect.mp_types & type) != 0);
+}
+
+/*
+ * Sanity-checks parameters given by userland.
+ */
+int
+mac_protect_validate(mac_resource_props_t *mrp)
+{
+ mac_protect_t *p = &mrp->mrp_protect;
+
+ /* check for invalid types */
+ if (p->mp_types != MPT_RESET && (p->mp_types & ~MPT_ALL) != 0)
+ return (EINVAL);
+
+ if (p->mp_ipaddrcnt != MPT_RESET) {
+ uint_t i, j;
+
+ if (p->mp_ipaddrcnt > MPT_MAXIPADDR)
+ return (EINVAL);
+
+ for (i = 0; i < p->mp_ipaddrcnt; i++) {
+ /*
+ * The unspecified address is implicitly allowed
+ * so there's no need to add it to the list.
+ */
+ if (p->mp_ipaddrs[i] == INADDR_ANY)
+ return (EINVAL);
+
+ for (j = 0; j < p->mp_ipaddrcnt; j++) {
+ /* found a duplicate */
+ if (i != j &&
+ p->mp_ipaddrs[i] == p->mp_ipaddrs[j])
+ return (EINVAL);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * Enable/disable link protection.
+ */
+int
+mac_protect_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_impl_t *mip = mcip->mci_mip;
+ uint_t media = mip->mi_info.mi_nativemedia;
+ int err;
+
+ ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
+
+ /* tunnels are not supported */
+ if (media == DL_IPV4 || media == DL_IPV6 || media == DL_6TO4)
+ return (ENOTSUP);
+
+ if ((err = mac_protect_validate(mrp)) != 0)
+ return (err);
+
+ mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
+ return (0);
+}
+
+void
+mac_protect_update(mac_resource_props_t *new, mac_resource_props_t *curr)
+{
+ mac_protect_t *np = &new->mrp_protect;
+ mac_protect_t *cp = &curr->mrp_protect;
+ uint32_t types = np->mp_types;
+
+ if (types == MPT_RESET) {
+ cp->mp_types = 0;
+ curr->mrp_mask &= ~MRP_PROTECT;
+ } else {
+ if (types != 0) {
+ cp->mp_types = types;
+ curr->mrp_mask |= MRP_PROTECT;
+ }
+ }
+
+ if (np->mp_ipaddrcnt != 0) {
+ if (np->mp_ipaddrcnt < MPT_MAXIPADDR) {
+ bcopy(np->mp_ipaddrs, cp->mp_ipaddrs,
+ sizeof (cp->mp_ipaddrs));
+ cp->mp_ipaddrcnt = np->mp_ipaddrcnt;
+ } else if (np->mp_ipaddrcnt == MPT_RESET) {
+ bzero(cp->mp_ipaddrs, sizeof (cp->mp_ipaddrs));
+ cp->mp_ipaddrcnt = 0;
+ }
+ }
+}
diff --git a/usr/src/uts/common/sys/dls_impl.h b/usr/src/uts/common/sys/dls_impl.h
index 19d885e821..8bcc048dd2 100644
--- a/usr/src/uts/common/sys/dls_impl.h
+++ b/usr/src/uts/common/sys/dls_impl.h
@@ -84,8 +84,6 @@ extern void dls_link_rele(dls_link_t *);
extern int dls_link_rele_by_name(const char *);
extern void dls_link_add(dls_link_t *, uint32_t, dld_str_t *);
extern void dls_link_remove(dls_link_t *, dld_str_t *);
-extern int dls_link_header_info(dls_link_t *, mblk_t *,
- mac_header_info_t *);
extern int dls_link_getzid(const char *, zoneid_t *);
extern int dls_link_setzid(const char *, zoneid_t);
extern dev_info_t *dls_link_devinfo(dev_t);
diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h
index 632a6065b5..fc0ea57e8c 100644
--- a/usr/src/uts/common/sys/mac.h
+++ b/usr/src/uts/common/sys/mac.h
@@ -211,6 +211,7 @@ typedef enum {
MAC_PROP_PVID,
MAC_PROP_LLIMIT,
MAC_PROP_LDECAY,
+ MAC_PROP_PROTECT,
MAC_PROP_PRIVATE = -1
} mac_prop_id_t;
diff --git a/usr/src/uts/common/sys/mac_client_priv.h b/usr/src/uts/common/sys/mac_client_priv.h
index 6174dd1a72..6689d20f34 100644
--- a/usr/src/uts/common/sys/mac_client_priv.h
+++ b/usr/src/uts/common/sys/mac_client_priv.h
@@ -68,6 +68,7 @@ extern boolean_t mac_sap_verify(mac_handle_t, uint32_t, uint32_t *);
extern mblk_t *mac_header(mac_handle_t, const uint8_t *, uint32_t, mblk_t *,
size_t);
extern int mac_header_info(mac_handle_t, mblk_t *, mac_header_info_t *);
+extern int mac_vlan_header_info(mac_handle_t, mblk_t *, mac_header_info_t *);
extern mblk_t *mac_header_cook(mac_handle_t, mblk_t *);
extern mblk_t *mac_header_uncook(mac_handle_t, mblk_t *);
diff --git a/usr/src/uts/common/sys/mac_flow.h b/usr/src/uts/common/sys/mac_flow.h
index 72658d619c..08c7a211a3 100644
--- a/usr/src/uts/common/sys/mac_flow.h
+++ b/usr/src/uts/common/sys/mac_flow.h
@@ -113,7 +113,7 @@ typedef struct mac_cpus_props_s {
* in retargetting the interrupt assignment.
*/
int32_t mc_intr_cpu;
- mac_cpu_mode_t mc_fanout_mode; /* fanout mode */
+ mac_cpu_mode_t mc_fanout_mode; /* fanout mode */
} mac_cpus_t;
/* Priority values */
@@ -124,6 +124,21 @@ typedef enum {
MPL_RESET
} mac_priority_level_t;
+/* Protection types */
+#define MPT_MACNOSPOOF 0x00000001
+#define MPT_IPNOSPOOF 0x00000002
+#define MPT_RESTRICTED 0x00000004
+#define MPT_ALL (MPT_MACNOSPOOF|MPT_IPNOSPOOF|MPT_RESTRICTED)
+#define MPT_RESET 0xffffffff
+#define MPT_MAXIPADDR 32
+
+typedef struct mac_protect_s {
+ uint32_t mp_types;
+ uint32_t mp_ipaddrcnt;
+ ipaddr_t mp_ipaddrs[MPT_MAXIPADDR];
+} mac_protect_t;
+
+
/* The default priority for links */
#define MPL_LINK_DEFAULT MPL_HIGH
@@ -134,6 +149,7 @@ typedef enum {
#define MRP_CPUS 0x00000002 /* CPU/fanout set */
#define MRP_CPUS_USERSPEC 0x00000004 /* CPU/fanout from user */
#define MRP_PRIORITY 0x00000008 /* Priority set */
+#define MRP_PROTECT 0x00000010 /* Protection set */
#define MRP_THROTTLE MRP_MAXBW
@@ -157,6 +173,7 @@ typedef struct mac_resource_props_s {
uint64_t mrp_maxbw; /* bandwidth limit in bps */
mac_priority_level_t mrp_priority; /* relative flow priority */
mac_cpus_t mrp_cpus;
+ mac_protect_t mrp_protect;
} mac_resource_props_t;
#define mrp_ncpus mrp_cpus.mc_ncpus
diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h
index 0b7d85314b..00ea926275 100644
--- a/usr/src/uts/common/sys/mac_impl.h
+++ b/usr/src/uts/common/sys/mac_impl.h
@@ -751,6 +751,12 @@ extern void i_mac_group_rem_ring(mac_group_t *, mac_ring_t *, boolean_t);
extern void mac_poll_state_change(mac_handle_t, boolean_t);
+extern mblk_t *mac_protect_check(mac_client_handle_t, mblk_t *);
+extern int mac_protect_set(mac_client_handle_t, mac_resource_props_t *);
+extern boolean_t mac_protect_enabled(mac_client_handle_t, uint32_t);
+extern int mac_protect_validate(mac_resource_props_t *);
+extern void mac_protect_update(mac_resource_props_t *, mac_resource_props_t *);
+
/* Global callbacks into the bridging module (when loaded) */
extern mac_bridge_tx_t mac_bridge_tx_cb;
extern mac_bridge_rx_t mac_bridge_rx_cb;