changeset 10734:0622a203d039

PSARC/2009/436 Anti-spoofing Link Protection PSARC/2009/488 flowadm(1m) remote_port flow attribute 6884729 Integrate Link Protection Phase I 6882391 Offer flowadm -a remote_port
author Eric Cheng
date Wed, 07 Oct 2009 14:39:04 -0700
parents b95259752377
children 336fb268ea6f
files usr/src/cmd/dladm/dladm.c usr/src/cmd/flowadm/flowadm.c usr/src/cmd/flowadm/flowadm.xcl usr/src/lib/libdladm/common/flowattr.c usr/src/lib/libdladm/common/flowprop.c usr/src/lib/libdladm/common/libdladm.c usr/src/lib/libdladm/common/libdladm.h usr/src/lib/libdladm/common/libdladm_impl.h usr/src/lib/libdladm/common/libdlflow.c usr/src/lib/libdladm/common/linkprop.c usr/src/lib/libdladm/common/mapfile-vers usr/src/lib/libinetutil/common/ofmt.c usr/src/lib/libinetutil/common/ofmt.h usr/src/uts/common/Makefile.files usr/src/uts/common/io/dld/dld_proto.c usr/src/uts/common/io/dld/dld_str.c usr/src/uts/common/io/dls/dls_link.c usr/src/uts/common/io/mac/mac.c usr/src/uts/common/io/mac/mac_client.c usr/src/uts/common/io/mac/mac_flow.c usr/src/uts/common/io/mac/mac_protect.c usr/src/uts/common/sys/dls_impl.h usr/src/uts/common/sys/mac.h usr/src/uts/common/sys/mac_client_priv.h usr/src/uts/common/sys/mac_flow.h usr/src/uts/common/sys/mac_impl.h
diffstat 26 files changed, 966 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/dladm/dladm.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/dladm/dladm.c	Wed Oct 07 14:39:04 2009 -0700
@@ -891,7 +891,7 @@
 { "PERM",	5,	LINKPROP_PERM,		print_linkprop_cb},
 { "VALUE",	15,	LINKPROP_VALUE,		print_linkprop_cb},
 { "DEFAULT",	15,	LINKPROP_DEFAULT,	print_linkprop_cb},
-{ "POSSIBLE",	21,	LINKPROP_POSSIBLE,	print_linkprop_cb},
+{ "POSSIBLE",	20,	LINKPROP_POSSIBLE,	print_linkprop_cb},
 { NULL,		0,	0,			NULL}}
 ;
 
@@ -6286,6 +6286,7 @@
 
 	statep->ls_status = DLADM_STATUS_OK;
 
+	buf[0] = '\0';
 	ptr = buf;
 	lim = buf + DLADM_STRSIZE;
 	for (i = 0; i < valcnt; i++) {
@@ -6493,6 +6494,9 @@
 
 	if (state.ls_parsable)
 		ofmtflags |= OFMT_PARSABLE;
+	else
+		ofmtflags |= OFMT_WRAP;
+
 	oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
 	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
 	state.ls_ofmt = ofmt;
--- a/usr/src/cmd/flowadm/flowadm.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/flowadm/flowadm.c	Wed Oct 07 14:39:04 2009 -0700
@@ -163,7 +163,8 @@
 	char flow_link[MAXLINKNAMELEN];
 	char flow_ipaddr[INET6_ADDRSTRLEN+4];
 	char flow_proto[PROTO_MAXSTR_LEN];
-	char flow_port[PORT_MAXSTR_LEN];
+	char flow_lport[PORT_MAXSTR_LEN];
+	char flow_rport[PORT_MAXSTR_LEN];
 	char flow_dsfield[DSFIELD_MAXSTR_LEN];
 } flow_fields_buf_t;
 
@@ -173,12 +174,14 @@
 	offsetof(flow_fields_buf_t, flow_name), print_default_cb},
 {  "LINK",	12,
 	offsetof(flow_fields_buf_t, flow_link), print_default_cb},
