1*10734SEric Cheng /* 2*10734SEric Cheng * CDDL HEADER START 3*10734SEric Cheng * 4*10734SEric Cheng * The contents of this file are subject to the terms of the 5*10734SEric Cheng * Common Development and Distribution License (the "License"). 6*10734SEric Cheng * You may not use this file except in compliance with the License. 7*10734SEric Cheng * 8*10734SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10734SEric Cheng * or http://www.opensolaris.org/os/licensing. 10*10734SEric Cheng * See the License for the specific language governing permissions 11*10734SEric Cheng * and limitations under the License. 12*10734SEric Cheng * 13*10734SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 14*10734SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10734SEric Cheng * If applicable, add the following below this CDDL HEADER, with the 16*10734SEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 17*10734SEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 18*10734SEric Cheng * 19*10734SEric Cheng * CDDL HEADER END 20*10734SEric Cheng */ 21*10734SEric Cheng 22*10734SEric Cheng /* 23*10734SEric Cheng * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*10734SEric Cheng * Use is subject to license terms. 25*10734SEric Cheng */ 26*10734SEric Cheng 27*10734SEric Cheng #include <sys/strsun.h> 28*10734SEric Cheng #include <sys/sdt.h> 29*10734SEric Cheng #include <sys/mac.h> 30*10734SEric Cheng #include <sys/mac_impl.h> 31*10734SEric Cheng #include <sys/mac_client_impl.h> 32*10734SEric Cheng #include <sys/mac_client_priv.h> 33*10734SEric Cheng #include <sys/ethernet.h> 34*10734SEric Cheng #include <sys/vlan.h> 35*10734SEric Cheng #include <sys/dlpi.h> 36*10734SEric Cheng #include <inet/ip.h> 37*10734SEric Cheng #include <inet/ip6.h> 38*10734SEric Cheng #include <inet/arp.h> 39*10734SEric Cheng 40*10734SEric Cheng /* 41*10734SEric Cheng * Check if ipaddr is in the 'allowed-ips' list. 42*10734SEric Cheng */ 43*10734SEric Cheng static boolean_t 44*10734SEric Cheng ipnospoof_check_ips(mac_protect_t *protect, ipaddr_t ipaddr) 45*10734SEric Cheng { 46*10734SEric Cheng uint_t i; 47*10734SEric Cheng 48*10734SEric Cheng /* 49*10734SEric Cheng * unspecified addresses are harmless and are used by ARP,DHCP..etc. 50*10734SEric Cheng */ 51*10734SEric Cheng if (ipaddr == INADDR_ANY) 52*10734SEric Cheng return (B_TRUE); 53*10734SEric Cheng 54*10734SEric Cheng for (i = 0; i < protect->mp_ipaddrcnt; i++) { 55*10734SEric Cheng if (protect->mp_ipaddrs[i] == ipaddr) 56*10734SEric Cheng return (B_TRUE); 57*10734SEric Cheng } 58*10734SEric Cheng return (B_FALSE); 59*10734SEric Cheng } 60*10734SEric Cheng 61*10734SEric Cheng /* 62*10734SEric Cheng * Enforce ip-nospoof protection. Only IPv4 is supported for now. 63*10734SEric Cheng */ 64*10734SEric Cheng static int 65*10734SEric Cheng ipnospoof_check(mac_client_impl_t *mcip, mac_protect_t *protect, 66*10734SEric Cheng mblk_t *mp, mac_header_info_t *mhip) 67*10734SEric Cheng { 68*10734SEric Cheng uint32_t sap = mhip->mhi_bindsap; 69*10734SEric Cheng uchar_t *start = mp->b_rptr + mhip->mhi_hdrsize; 70*10734SEric Cheng int err = EINVAL; 71*10734SEric Cheng 72*10734SEric Cheng /* 73*10734SEric Cheng * This handles the case where the mac header is not in 74*10734SEric Cheng * the same mblk as the IP header. 75*10734SEric Cheng */ 76*10734SEric Cheng if (start == mp->b_wptr) { 77*10734SEric Cheng mp = mp->b_cont; 78*10734SEric Cheng 79*10734SEric Cheng /* 80*10734SEric Cheng * IP header missing. Let the packet through. 81*10734SEric Cheng */ 82*10734SEric Cheng if (mp == NULL) 83*10734SEric Cheng return (0); 84*10734SEric Cheng 85*10734SEric Cheng start = mp->b_rptr; 86*10734SEric Cheng } 87*10734SEric Cheng 88*10734SEric Cheng switch (sap) { 89*10734SEric Cheng case ETHERTYPE_IP: { 90*10734SEric Cheng ipha_t *ipha = (ipha_t *)start; 91*10734SEric Cheng 92*10734SEric Cheng if (start + sizeof (ipha_t) > mp->b_wptr || !OK_32PTR(start)) 93*10734SEric Cheng goto fail; 94*10734SEric Cheng 95*10734SEric Cheng if (!ipnospoof_check_ips(protect, ipha->ipha_src)) 96*10734SEric Cheng goto fail; 97*10734SEric Cheng 98*10734SEric Cheng break; 99*10734SEric Cheng } 100*10734SEric Cheng case ETHERTYPE_ARP: { 101*10734SEric Cheng arh_t *arh = (arh_t *)start; 102*10734SEric Cheng uint32_t maclen, hlen, plen, arplen; 103*10734SEric Cheng ipaddr_t spaddr; 104*10734SEric Cheng uchar_t *shaddr; 105*10734SEric Cheng 106*10734SEric Cheng if (start + sizeof (arh_t) > mp->b_wptr) 107*10734SEric Cheng goto fail; 108*10734SEric Cheng 109*10734SEric Cheng maclen = mcip->mci_mip->mi_info.mi_addr_length; 110*10734SEric Cheng hlen = arh->arh_hlen; 111*10734SEric Cheng plen = arh->arh_plen; 112*10734SEric Cheng if ((hlen != 0 && hlen != maclen) || 113*10734SEric Cheng plen != sizeof (ipaddr_t)) 114*10734SEric Cheng goto fail; 115*10734SEric Cheng 116*10734SEric Cheng arplen = sizeof (arh_t) + 2 * hlen + 2 * plen; 117*10734SEric Cheng if (start + arplen > mp->b_wptr) 118*10734SEric Cheng goto fail; 119*10734SEric Cheng 120*10734SEric Cheng shaddr = start + sizeof (arh_t); 121*10734SEric Cheng if (hlen != 0 && 122*10734SEric Cheng bcmp(mcip->mci_unicast->ma_addr, shaddr, maclen) != 0) 123*10734SEric Cheng goto fail; 124*10734SEric Cheng 125*10734SEric Cheng bcopy(shaddr + hlen, &spaddr, sizeof (spaddr)); 126*10734SEric Cheng if (!ipnospoof_check_ips(protect, spaddr)) 127*10734SEric Cheng goto fail; 128*10734SEric Cheng break; 129*10734SEric Cheng } 130*10734SEric Cheng default: 131*10734SEric Cheng break; 132*10734SEric Cheng } 133*10734SEric Cheng return (0); 134*10734SEric Cheng 135*10734SEric Cheng fail: 136*10734SEric Cheng /* increment ipnospoof stat here */ 137*10734SEric Cheng return (err); 138*10734SEric Cheng } 139*10734SEric Cheng 140*10734SEric Cheng /* 141*10734SEric Cheng * Enforce link protection on one packet. 142*10734SEric Cheng */ 143*10734SEric Cheng static int 144*10734SEric Cheng mac_protect_check_one(mac_client_impl_t *mcip, mblk_t *mp) 145*10734SEric Cheng { 146*10734SEric Cheng mac_impl_t *mip = mcip->mci_mip; 147*10734SEric Cheng mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip); 148*10734SEric Cheng mac_protect_t *protect; 149*10734SEric Cheng mac_header_info_t mhi; 150*10734SEric Cheng uint32_t types; 151*10734SEric Cheng int err; 152*10734SEric Cheng 153*10734SEric Cheng ASSERT(mp->b_next == NULL); 154*10734SEric Cheng ASSERT(mrp != NULL); 155*10734SEric Cheng 156*10734SEric Cheng err = mac_vlan_header_info((mac_handle_t)mip, mp, &mhi); 157*10734SEric Cheng if (err != 0) { 158*10734SEric Cheng DTRACE_PROBE2(invalid__header, mac_client_impl_t *, mcip, 159*10734SEric Cheng mblk_t *, mp); 160*10734SEric Cheng return (err); 161*10734SEric Cheng } 162*10734SEric Cheng 163*10734SEric Cheng protect = &mrp->mrp_protect; 164*10734SEric Cheng types = protect->mp_types; 165*10734SEric Cheng 166*10734SEric Cheng if ((types & MPT_MACNOSPOOF) != 0) { 167*10734SEric Cheng if (mhi.mhi_saddr != NULL && 168*10734SEric Cheng bcmp(mcip->mci_unicast->ma_addr, mhi.mhi_saddr, 169*10734SEric Cheng mip->mi_info.mi_addr_length) != 0) { 170*10734SEric Cheng DTRACE_PROBE2(mac__nospoof__fail, 171*10734SEric Cheng mac_client_impl_t *, mcip, mblk_t *, mp); 172*10734SEric Cheng return (EINVAL); 173*10734SEric Cheng } 174*10734SEric Cheng } 175*10734SEric Cheng 176*10734SEric Cheng if ((types & MPT_RESTRICTED) != 0) { 177*10734SEric Cheng uint32_t vid = VLAN_ID(mhi.mhi_tci); 178*10734SEric Cheng uint32_t sap = mhi.mhi_bindsap; 179*10734SEric Cheng 180*10734SEric Cheng /* 181*10734SEric Cheng * ETHERTYPE_VLAN packets are allowed through, provided that 182*10734SEric Cheng * the vid is not spoofed. 183*10734SEric Cheng */ 184*10734SEric Cheng if (vid != 0 && !mac_client_check_flow_vid(mcip, vid)) { 185*10734SEric Cheng DTRACE_PROBE2(restricted__vid__invalid, 186*10734SEric Cheng mac_client_impl_t *, mcip, mblk_t *, mp); 187*10734SEric Cheng return (EINVAL); 188*10734SEric Cheng } 189*10734SEric Cheng 190*10734SEric Cheng if (sap != ETHERTYPE_IP && sap != ETHERTYPE_IPV6 && 191*10734SEric Cheng sap != ETHERTYPE_ARP) { 192*10734SEric Cheng DTRACE_PROBE2(restricted__fail, 193*10734SEric Cheng mac_client_impl_t *, mcip, mblk_t *, mp); 194*10734SEric Cheng return (EINVAL); 195*10734SEric Cheng } 196*10734SEric Cheng } 197*10734SEric Cheng 198*10734SEric Cheng if ((types & MPT_IPNOSPOOF) != 0) { 199*10734SEric Cheng if ((err = ipnospoof_check(mcip, protect, 200*10734SEric Cheng mp, &mhi)) != 0) { 201*10734SEric Cheng DTRACE_PROBE2(ip__nospoof__fail, 202*10734SEric Cheng mac_client_impl_t *, mcip, mblk_t *, mp); 203*10734SEric Cheng return (err); 204*10734SEric Cheng } 205*10734SEric Cheng } 206*10734SEric Cheng return (0); 207*10734SEric Cheng } 208*10734SEric Cheng 209*10734SEric Cheng /* 210*10734SEric Cheng * Enforce link protection on a packet chain. 211*10734SEric Cheng * Packets that pass the checks are returned back to the caller. 212*10734SEric Cheng */ 213*10734SEric Cheng mblk_t * 214*10734SEric Cheng mac_protect_check(mac_client_handle_t mch, mblk_t *mp) 215*10734SEric Cheng { 216*10734SEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 217*10734SEric Cheng mblk_t *ret_mp = NULL, **tailp = &ret_mp, *next; 218*10734SEric Cheng 219*10734SEric Cheng /* 220*10734SEric Cheng * Skip checks if we are part of an aggr. 221*10734SEric Cheng */ 222*10734SEric Cheng if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0) 223*10734SEric Cheng return (mp); 224*10734SEric Cheng 225*10734SEric Cheng for (; mp != NULL; mp = next) { 226*10734SEric Cheng next = mp->b_next; 227*10734SEric Cheng mp->b_next = NULL; 228*10734SEric Cheng 229*10734SEric Cheng if (mac_protect_check_one(mcip, mp) == 0) { 230*10734SEric Cheng *tailp = mp; 231*10734SEric Cheng tailp = &mp->b_next; 232*10734SEric Cheng } else { 233*10734SEric Cheng freemsg(mp); 234*10734SEric Cheng } 235*10734SEric Cheng } 236*10734SEric Cheng return (ret_mp); 237*10734SEric Cheng } 238*10734SEric Cheng 239*10734SEric Cheng /* 240*10734SEric Cheng * Check if a particular protection type is enabled. 241*10734SEric Cheng */ 242*10734SEric Cheng boolean_t 243*10734SEric Cheng mac_protect_enabled(mac_client_handle_t mch, uint32_t type) 244*10734SEric Cheng { 245*10734SEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 246*10734SEric Cheng mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip); 247*10734SEric Cheng 248*10734SEric Cheng ASSERT(mrp != NULL); 249*10734SEric Cheng return ((mrp->mrp_protect.mp_types & type) != 0); 250*10734SEric Cheng } 251*10734SEric Cheng 252*10734SEric Cheng /* 253*10734SEric Cheng * Sanity-checks parameters given by userland. 254*10734SEric Cheng */ 255*10734SEric Cheng int 256*10734SEric Cheng mac_protect_validate(mac_resource_props_t *mrp) 257*10734SEric Cheng { 258*10734SEric Cheng mac_protect_t *p = &mrp->mrp_protect; 259*10734SEric Cheng 260*10734SEric Cheng /* check for invalid types */ 261*10734SEric Cheng if (p->mp_types != MPT_RESET && (p->mp_types & ~MPT_ALL) != 0) 262*10734SEric Cheng return (EINVAL); 263*10734SEric Cheng 264*10734SEric Cheng if (p->mp_ipaddrcnt != MPT_RESET) { 265*10734SEric Cheng uint_t i, j; 266*10734SEric Cheng 267*10734SEric Cheng if (p->mp_ipaddrcnt > MPT_MAXIPADDR) 268*10734SEric Cheng return (EINVAL); 269*10734SEric Cheng 270*10734SEric Cheng for (i = 0; i < p->mp_ipaddrcnt; i++) { 271*10734SEric Cheng /* 272*10734SEric Cheng * The unspecified address is implicitly allowed 273*10734SEric Cheng * so there's no need to add it to the list. 274*10734SEric Cheng */ 275*10734SEric Cheng if (p->mp_ipaddrs[i] == INADDR_ANY) 276*10734SEric Cheng return (EINVAL); 277*10734SEric Cheng 278*10734SEric Cheng for (j = 0; j < p->mp_ipaddrcnt; j++) { 279*10734SEric Cheng /* found a duplicate */ 280*10734SEric Cheng if (i != j && 281*10734SEric Cheng p->mp_ipaddrs[i] == p->mp_ipaddrs[j]) 282*10734SEric Cheng return (EINVAL); 283*10734SEric Cheng } 284*10734SEric Cheng } 285*10734SEric Cheng } 286*10734SEric Cheng return (0); 287*10734SEric Cheng } 288*10734SEric Cheng 289*10734SEric Cheng /* 290*10734SEric Cheng * Enable/disable link protection. 291*10734SEric Cheng */ 292*10734SEric Cheng int 293*10734SEric Cheng mac_protect_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 294*10734SEric Cheng { 295*10734SEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 296*10734SEric Cheng mac_impl_t *mip = mcip->mci_mip; 297*10734SEric Cheng uint_t media = mip->mi_info.mi_nativemedia; 298*10734SEric Cheng int err; 299*10734SEric Cheng 300*10734SEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 301*10734SEric Cheng 302*10734SEric Cheng /* tunnels are not supported */ 303*10734SEric Cheng if (media == DL_IPV4 || media == DL_IPV6 || media == DL_6TO4) 304*10734SEric Cheng return (ENOTSUP); 305*10734SEric Cheng 306*10734SEric Cheng if ((err = mac_protect_validate(mrp)) != 0) 307*10734SEric Cheng return (err); 308*10734SEric Cheng 309*10734SEric Cheng mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 310*10734SEric Cheng return (0); 311*10734SEric Cheng } 312*10734SEric Cheng 313*10734SEric Cheng void 314*10734SEric Cheng mac_protect_update(mac_resource_props_t *new, mac_resource_props_t *curr) 315*10734SEric Cheng { 316*10734SEric Cheng mac_protect_t *np = &new->mrp_protect; 317*10734SEric Cheng mac_protect_t *cp = &curr->mrp_protect; 318*10734SEric Cheng uint32_t types = np->mp_types; 319*10734SEric Cheng 320*10734SEric Cheng if (types == MPT_RESET) { 321*10734SEric Cheng cp->mp_types = 0; 322*10734SEric Cheng curr->mrp_mask &= ~MRP_PROTECT; 323*10734SEric Cheng } else { 324*10734SEric Cheng if (types != 0) { 325*10734SEric Cheng cp->mp_types = types; 326*10734SEric Cheng curr->mrp_mask |= MRP_PROTECT; 327*10734SEric Cheng } 328*10734SEric Cheng } 329*10734SEric Cheng 330*10734SEric Cheng if (np->mp_ipaddrcnt != 0) { 331*10734SEric Cheng if (np->mp_ipaddrcnt < MPT_MAXIPADDR) { 332*10734SEric Cheng bcopy(np->mp_ipaddrs, cp->mp_ipaddrs, 333*10734SEric Cheng sizeof (cp->mp_ipaddrs)); 334*10734SEric Cheng cp->mp_ipaddrcnt = np->mp_ipaddrcnt; 335*10734SEric Cheng } else if (np->mp_ipaddrcnt == MPT_RESET) { 336*10734SEric Cheng bzero(cp->mp_ipaddrs, sizeof (cp->mp_ipaddrs)); 337*10734SEric Cheng cp->mp_ipaddrcnt = 0; 338*10734SEric Cheng } 339*10734SEric Cheng } 340*10734SEric Cheng } 341