diff options
Diffstat (limited to 'usr/src/uts/common')
| -rw-r--r-- | usr/src/uts/common/Makefile.files | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/dld/dld_proto.c | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/io/dld/dld_str.c | 4 | ||||
| -rw-r--r-- | usr/src/uts/common/io/dls/dls_link.c | 85 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac_client.c | 96 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac_flow.c | 8 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac_protect.c | 340 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dls_impl.h | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac.h | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac_client_priv.h | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac_flow.h | 19 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac_impl.h | 6 |
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; |