-{  "IPADDR",	31,
+{  "IPADDR",	25,
 	offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
 {  "PROTO",	7,
 	offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
-{  "PORT",	8,
-	offsetof(flow_fields_buf_t, flow_port), print_default_cb},
+{  "LPORT",	8,
+	offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
+{  "RPORT",	8,
+	offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
 {  "DSFLD",	10,
 	offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
 NULL_OFMT}
@@ -344,7 +347,8 @@
 static dladm_handle_t handle = NULL;
 
 static const char *attr_table[] =
-	{"local_ip", "remote_ip", "transport", "local_port", "dsfield"};
+	{"local_ip", "remote_ip", "transport", "local_port", "remote_port",
+	    "dsfield"};
 
 #define	NATTR	(sizeof (attr_table)/sizeof (char *))
 
@@ -909,8 +913,14 @@
 	    sizeof (fbuf->flow_ipaddr));
 	(void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
 	    sizeof (fbuf->flow_proto));
-	(void) dladm_flow_attr_port2str(attr, fbuf->flow_port,
-	    sizeof (fbuf->flow_port));
+	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) {
+		(void) dladm_flow_attr_port2str(attr, fbuf->flow_lport,
+		    sizeof (fbuf->flow_lport));
+	}
+	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) {
+		(void) dladm_flow_attr_port2str(attr, fbuf->flow_rport,
+		    sizeof (fbuf->flow_rport));
+	}
 	(void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
 	    sizeof (fbuf->flow_dsfield));
 
--- a/usr/src/cmd/flowadm/flowadm.xcl	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/flowadm/flowadm.xcl	Wed Oct 07 14:39:04 2009 -0700
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
@@ -92,6 +92,7 @@
 msgid  "property"
 msgid  "psSi:l:o:"
 msgid  "remote_ip"
+msgid  "remote_port"
 msgid  "remove-flow"
 msgid  "reset"
 msgid  "reset-flowprop"
--- a/usr/src/lib/libdladm/common/flowattr.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/flowattr.c	Wed Oct 07 14:39:04 2009 -0700
@@ -50,15 +50,17 @@
 static fad_checkf_t do_check_remote_ip;
 static fad_checkf_t do_check_protocol;
 static fad_checkf_t do_check_local_port;
+static fad_checkf_t do_check_remote_port;
 
 static dladm_status_t do_check_port(char *, boolean_t, flow_desc_t *);
 
 static fattr_desc_t	attr_table[] = {
-	{ "local_ip",	do_check_local_ip },
-	{ "remote_ip",	do_check_remote_ip },
-	{ "transport",	do_check_protocol },
-	{ "local_port",	do_check_local_port },
-	{ "dsfield",	do_check_dsfield },
+	{ "local_ip",		do_check_local_ip },
+	{ "remote_ip",		do_check_remote_ip },
+	{ "transport",		do_check_protocol },
+	{ "local_port",		do_check_local_port },
+	{ "remote_port",	do_check_remote_port },
+	{ "dsfield",		do_check_dsfield },
 };
 
 #define	DLADM_MAX_FLOWATTRS	(sizeof (attr_table) / sizeof (fattr_desc_t))
@@ -162,19 +164,26 @@
 }
 
 dladm_status_t
+do_check_remote_port(char *attr_val, flow_desc_t *fdesc)
+{
+	return (do_check_port(attr_val, B_FALSE, fdesc));
+}
+
+dladm_status_t
 do_check_port(char *attr_val, boolean_t local, flow_desc_t *fdesc)
 {
 	char	*endp = NULL;
 	long	val;
 
+	val = strtol(attr_val, &endp, 10);
+	if (val < 1 || val > MAX_PORT || *endp != '\0')
+		return (DLADM_STATUS_INVALID_PORT);
 	if (local) {
 		fdesc->fd_mask |= FLOW_ULP_PORT_LOCAL;
-		val = strtol(attr_val, &endp, 10);
-		if (val < 1 || val > MAX_PORT)
-			return (DLADM_STATUS_INVALID_PORT);
 		fdesc->fd_local_port = htons((uint16_t)val);
 	} else {
-		return (DLADM_STATUS_BADVAL);
+		fdesc->fd_mask |= FLOW_ULP_PORT_REMOTE;
+		fdesc->fd_remote_port = htons((uint16_t)val);
 	}
 
 	return (DLADM_STATUS_OK);
@@ -391,6 +400,9 @@
 	if (fdesc.fd_mask & FLOW_ULP_PORT_LOCAL) {
 		(void) snprintf(buf, buf_len, "%d",
 		    ntohs(fdesc.fd_local_port));
+	} else if (fdesc.fd_mask & FLOW_ULP_PORT_REMOTE) {
+		(void) snprintf(buf, buf_len, "%d",
+		    ntohs(fdesc.fd_remote_port));
 	} else {
 		buf[0] = '\0';
 	}
--- a/usr/src/lib/libdladm/common/flowprop.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/flowprop.c	Wed Oct 07 14:39:04 2009 -0700
@@ -493,7 +493,7 @@
  */
 static dladm_status_t
 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
-    const char *name, void *val)
+    const char *name, void *arg)
 {
 	dladm_status_t		status;
 	dladm_arg_info_t	*aip = NULL;
@@ -543,8 +543,8 @@
 
 			/* Extract kernel structure */
 			if (rpp->rp_extract != NULL) {
-				status = rpp->rp_extract(vdp, val,
-				    aip->ai_count);
+				status = rpp->rp_extract(vdp,
+				    aip->ai_count, arg);
 			} else {
 				status = DLADM_STATUS_BADARG;
 			}
--- a/usr/src/lib/libdladm/common/libdladm.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm.c	Wed Oct 07 14:39:04 2009 -0700
@@ -30,6 +30,8 @@
 #include <strings.h>
 #include <dirent.h>
 #include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/dld.h>
@@ -80,6 +82,18 @@
 };
 #define	MEDIATYPECOUNT	(sizeof (media_type_table) / sizeof (media_type_t))
 
+typedef struct {
+	uint32_t	lp_type;
+	char		*lp_name;
+} link_protect_t;
+
+static link_protect_t link_protect_types[] = {
+	{ MPT_MACNOSPOOF, "mac-nospoof" },
+	{ MPT_IPNOSPOOF, "ip-nospoof" },
+	{ MPT_RESTRICTED, "restricted" }
+};
+#define	LPTYPES	(sizeof (link_protect_types) / sizeof (link_protect_t))
+
 dladm_status_t
 dladm_open(dladm_handle_t *handle)
 {
@@ -836,6 +850,82 @@
 	return (buf);
 }
 
+/*
+ * Convert protect string to a value.
+ */
+dladm_status_t
+dladm_str2protect(char *token, uint32_t *ptype)
+{
+	link_protect_t	*lp;
+	int		i;
+
+	for (i = 0; i < LPTYPES; i++) {
+		lp = &link_protect_types[i];
+		if (strcmp(token, lp->lp_name) == 0) {
+			*ptype = lp->lp_type;
+			return (DLADM_STATUS_OK);
+		}
+	}
+	return (DLADM_STATUS_BADVAL);
+}
+
+/*
+ * Convert protect value to a string.
+ */
+const char *
+dladm_protect2str(uint32_t ptype, char *buf)
+{
+	const char	*s = "--";
+	link_protect_t	*lp;
+	int		i;
+
+	for (i = 0; i < LPTYPES; i++) {
+		lp = &link_protect_types[i];
+		if (lp->lp_type == ptype) {
+			s = lp->lp_name;
+			break;
+		}
+	}
+	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
+	return (buf);
+}
+
+/*
+ * Convert an IPv4 address to/from a string.
+ */
+const char *
+dladm_ipv4addr2str(void *addr, char *buf)
+{
+	if (inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN) == NULL)
+		buf[0] = 0;
+
+	return (buf);
+}
+
+dladm_status_t
+dladm_str2ipv4addr(char *token, void *addr)
+{
+	return (inet_pton(AF_INET, token, addr) == 1 ?
+	    DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP);
+}
+
+/*
+ * Find the set bits in a mask.
+ * This is used for expanding a bitmask into individual sub-masks
+ * which can be used for further processing.
+ */
+void
+dladm_find_setbits32(uint32_t mask, uint32_t *list, uint32_t *cnt)
+{
+	int	i, c = 0;
+
+	for (i = 0; i < 32; i++) {
+		if (((1 << i) & mask) != 0)
+			list[c++] = 1 << i;
+	}
+	*cnt = c;
+}
+
 void
 dladm_free_args(dladm_arg_list_t *list)
 {
--- a/usr/src/lib/libdladm/common/libdladm.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm.h	Wed Oct 07 14:39:04 2009 -0700
@@ -27,6 +27,7 @@
 #define	_LIBDLADM_H
 
 #include <sys/dls_mgmt.h>
+#include <sys/dld.h>
 #include <sys/dlpi.h>
 
 /*
@@ -224,6 +225,12 @@
 extern boolean_t	dladm_str2interval(char *, uint32_t *);
 extern dladm_status_t	dladm_str2bw(char *, uint64_t *);
 extern const char	*dladm_bw2str(int64_t, char *);
+extern dladm_status_t	dladm_str2pri(char *, mac_priority_level_t *);
+extern const char	*dladm_pri2str(mac_priority_level_t, char *);
+extern dladm_status_t	dladm_str2protect(char *, uint32_t *);
+extern const char	*dladm_protect2str(uint32_t, char *);
+extern dladm_status_t	dladm_str2ipv4addr(char *, void *);
+extern const char	*dladm_ipv4addr2str(void *, char *);
 
 extern dladm_status_t	dladm_parse_flow_props(char *, dladm_arg_list_t **,
 			    boolean_t);
--- a/usr/src/lib/libdladm/common/libdladm_impl.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm_impl.h	Wed Oct 07 14:39:04 2009 -0700
@@ -59,9 +59,7 @@
 			    FILE *), void *, boolean_t);
 extern dladm_status_t	i_dladm_get_state(dladm_handle_t, datalink_id_t,
 			    link_state_t *);
-
-extern const char	*dladm_pri2str(mac_priority_level_t, char *);
-extern dladm_status_t	dladm_str2pri(char *, mac_priority_level_t *);
+extern void		dladm_find_setbits32(uint32_t, uint32_t *, uint32_t *);
 extern dladm_status_t	dladm_parse_args(char *, dladm_arg_list_t **,
 			    boolean_t);
 extern void		dladm_free_args(dladm_arg_list_t *);
@@ -140,10 +138,10 @@
  * rp_extract extracts the kernel structure from the val_desc_t created
  * by the pd_check function.
  */
-typedef	dladm_status_t	rp_extractf_t(val_desc_t *propval, void *arg,
-				uint_t cnt);
+typedef	dladm_status_t	rp_extractf_t(val_desc_t *, uint_t, void *);
 extern rp_extractf_t	do_extract_maxbw, do_extract_priority,
-			do_extract_cpus;
+			do_extract_cpus, do_extract_protection,
+			do_extract_allowedips;
 
 typedef struct resource_prop_s {
 	/*
--- a/usr/src/lib/libdladm/common/libdlflow.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdlflow.c	Wed Oct 07 14:39:04 2009 -0700
@@ -72,6 +72,7 @@
 static const char *REMOTE_IP_ADDR = "remote_ip";
 static const char *TRANSPORT = "transport";
 static const char *LOCAL_PORT = "local_port";
+static const char *REMOTE_PORT = "remote_port";
 static const char *DSFIELD = "dsfield";
 
 /*
@@ -131,7 +132,6 @@
 {
 	char		*token;
 	char		*value, *name = NULL;
-	char		*endp = NULL;
 	char		*lasts = NULL;
 	dladm_status_t	status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
 
@@ -156,7 +156,7 @@
 
 		if (strcmp(name, "linkid") == 0) {
 			if ((attr->fi_linkid =
-			    (uint32_t)strtol(value, &endp, 10)) ==
+			    (uint32_t)strtol(value, NULL, 10)) ==
 			    DATALINK_INVALID_LINKID)
 				goto done;
 
@@ -164,7 +164,7 @@
 			attr->fi_resource_props.mrp_mask |=
 			    MRP_MAXBW;
 			attr->fi_resource_props.mrp_maxbw =
-			    (uint64_t)strtol(value, &endp, 0);
+			    (uint64_t)strtol(value, NULL, 0);
 
 		} else if (strcmp(name, PRIORITY) == 0) {
 			attr->fi_resource_props.mrp_mask |= MRP_PRIORITY;
@@ -194,14 +194,20 @@
 		} else if (strcmp(name, TRANSPORT) == 0) {
 			attr->fi_flow_desc.fd_mask |= FLOW_IP_PROTOCOL;
 			attr->fi_flow_desc.fd_protocol =
-			    (uint8_t)strtol(value, &endp, 0);
+			    (uint8_t)strtol(value, NULL, 0);
 
 		} else if (strcmp(name, LOCAL_PORT) == 0) {
 			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_LOCAL;
 			attr->fi_flow_desc.fd_local_port =
-			    (uint16_t)strtol(value, &endp, 10);
+			    (uint16_t)strtol(value, NULL, 10);
 			attr->fi_flow_desc.fd_local_port =
 			    htons(attr->fi_flow_desc.fd_local_port);
+		} else if (strcmp(name, REMOTE_PORT) == 0) {
+			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_REMOTE;
+			attr->fi_flow_desc.fd_remote_port =
+			    (uint16_t)strtol(value, NULL, 10);
+			attr->fi_flow_desc.fd_remote_port =
+			    htons(attr->fi_flow_desc.fd_remote_port);
 		}
 		free(name);
 		name = NULL;
@@ -303,6 +309,10 @@
 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT,
 		    ntohs(attr->fi_flow_desc.fd_local_port)));
 
+	if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE)
+		FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT,
+		    ntohs(attr->fi_flow_desc.fd_remote_port)));
+
 	FPRINTF_ERR(fprintf(fp, "\n"));
 
 	return (0);
--- a/usr/src/lib/libdladm/common/linkprop.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/linkprop.c	Wed Oct 07 14:39:04 2009 -0700
@@ -51,7 +51,6 @@
 #include <sys/param.h>
 #include <sys/debug.h>
 #include <sys/dld.h>
-#include <sys/mac_flow.h>
 #include <inttypes.h>
 #include <sys/ethernet.h>
 #include <inet/iptun.h>
@@ -139,17 +138,21 @@
 			i_dladm_cpus_get, i_dladm_priority_get,
 			i_dladm_tagmode_get, i_dladm_range_get,
 			get_stp_prop, get_bridge_forward,
-			get_bridge_pvid;
+			get_bridge_pvid,
+			/* the above need to be renamed to "do_get_xxx" */
+			do_get_protection;
 
 static pd_setf_t	do_set_zone, do_set_rate_prop,
 			do_set_powermode_prop, do_set_radio_prop,
 			i_dladm_set_public_prop, do_set_res, do_set_cpus,
-			set_stp_prop, set_bridge_forward, set_bridge_pvid;
+			set_stp_prop, set_bridge_forward, set_bridge_pvid,
+			do_set_protection;
 
 static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
 			do_check_hoplimit, do_check_encaplim,
 			i_dladm_uint32_check, do_check_maxbw, do_check_cpus,
-			do_check_priority, check_stp_prop, check_bridge_pvid;
+			do_check_priority, check_stp_prop, check_bridge_pvid,
+			do_check_allowedips, do_check_prop;
 
 static dladm_status_t	i_dladm_speed_get(dladm_handle_t, prop_desc_t *,
 			    datalink_id_t, char **, uint_t *, uint_t, uint_t *);
@@ -341,8 +344,9 @@
 
 	{ MAC_PROP_LDECAY,	sizeof (uint32_t),	"learn_decay"},
 
+	{ MAC_PROP_PROTECT,	sizeof (mac_resource_props_t),	"protection"},
+
 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
-
 };
 
 typedef struct bridge_public_prop_s {
@@ -389,6 +393,12 @@
 	{ "vlanonly",	LINK_TAGMODE_VLANONLY	}
 };
 
+static  val_desc_t	link_protect_vals[] = {
+	{ "mac-nospoof",	MPT_MACNOSPOOF	},
+	{ "ip-nospoof",		MPT_IPNOSPOOF	},
+	{ "restricted",		MPT_RESTRICTED	}
+};
+
 static val_desc_t	dladm_wlan_radio_vals[] = {
 	{ "on",		DLADM_WLAN_RADIO_ON	},
 	{ "off",	DLADM_WLAN_RADIO_OFF	}
@@ -622,6 +632,16 @@
 	    set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM,
 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
+
+	{ "protection", { "--", RESET_VAL },
+	    link_protect_vals, VALCNT(link_protect_vals),
+	    do_set_protection, NULL, do_get_protection, do_check_prop, 0,
+	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
+
+	{ "allowed-ips", { "--", 0 },
+	    NULL, 0, do_set_protection, NULL,
+	    do_get_protection, do_check_allowedips, 0,
+	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
 };
 
 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
@@ -629,7 +649,9 @@
 static resource_prop_t rsrc_prop_table[] = {
 	{"maxbw",	do_extract_maxbw},
 	{"priority",	do_extract_priority},
-	{"cpus",	do_extract_cpus}
+	{"cpus",	do_extract_cpus},
+	{"protection",	do_extract_protection},
+	{"allowed-ips",	do_extract_allowedips}
 };
 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
 	sizeof (resource_prop_t))
@@ -667,29 +689,26 @@
 #define	AP_ANCHOR	"[anchor]"
 #define	AP_DELIMITER	'.'
 
+/* ARGSUSED */
 static dladm_status_t
-do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
-    val_desc_t *vdp)
+do_check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
+    char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
 {
 	int		i, j;
-	dladm_status_t	status = DLADM_STATUS_OK;
 
 	for (j = 0; j < val_cnt; j++) {
 		for (i = 0; i < pdp->pd_noptval; i++) {
-			if (strcasecmp(*prop_val,
+			if (strcasecmp(prop_val[j],
 			    pdp->pd_optval[i].vd_name) == 0) {
 				break;
 			}
 		}
-		if (i == pdp->pd_noptval) {
-			status = DLADM_STATUS_BADVAL;
-			goto done;
-		}
-		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
+		if (i == pdp->pd_noptval)
+			return (DLADM_STATUS_BADVAL);
+
+		(void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
 	}
-
-done:
-	return (status);
+	return (DLADM_STATUS_OK);
 }
 
 static dladm_status_t
@@ -727,7 +746,8 @@
 			status = pdp->pd_check(handle, pdp, linkid, prop_val,
 			    val_cnt, vdp, media);
 		} else if (pdp->pd_optval != NULL) {
-			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
+			status = do_check_prop(handle, pdp, linkid, prop_val,
+			    val_cnt, vdp, media);
 		} else {
 			status = DLADM_STATUS_BADARG;
 		}
@@ -1523,9 +1543,9 @@
 
 /* ARGSUSED */
 dladm_status_t
-do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
 {
-	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
+	mac_resource_props_t *mrp = arg;
 
 	bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
 	mrp->mrp_mask |= MRP_MAXBW;
@@ -1728,9 +1748,9 @@
 
 /* ARGSUSED */
 dladm_status_t
-do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
 {
-	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
+	mac_resource_props_t	*mrp = arg;
 	mac_resource_props_t	*vmrp = (mac_resource_props_t *)vdp->vd_val;
 	int			i;
 
@@ -1804,9 +1824,9 @@
 
 /* ARGSUSED */
 dladm_status_t
-do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
 {
-	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
+	mac_resource_props_t *mrp = arg;
 
 	bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
 	    sizeof (mac_priority_level_t));
@@ -1817,6 +1837,157 @@
 
 /* ARGSUSED */
 static dladm_status_t
+do_set_protection(dladm_handle_t handle, prop_desc_t *pdp,
+    datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
+    uint_t flags, datalink_media_t media)
+{
+	mac_resource_props_t	mrp;
+	dladm_status_t		status = DLADM_STATUS_OK;
+	dld_ioc_macprop_t	*dip;
+
+	bzero(&mrp, sizeof (mac_resource_props_t));
+	dip = i_dladm_buf_alloc_by_name(0, linkid, "protection",
+	    flags, &status);
+
+	if (dip == NULL)
+		return (status);
+
+	if (strcmp(pdp->pd_name, "protection") == 0) {
+		status = do_extract_protection(vdp, val_cnt, &mrp);
+		if (status != DLADM_STATUS_OK)
+			goto done;
+
+	} else if (strcmp(pdp->pd_name, "allowed-ips") == 0) {
+		status = do_extract_allowedips(vdp, val_cnt, &mrp);
+		if (status != DLADM_STATUS_OK)
+			goto done;
+	} else {
+		status = DLADM_STATUS_BADARG;
+		goto done;
+	}
+
+	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
+	status = i_dladm_macprop(handle, dip, B_TRUE);
+
+done:
+	free(dip);
+	return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_get_protection(dladm_handle_t handle, prop_desc_t *pdp,
+    datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
+    datalink_media_t media, uint_t flags, uint_t *perm_flags)
+{
+	dld_ioc_macprop_t	*dip;
+	mac_resource_props_t	mrp;
+	mac_protect_t		*p;
+	dladm_status_t		status;
+	int			i;
+
+	dip = i_dladm_get_public_prop(handle, linkid, "protection", flags,
+	    &status, perm_flags);
+	if (dip == NULL)
+		return (status);
+
+	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
+	free(dip);
+
+	p = &mrp.mrp_protect;
+	if ((mrp.mrp_mask & MRP_PROTECT) != 0 &&
+	    strcmp(pdp->pd_name, "protection") == 0) {
+		uint32_t	cnt = 0, setbits[32];
+
+		dladm_find_setbits32(p->mp_types, setbits, &cnt);
+		if (cnt > *val_cnt)
+			return (DLADM_STATUS_BADVALCNT);
+
+		for (i = 0; i < cnt; i++)
+			(void) dladm_protect2str(setbits[i], prop_val[i]);
+
+		*val_cnt = cnt;
+		return (DLADM_STATUS_OK);
+	}
+
+	if (p->mp_ipaddrcnt > 0 &&
+	    strcmp(pdp->pd_name, "allowed-ips") == 0) {
+		if (p->mp_ipaddrcnt > *val_cnt)
+			return (DLADM_STATUS_BADVALCNT);
+
+		for (i = 0; i < p->mp_ipaddrcnt; i++) {
+			(void) dladm_ipv4addr2str(&p->mp_ipaddrs[i],
+			    prop_val[i]);
+		}
+		*val_cnt = p->mp_ipaddrcnt;
+		return (DLADM_STATUS_OK);
+	}
+
+	*val_cnt = 0;
+	return (DLADM_STATUS_OK);
+}
+
+dladm_status_t
+do_extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
+{
+	mac_resource_props_t	*mrp = arg;
+	uint32_t		types = 0;
+	int			i;
+
+	for (i = 0; i < cnt; i++)
+		types |= (uint32_t)vdp[i].vd_val;
+
+	mrp->mrp_protect.mp_types = types;
+	mrp->mrp_mask |= MRP_PROTECT;
+	return (DLADM_STATUS_OK);
+}
+
+dladm_status_t
+do_extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
+{
+	mac_resource_props_t	*mrp = arg;
+	mac_protect_t		*p = &mrp->mrp_protect;
+	int			i;
+
+	if (vdp->vd_val == 0) {
+		cnt = (uint_t)-1;
+	} else {
+		for (i = 0; i < cnt; i++)
+			p->mp_ipaddrs[i] = (ipaddr_t)vdp[i].vd_val;
+	}
+	p->mp_ipaddrcnt = cnt;
+	mrp->mrp_mask |= MRP_PROTECT;
+	return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
+    datalink_id_t linkid, char **prop_val, uint_t val_cnt,
+    val_desc_t *vdp, datalink_media_t media)
+{
+	dladm_status_t	status;
+	ipaddr_t	addr;
+	int		i;
+
+	if (val_cnt > MPT_MAXIPADDR)
+		return (DLADM_STATUS_BADVALCNT);
+
+	for (i = 0; i < val_cnt; i++) {
+		status = dladm_str2ipv4addr(prop_val[i], &addr);
+		if (status != DLADM_STATUS_OK)
+			return (status);
+
+		if (addr == 0)
+			return (DLADM_STATUS_BADVAL);
+
+		vdp[i].vd_val = (uintptr_t)addr;
+	}
+	return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
     char **prop_val, uint_t *val_cnt, datalink_media_t media,
     uint_t flags, uint_t *perm_flags)
@@ -3438,7 +3609,7 @@
  */
 static dladm_status_t
 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
-    dladm_arg_list_t *proplist, const char *name, void *val)
+    dladm_arg_list_t *proplist, const char *name, void *arg)
 {
 	dladm_status_t		status;
 	dladm_arg_info_t	*aip = NULL;
@@ -3488,8 +3659,8 @@
 
 			/* Extract kernel structure */
 			if (rpp->rp_extract != NULL) {
-				status = rpp->rp_extract(vdp, val,
-				    aip->ai_count);
+				status = rpp->rp_extract(vdp,
+				    aip->ai_count, arg);
 			} else {
 				status = DLADM_STATUS_BADARG;
 			}
@@ -3511,20 +3682,15 @@
 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
     mac_resource_props_t *mrp)
 {
-	dladm_status_t	status = DLADM_STATUS_OK;
-
-	status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw",
-	    mrp);
-	if (status != DLADM_STATUS_OK)
-		return (status);
-	status = i_dladm_link_proplist_extract_one(handle, proplist, "priority",
-	    mrp);
-	if (status != DLADM_STATUS_OK)
-		return (status);
-	status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus",
-	    mrp);
-	if (status != DLADM_STATUS_OK)
-		return (status);
+	dladm_status_t	status;
+	int		i;
+
+	for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
+		status = i_dladm_link_proplist_extract_one(handle,
+		    proplist, rsrc_prop_table[i].rp_name, mrp);
+		if (status != DLADM_STATUS_OK)
+			return (status);
+	}
 	return (status);
 }
 
--- a/usr/src/lib/libdladm/common/mapfile-vers	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/mapfile-vers	Wed Oct 07 14:39:04 2009 -0700
@@ -157,6 +157,10 @@
 	dladm_walk_hwgrp;
 	dladm_pri2str;
 	dladm_str2pri;
+	dladm_protect2str;
+	dladm_str2protect;
+	dladm_ipv4addr2str;
+	dladm_str2ipv4addr;
 	dladm_start_usagelog;
 	dladm_stop_usagelog;
 	dladm_walk_usage_res;
--- a/usr/src/lib/libinetutil/common/ofmt.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libinetutil/common/ofmt.c	Wed Oct 07 14:39:04 2009 -0700
@@ -43,6 +43,7 @@
 	char	*s_buf;
 	const char **s_fields;	/* array of pointers to the fields in s_buf */
 	uint_t	s_nfields;	/* the number of fields in s_buf */
+	uint_t	s_currfield;	/* the current field being processed */
 } split_t;
 static void splitfree(split_t *);
 static split_t *split_str(const char *, uint_t);
@@ -62,6 +63,7 @@
 	struct winsize	os_winsize;
 	int		os_nrow;
 	boolean_t	os_parsable;
+	boolean_t	os_wrap;
 	int		os_nbad;
 	char		**os_badfields;
 } ofmt_state_t;
@@ -74,6 +76,12 @@
  */
 #define	OFMT_VAL_UNDEF		"--"
 #define	OFMT_VAL_UNKNOWN	"?"
+
+/*
+ * The maximum number of rows supported by the OFMT_WRAP option.
+ */
+#define	OFMT_MAX_ROWS		128
+
 static void ofmt_print_header(ofmt_state_t *);
 static void ofmt_print_field(ofmt_state_t *, ofmt_field_t *, const char *,
     boolean_t);
@@ -177,7 +185,8 @@
 	ofmt_state_t	*os;
 	int		nfields = 0;
 	ofmt_status_t	err = OFMT_SUCCESS;
-	boolean_t	parsable = (flags & OFMT_PARSABLE);
+	boolean_t	parsable = ((flags & OFMT_PARSABLE) != 0);
+	boolean_t	wrap = ((flags & OFMT_WRAP) != 0);
 
 	*ofmt = NULL;
 	if (parsable) {
@@ -190,6 +199,8 @@
 			return (OFMT_EPARSENONE);
 		if (strcmp(str, "all") == 0)
 			return (OFMT_EPARSEALL);
+		if (wrap)
+			return (OFMT_EPARSEWRAP);
 	}
 	if (template == NULL)
 		return (OFMT_ENOTEMPLATE);
@@ -216,6 +227,8 @@
 	*ofmt = os;
 	os->os_fields = (ofmt_field_t *)&os[1];
 	os->os_parsable = parsable;
+	os->os_wrap = wrap;
+
 	of = os->os_fields;
 	of_index = 0;
 	/*
@@ -318,8 +331,6 @@
 			(void) putchar(':');
 		return;
 	} else {
-		if (value[0] == '\0')
-			value = OFMT_VAL_UNDEF;
 		if (os->os_lastfield) {
 			(void) printf("%s", value);
 			os->os_overflow = 0;
@@ -343,7 +354,42 @@
 }
 
 /*
- * print one row of output values for the selected columns.
+ * Print enough to fit the field width.
+ */
+static void
+ofmt_fit_width(split_t **spp, uint_t width, char *value, uint_t bufsize)
+{
+	split_t		*sp = *spp;
+	char		*ptr = value, *lim = ptr + bufsize;
+	int		i, nextlen;
+
+	if (sp == NULL) {
+		sp = split_str(value, OFMT_MAX_ROWS);
+		if (sp == NULL)
+			return;
+
+		*spp = sp;
+	}
+	for (i = sp->s_currfield; i < sp->s_nfields; i++) {
+		ptr += snprintf(ptr, lim - ptr, "%s,", sp->s_fields[i]);
+		if (i + 1 == sp->s_nfields) {
+			nextlen = 0;
+			if (ptr > value)
+				ptr[-1] = '\0';
+		} else {
+			nextlen = strlen(sp->s_fields[i + 1]);
+		}
+
+		if (strlen(value) + nextlen > width || ptr >= lim) {
+			i++;
+			break;
+		}
+	}
+	sp->s_currfield = i;
+}
+
+/*
+ * Print one or more rows of output values for the selected columns.
  */
 void
 ofmt_print(ofmt_handle_t ofmt, void *arg)
@@ -352,8 +398,15 @@
 	int i;
 	char value[1024];
 	ofmt_field_t *of;
-	boolean_t escsep;
+	boolean_t escsep, more_rows;
 	ofmt_arg_t ofarg;
+	split_t **sp = NULL;
+
+	if (os->os_wrap) {
+		sp = calloc(sizeof (split_t *), os->os_nfields);
+		if (sp == NULL)
+			return;
+	}
 
 	if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 && !os->os_parsable) {
 		ofmt_print_header(os);
@@ -362,18 +415,57 @@
 
 	of = os->os_fields;
 	escsep = (os->os_nfields > 1);
+	more_rows = B_FALSE;
 	for (i = 0; i < os->os_nfields; i++) {
 		os->os_lastfield = (i + 1 == os->os_nfields);
 		value[0] = '\0';
 		ofarg.ofmt_id = of[i].of_id;
 		ofarg.ofmt_cbarg = arg;
-		if ((*of[i].of_cb)(&ofarg, value, sizeof (value)))
-			ofmt_print_field(os, &of[i], value, escsep);
-		else
+
+		if ((*of[i].of_cb)(&ofarg, value, sizeof (value))) {
+			if (os->os_wrap) {
+				/*
+				 * 'value' will be split at comma boundaries
+				 * and stored into sp[i].
+				 */
+				ofmt_fit_width(&sp[i], of[i].of_width, value,
+				    sizeof (value));
+				if (sp[i] != NULL &&
+				    sp[i]->s_currfield < sp[i]->s_nfields)
+					more_rows = B_TRUE;
+			}
+			ofmt_print_field(os, &of[i],
+			    (*value == '\0' && !os->os_parsable) ?
+			    OFMT_VAL_UNDEF : value, escsep);
+		} else {
 			ofmt_print_field(os, &of[i], OFMT_VAL_UNKNOWN, escsep);
+		}
 	}
 	(void) putchar('\n');
+
+	while (more_rows) {
+		more_rows = B_FALSE;
+		for (i = 0; i < os->os_nfields; i++) {
+			os->os_lastfield = (i + 1 == os->os_nfields);
+			value[0] = '\0';
+
+			ofmt_fit_width(&sp[i], of[i].of_width,
+			    value, sizeof (value));
+			if (sp[i] != NULL &&
+			    sp[i]->s_currfield < sp[i]->s_nfields)
+				more_rows = B_TRUE;
+
+			ofmt_print_field(os, &of[i], value, escsep);
+		}
+		(void) putchar('\n');
+	}
 	(void) fflush(stdout);
+
+	if (sp != NULL) {
+		for (i = 0; i < os->os_nfields; i++)
+			splitfree(sp[i]);
+		free(sp);
+	}
 }
 
 /*
@@ -463,6 +555,9 @@
 	case OFMT_EPARSENONE:
 		s = "output fields must be specified in parsable mode";
 		break;
+	case OFMT_EPARSEWRAP:
+		s = "parsable mode is incompatible with wrap mode";
+		break;
 	case OFMT_ENOTEMPLATE:
 		s = "no template provided for fields";
 		break;
--- a/usr/src/lib/libinetutil/common/ofmt.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libinetutil/common/ofmt.h	Wed Oct 07 14:39:04 2009 -0700
@@ -134,6 +134,7 @@
 	OFMT_ENOFIELDS,		/* no valid output fields */
 	OFMT_EPARSEALL,		/* 'all' invalid in parsable mode */
 	OFMT_EPARSENONE,	/* output fields missing in parsable mode */
+	OFMT_EPARSEWRAP,	/* parsable mode incompatible with wrap mode */
 	OFMT_ENOTEMPLATE	/* no template provided for fields */
 } ofmt_status_t;
 
@@ -169,6 +170,7 @@
     uint_t, ofmt_handle_t *);
 
 #define	OFMT_PARSABLE	0x00000001 /* machine parsable mode */
+#define	OFMT_WRAP	0x00000002 /* wrap output if field width is exceeded */
 
 /*
  * ofmt_close() must be called to free resources associated
--- a/usr/src/uts/common/Makefile.files	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Wed Oct 07 14:39:04 2009 -0700
@@ -613,7 +613,7 @@
 
 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
 
--- a/usr/src/uts/common/io/dld/dld_proto.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dld/dld_proto.c	Wed Oct 07 14:39:04 2009 -0700
@@ -913,6 +913,17 @@
 		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) {
--- a/usr/src/uts/common/io/dld/dld_str.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dld/dld_str.c	Wed Oct 07 14:39:04 2009 -0700
@@ -934,7 +934,7 @@
 		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 @@
 	/*
 	 * 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);
 
 	/*
--- a/usr/src/uts/common/io/dls/dls_link.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dls/dls_link.c	Wed Oct 07 14:39:04 2009 -0700
@@ -100,17 +100,17 @@
  * - 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 @@
 				(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 @@
 		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 @@
 		 */
 		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 @@
 	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_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 @@
 		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);
-}
--- a/usr/src/uts/common/io/mac/mac.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac.c	Wed Oct 07 14:39:04 2009 -0700
@@ -2729,6 +2729,7 @@
 	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 @@
 	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;
 
--- a/usr/src/uts/common/io/mac/mac_client.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac_client.c	Wed Oct 07 14:39:04 2009 -0700
@@ -2791,7 +2791,7 @@
 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 @@
 		}
 	}
 
+	/*
+	 * 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 @@
 	 * 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 @@
 
 	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 @@
 	    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 @@
 		}
 		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 @@
 		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);
 }
 
--- a/usr/src/uts/common/io/mac/mac_flow.c	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac_flow.c	Wed Oct 07 14:39:04 2009 -0700
@@ -2354,7 +2354,10 @@
 	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 @@
 	{&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 \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mac/mac_protect.c	Wed Oct 07 14:39:04 2009 -0700
@@ -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;
+		}
+	}
+}
--- a/usr/src/uts/common/sys/dls_impl.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/dls_impl.h	Wed Oct 07 14:39:04 2009 -0700
@@ -84,8 +84,6 @@
 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);
--- a/usr/src/uts/common/sys/mac.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac.h	Wed Oct 07 14:39:04 2009 -0700
@@ -211,6 +211,7 @@
 	MAC_PROP_PVID,
 	MAC_PROP_LLIMIT,
 	MAC_PROP_LDECAY,
+	MAC_PROP_PROTECT,
 	MAC_PROP_PRIVATE = -1
 } mac_prop_id_t;
 
--- a/usr/src/uts/common/sys/mac_client_priv.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_client_priv.h	Wed Oct 07 14:39:04 2009 -0700
@@ -68,6 +68,7 @@
 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 *);
 
--- a/usr/src/uts/common/sys/mac_flow.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_flow.h	Wed Oct 07 14:39:04 2009 -0700
@@ -113,7 +113,7 @@
 	 * 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 @@
 	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 @@
 #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 @@
 	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
--- a/usr/src/uts/common/sys/mac_impl.h	Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_impl.h	Wed Oct 07 14:39:04 2009 -0700
@@ -751,6 +751,12 @@
 
 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;