10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51502Sericheng * Common Development and Distribution License (the "License"). 61502Sericheng * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*8833SVenu.Iyer@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Data-Link Services Module 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/strsun.h> 310Sstevel@tonic-gate #include <sys/vlan.h> 328275SEric Cheng #include <sys/dld_impl.h> 330Sstevel@tonic-gate 348275SEric Cheng int 358275SEric Cheng dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp) 368275SEric Cheng { 378275SEric Cheng zoneid_t zid = getzoneid(); 388275SEric Cheng boolean_t local; 390Sstevel@tonic-gate 408275SEric Cheng /* 418275SEric Cheng * Check whether this client belongs to the zone of this dlp. Note that 428275SEric Cheng * a global zone client is allowed to open a local zone dlp. 438275SEric Cheng */ 448275SEric Cheng if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid) 458275SEric Cheng return (ENOENT); 461184Skrgopi 478275SEric Cheng local = (zid == dlp->dl_zid); 488275SEric Cheng dlp->dl_zone_ref += (local ? 1 : 0); 495895Syz147064 508275SEric Cheng /* 518275SEric Cheng * Cache a copy of the MAC interface handle, a pointer to the 528275SEric Cheng * immutable MAC info. 538275SEric Cheng */ 548275SEric Cheng dsp->ds_dlp = dlp; 558275SEric Cheng dsp->ds_mh = dlp->dl_mh; 568275SEric Cheng dsp->ds_mch = dlp->dl_mch; 578275SEric Cheng dsp->ds_mip = dlp->dl_mip; 588275SEric Cheng dsp->ds_ddh = ddh; 598275SEric Cheng dsp->ds_local = local; 600Sstevel@tonic-gate 618275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 620Sstevel@tonic-gate return (0); 630Sstevel@tonic-gate } 640Sstevel@tonic-gate 658275SEric Cheng void 668275SEric Cheng dls_close(dld_str_t *dsp) 670Sstevel@tonic-gate { 688275SEric Cheng dls_link_t *dlp = dsp->ds_dlp; 698275SEric Cheng dls_multicst_addr_t *p; 708275SEric Cheng dls_multicst_addr_t *nextp; 718275SEric Cheng uint32_t old_flags; 720Sstevel@tonic-gate 738275SEric Cheng ASSERT(dsp->ds_datathr_cnt == 0); 748275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 750Sstevel@tonic-gate 768275SEric Cheng if (dsp->ds_local) 778275SEric Cheng dlp->dl_zone_ref--; 788275SEric Cheng dsp->ds_local = B_FALSE; 790Sstevel@tonic-gate 808275SEric Cheng /* 818275SEric Cheng * Walk the list of multicast addresses, disabling each at the MAC. 828275SEric Cheng * Note that we must remove multicast address before 838275SEric Cheng * mac_unicast_remove() (called by dls_active_clear()) because 848275SEric Cheng * mac_multicast_remove() relies on the unicast flows on the mac 858275SEric Cheng * client. 868275SEric Cheng */ 878275SEric Cheng for (p = dsp->ds_dmap; p != NULL; p = nextp) { 888275SEric Cheng (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr); 898275SEric Cheng nextp = p->dma_nextp; 908275SEric Cheng kmem_free(p, sizeof (dls_multicst_addr_t)); 910Sstevel@tonic-gate } 928275SEric Cheng dsp->ds_dmap = NULL; 938275SEric Cheng 948275SEric Cheng dls_active_clear(dsp); 950Sstevel@tonic-gate 968275SEric Cheng /* 978275SEric Cheng * If the dld_str_t is bound then unbind it. 988275SEric Cheng */ 998275SEric Cheng if (dsp->ds_dlstate == DL_IDLE) { 1008275SEric Cheng (void) dls_unbind(dsp); 1018275SEric Cheng dsp->ds_dlstate = DL_UNBOUND; 1021184Skrgopi } 1031184Skrgopi 1048275SEric Cheng /* 1058275SEric Cheng * If the MAC has been set in promiscuous mode then disable it. 1068275SEric Cheng * This needs to be done before resetting ds_rx. 1078275SEric Cheng */ 1088275SEric Cheng old_flags = dsp->ds_promisc; 1098275SEric Cheng dsp->ds_promisc = 0; 1108275SEric Cheng (void) dls_promisc(dsp, old_flags); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1138275SEric Cheng * At this point we have cutoff inbound packet flow from the mac 1148275SEric Cheng * for this 'dsp'. The dls_link_remove above cut off packets meant 1158275SEric Cheng * for us and waited for upcalls to finish. Similarly the dls_promisc 1168275SEric Cheng * reset above waited for promisc callbacks to finish. Now we can 1178275SEric Cheng * safely reset ds_rx to NULL 1180Sstevel@tonic-gate */ 1198275SEric Cheng dsp->ds_rx = NULL; 1208275SEric Cheng dsp->ds_rx_arg = NULL; 1218275SEric Cheng 1228275SEric Cheng dsp->ds_dlp = NULL; 1238275SEric Cheng 1248275SEric Cheng /* 1258275SEric Cheng * Release our reference to the dls_link_t allowing that to be 1268275SEric Cheng * destroyed if there are no more dls_impl_t. 1278275SEric Cheng */ 1288275SEric Cheng dls_link_rele(dlp); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate int 1328275SEric Cheng dls_bind(dld_str_t *dsp, uint32_t sap) 1330Sstevel@tonic-gate { 1348275SEric Cheng uint32_t dls_sap; 1358275SEric Cheng 1368275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 1378275SEric Cheng 1380Sstevel@tonic-gate /* 1398275SEric Cheng * Check to see the value is legal for the media type. 1400Sstevel@tonic-gate */ 1418275SEric Cheng if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap)) 1428275SEric Cheng return (EINVAL); 1438275SEric Cheng 1448275SEric Cheng if (dsp->ds_promisc & DLS_PROMISC_SAP) 1458275SEric Cheng dls_sap = DLS_SAP_PROMISC; 1468275SEric Cheng 1478275SEric Cheng /* 1488275SEric Cheng * Set up the dld_str_t to mark it as able to receive packets. 1498275SEric Cheng */ 1508275SEric Cheng dsp->ds_sap = sap; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* 1538275SEric Cheng * The MAC layer does the VLAN demultiplexing and will only pass up 1548275SEric Cheng * untagged packets to non-promiscuous primary MAC clients. In order to 1558275SEric Cheng * support the binding to the VLAN SAP which is required by DLPI, dls 1568275SEric Cheng * needs to get a copy of all tagged packets when the client binds to 1578275SEric Cheng * the VLAN SAP. We do this by registering a separate promiscuous 1588275SEric Cheng * callback for each dls client binding to that SAP. 1598275SEric Cheng * 1608275SEric Cheng * Note: even though there are two promiscuous handles in dld_str_t, 1618275SEric Cheng * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle 1628275SEric Cheng * to receive VLAN pkt when promiscuous mode is not on. Only one of 1638275SEric Cheng * them can be non-NULL at the same time, to avoid receiving dup copies 1648275SEric Cheng * of pkts. 1650Sstevel@tonic-gate */ 1668275SEric Cheng if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) { 1678275SEric Cheng int err; 1688275SEric Cheng 1698275SEric Cheng if (dsp->ds_vlan_mph != NULL) 1708275SEric Cheng return (EINVAL); 1718275SEric Cheng err = mac_promisc_add(dsp->ds_mch, 1728275SEric Cheng MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 1738275SEric Cheng &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 1748275SEric Cheng return (err); 1758275SEric Cheng } 1768275SEric Cheng 1778275SEric Cheng /* 1788275SEric Cheng * Now bind the dld_str_t by adding it into the hash table in the 1798275SEric Cheng * dls_link_t. 1808275SEric Cheng */ 1818275SEric Cheng dls_link_add(dsp->ds_dlp, dls_sap, dsp); 1820Sstevel@tonic-gate return (0); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate int 1868275SEric Cheng dls_unbind(dld_str_t *dsp) 1870Sstevel@tonic-gate { 1888275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 1895895Syz147064 1905895Syz147064 /* 1918275SEric Cheng * For VLAN SAP, there was a promisc handle registered when dls_bind. 1928275SEric Cheng * When unbind this dls link, we need to remove the promisc handle. 1938275SEric Cheng * See comments in dls_bind(). 1945895Syz147064 */ 1958275SEric Cheng if (dsp->ds_vlan_mph != NULL) { 1968275SEric Cheng int err; 1975895Syz147064 1988275SEric Cheng err = mac_promisc_remove(dsp->ds_vlan_mph); 1998275SEric Cheng ASSERT(err == 0); 2008275SEric Cheng dsp->ds_vlan_mph = NULL; 2018275SEric Cheng return (err); 2028275SEric Cheng } 2035895Syz147064 2048275SEric Cheng /* 2058275SEric Cheng * Unbind the dld_str_t by removing it from the hash table in the 2068275SEric Cheng * dls_link_t. 2078275SEric Cheng */ 2088275SEric Cheng dls_link_remove(dsp->ds_dlp, dsp); 2098275SEric Cheng dsp->ds_sap = 0; 2108275SEric Cheng return (0); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate int 2148275SEric Cheng dls_promisc(dld_str_t *dsp, uint32_t old_flags) 2150Sstevel@tonic-gate { 2168275SEric Cheng int err = 0; 2178275SEric Cheng 2188275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 2198275SEric Cheng ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 2208275SEric Cheng DLS_PROMISC_PHYS))); 2218275SEric Cheng 2228275SEric Cheng if (old_flags == 0 && dsp->ds_promisc != 0) { 2238275SEric Cheng /* 2248275SEric Cheng * If only DLS_PROMISC_SAP, we don't turn on the 2258275SEric Cheng * physical promisc mode 2268275SEric Cheng */ 2278275SEric Cheng err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 2288275SEric Cheng dls_rx_promisc, dsp, &dsp->ds_mph, 2298275SEric Cheng (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 : 2308275SEric Cheng MAC_PROMISC_FLAGS_NO_PHYS); 2318275SEric Cheng if (err != 0) 2328275SEric Cheng return (err); 2330Sstevel@tonic-gate 2348275SEric Cheng /* Remove vlan promisc handle to avoid sending dup copy up */ 2358275SEric Cheng if (dsp->ds_vlan_mph != NULL) { 2368275SEric Cheng err = mac_promisc_remove(dsp->ds_vlan_mph); 2378275SEric Cheng dsp->ds_vlan_mph = NULL; 2388275SEric Cheng } 2398275SEric Cheng } else if (old_flags != 0 && dsp->ds_promisc == 0) { 2408275SEric Cheng ASSERT(dsp->ds_mph != NULL); 2418275SEric Cheng err = mac_promisc_remove(dsp->ds_mph); 2428275SEric Cheng /* 2438275SEric Cheng * The failure only relates to resetting the device promiscuity 2448275SEric Cheng * The mac layer does not fail in freeing up the promiscuous 2458275SEric Cheng * data structures, and so we clear the ds_mph. The dld stream 2468275SEric Cheng * may be closing and we can't fail that. 2478275SEric Cheng */ 2488275SEric Cheng dsp->ds_mph = NULL; 2498275SEric Cheng if (err != 0) 2508275SEric Cheng return (err); 2510Sstevel@tonic-gate 2528275SEric Cheng if (dsp->ds_sap == ETHERTYPE_VLAN && 2538275SEric Cheng dsp->ds_dlstate != DL_UNBOUND) { 2548275SEric Cheng int err; 2558275SEric Cheng 2568275SEric Cheng if (dsp->ds_vlan_mph != NULL) 2578275SEric Cheng return (EINVAL); 2588275SEric Cheng err = mac_promisc_add(dsp->ds_mch, 2598275SEric Cheng MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 2608275SEric Cheng &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 2618275SEric Cheng return (err); 2628275SEric Cheng } 2638275SEric Cheng } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 && 2648275SEric Cheng dsp->ds_promisc != old_flags) { 2658275SEric Cheng /* 2668275SEric Cheng * If the old flag is PROMISC_SAP, but the current flag has 2678275SEric Cheng * changed to some new non-zero value, we need to turn the 2688275SEric Cheng * physical promiscuous mode. 2698275SEric Cheng */ 2708275SEric Cheng ASSERT(dsp->ds_mph != NULL); 2718275SEric Cheng err = mac_promisc_remove(dsp->ds_mph); 2728275SEric Cheng if (err != 0) 2738275SEric Cheng return (err); 2748275SEric Cheng err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 2758275SEric Cheng dls_rx_promisc, dsp, &dsp->ds_mph, 0); 2765895Syz147064 } 2775895Syz147064 2785895Syz147064 return (err); 2795895Syz147064 } 2805895Syz147064 2818275SEric Cheng int 2828275SEric Cheng dls_multicst_add(dld_str_t *dsp, const uint8_t *addr) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate int err; 2850Sstevel@tonic-gate dls_multicst_addr_t **pp; 2860Sstevel@tonic-gate dls_multicst_addr_t *p; 2870Sstevel@tonic-gate uint_t addr_length; 2880Sstevel@tonic-gate 2898275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 2908275SEric Cheng 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Check whether the address is in the list of enabled addresses for 2938275SEric Cheng * this dld_str_t. 2940Sstevel@tonic-gate */ 2958275SEric Cheng addr_length = dsp->ds_mip->mi_addr_length; 2968275SEric Cheng 2978275SEric Cheng /* 2988275SEric Cheng * Protect against concurrent access of ds_dmap by data threads using 2998275SEric Cheng * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 3008275SEric Cheng * remove operations. Dropping the ds_rw_lock across mac calls is thus 3018275SEric Cheng * ok and is also required by the locking protocol. 3028275SEric Cheng */ 3038275SEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER); 3048275SEric Cheng for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 3050Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) { 3060Sstevel@tonic-gate /* 3070Sstevel@tonic-gate * It is there so there's nothing to do. 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate err = 0; 3100Sstevel@tonic-gate goto done; 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3158275SEric Cheng * Allocate a new list item and add it to the list. 3160Sstevel@tonic-gate */ 3178275SEric Cheng p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP); 3188275SEric Cheng bcopy(addr, p->dma_addr, addr_length); 3198275SEric Cheng *pp = p; 3208275SEric Cheng rw_exit(&dsp->ds_rw_lock); 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Enable the address at the MAC. 3240Sstevel@tonic-gate */ 3258275SEric Cheng err = mac_multicast_add(dsp->ds_mch, addr); 3268275SEric Cheng if (err == 0) 3278275SEric Cheng return (0); 3280Sstevel@tonic-gate 3298275SEric Cheng /* Undo the operation as it has failed */ 3308275SEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER); 3318275SEric Cheng ASSERT(*pp == p && p->dma_nextp == NULL); 3328275SEric Cheng *pp = NULL; 3338275SEric Cheng kmem_free(p, sizeof (dls_multicst_addr_t)); 3340Sstevel@tonic-gate done: 3358275SEric Cheng rw_exit(&dsp->ds_rw_lock); 3360Sstevel@tonic-gate return (err); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate int 3408275SEric Cheng dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate dls_multicst_addr_t **pp; 3430Sstevel@tonic-gate dls_multicst_addr_t *p; 3440Sstevel@tonic-gate uint_t addr_length; 3450Sstevel@tonic-gate 3468275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 3478275SEric Cheng 3480Sstevel@tonic-gate /* 3490Sstevel@tonic-gate * Find the address in the list of enabled addresses for this 3508275SEric Cheng * dld_str_t. 3510Sstevel@tonic-gate */ 3528275SEric Cheng addr_length = dsp->ds_mip->mi_addr_length; 3538275SEric Cheng 3548275SEric Cheng /* 3558275SEric Cheng * Protect against concurrent access to ds_dmap by data threads using 3568275SEric Cheng * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 3578275SEric Cheng * remove operations. Dropping the ds_rw_lock across mac calls is thus 3588275SEric Cheng * ok and is also required by the locking protocol. 3598275SEric Cheng */ 3608275SEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER); 3618275SEric Cheng for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 3620Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) 3630Sstevel@tonic-gate break; 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * If we walked to the end of the list then the given address is 3688275SEric Cheng * not currently enabled for this dld_str_t. 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate if (p == NULL) { 3718275SEric Cheng rw_exit(&dsp->ds_rw_lock); 3728275SEric Cheng return (ENOENT); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate /* 3760Sstevel@tonic-gate * Remove the address from the list. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate *pp = p->dma_nextp; 3798275SEric Cheng rw_exit(&dsp->ds_rw_lock); 3800Sstevel@tonic-gate 3818275SEric Cheng /* 3828275SEric Cheng * Disable the address at the MAC. 3838275SEric Cheng */ 3848275SEric Cheng mac_multicast_remove(dsp->ds_mch, addr); 3858275SEric Cheng kmem_free(p, sizeof (dls_multicst_addr_t)); 3868275SEric Cheng return (0); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate mblk_t * 3908275SEric Cheng dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri, 3912760Sdg199075 mblk_t **payloadp) 3920Sstevel@tonic-gate { 3932760Sdg199075 uint16_t vid; 3942760Sdg199075 size_t extra_len; 3952760Sdg199075 uint16_t mac_sap; 3962760Sdg199075 mblk_t *mp, *payload; 3978275SEric Cheng boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); 3982311Sseb struct ether_vlan_header *evhp; 3990Sstevel@tonic-gate 4008275SEric Cheng vid = mac_client_vid(dsp->ds_mch); 4012760Sdg199075 payload = (payloadp == NULL) ? NULL : (*payloadp); 4022760Sdg199075 4032760Sdg199075 /* 4042760Sdg199075 * If the following conditions are satisfied: 4052760Sdg199075 * - This is not a ETHERTYPE_VLAN listener; and 4062760Sdg199075 * - This is either a VLAN stream or this is a physical stream 4072760Sdg199075 * but the priority is not 0. 4082760Sdg199075 * 4092760Sdg199075 * then we know ahead of time that we'll need to fill in additional 4102760Sdg199075 * VLAN information in the link-layer header. We will tell the MAC 4112760Sdg199075 * layer to pre-allocate some space at the end of the Ethernet 4122760Sdg199075 * header for us. 4132760Sdg199075 */ 4142760Sdg199075 if (is_ethernet && sap != ETHERTYPE_VLAN && 4152760Sdg199075 (vid != VLAN_ID_NONE || pri != 0)) { 4162311Sseb extra_len = sizeof (struct ether_vlan_header) - 4172311Sseb sizeof (struct ether_header); 4182760Sdg199075 mac_sap = ETHERTYPE_VLAN; 4192311Sseb } else { 4202311Sseb extra_len = 0; 4212311Sseb mac_sap = sap; 4222311Sseb } 4232311Sseb 4248275SEric Cheng mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len); 4252760Sdg199075 if (mp == NULL) 4262760Sdg199075 return (NULL); 4272760Sdg199075 4282760Sdg199075 if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) 4292311Sseb return (mp); 4302311Sseb 4312760Sdg199075 /* 4322760Sdg199075 * Fill in the tag information. 4332760Sdg199075 */ 4342311Sseb ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 4352760Sdg199075 if (extra_len != 0) { 4362760Sdg199075 mp->b_wptr += extra_len; 4372760Sdg199075 evhp = (struct ether_vlan_header *)mp->b_rptr; 4382760Sdg199075 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 4392760Sdg199075 evhp->ether_type = htons(sap); 4402760Sdg199075 } else { 4412760Sdg199075 /* 4422760Sdg199075 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 4432760Sdg199075 * in the payload. Update the priority. 4442760Sdg199075 */ 4452760Sdg199075 struct ether_vlan_extinfo *extinfo; 4462760Sdg199075 size_t len = sizeof (struct ether_vlan_extinfo); 4472760Sdg199075 4482760Sdg199075 ASSERT(sap == ETHERTYPE_VLAN); 4492760Sdg199075 ASSERT(payload != NULL); 4502760Sdg199075 4512760Sdg199075 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 4522760Sdg199075 mblk_t *newmp; 4532760Sdg199075 4542760Sdg199075 /* 4552760Sdg199075 * Because some DLS consumers only check the db_ref 4562760Sdg199075 * count of the first mblk, we pullup 'payload' into 4572760Sdg199075 * a single mblk. 4582760Sdg199075 */ 4592760Sdg199075 newmp = msgpullup(payload, -1); 4602760Sdg199075 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 4612760Sdg199075 freemsg(newmp); 4622760Sdg199075 freemsg(mp); 4632760Sdg199075 return (NULL); 4642760Sdg199075 } else { 4652760Sdg199075 freemsg(payload); 4662760Sdg199075 *payloadp = payload = newmp; 4672760Sdg199075 } 4682760Sdg199075 } 4692760Sdg199075 4702760Sdg199075 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 4712760Sdg199075 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 4722760Sdg199075 VLAN_ID(ntohs(extinfo->ether_tci)))); 4732760Sdg199075 } 4742311Sseb return (mp); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate void 4788275SEric Cheng dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg) 4790Sstevel@tonic-gate { 4808275SEric Cheng mutex_enter(&dsp->ds_lock); 4818275SEric Cheng dsp->ds_rx = rx; 4828275SEric Cheng dsp->ds_rx_arg = arg; 4838275SEric Cheng mutex_exit(&dsp->ds_lock); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4868275SEric Cheng static boolean_t 4878275SEric Cheng dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 4888275SEric Cheng void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate dls_multicst_addr_t *dmap; 4918275SEric Cheng size_t addr_length = dsp->ds_mip->mi_addr_length; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4948275SEric Cheng * We must not accept packets if the dld_str_t is not marked as bound 4950Sstevel@tonic-gate * or is being removed. 4960Sstevel@tonic-gate */ 4978275SEric Cheng if (dsp->ds_dlstate != DL_IDLE) 4980Sstevel@tonic-gate goto refuse; 4990Sstevel@tonic-gate 5008275SEric Cheng if (dsp->ds_promisc != 0) { 5018275SEric Cheng /* 5028275SEric Cheng * Filter out packets that arrived from the data path 5038275SEric Cheng * (i_dls_link_rx) when promisc mode is on. 5048275SEric Cheng */ 5058275SEric Cheng if (!promisc) 5068275SEric Cheng goto refuse; 5078275SEric Cheng /* 5088275SEric Cheng * If the dls_impl_t is in 'all physical' mode then 5098275SEric Cheng * always accept. 5108275SEric Cheng */ 5118275SEric Cheng if (dsp->ds_promisc & DLS_PROMISC_PHYS) 5128275SEric Cheng goto accept; 5130Sstevel@tonic-gate 5148275SEric Cheng /* 5158275SEric Cheng * Loopback packets i.e. packets sent out by DLS on a given 5168275SEric Cheng * mac end point, will be accepted back by DLS on loopback 5178275SEric Cheng * from the mac, only in the 'all physical' mode which has been 5188275SEric Cheng * covered by the previous check above 5198275SEric Cheng */ 5208275SEric Cheng if (promisc_loopback) 5218275SEric Cheng goto refuse; 5228275SEric Cheng } 5235895Syz147064 5242311Sseb switch (mhip->mhi_dsttype) { 5252311Sseb case MAC_ADDRTYPE_UNICAST: 5268275SEric Cheng case MAC_ADDRTYPE_BROADCAST: 5272311Sseb /* 5288275SEric Cheng * We can accept unicast and broadcast packets because 5298275SEric Cheng * filtering is already done by the mac layer. 5302311Sseb */ 5318275SEric Cheng goto accept; 5322311Sseb case MAC_ADDRTYPE_MULTICAST: 5332311Sseb /* 5348275SEric Cheng * Additional filtering is needed for multicast addresses 5358275SEric Cheng * because different streams may be interested in different 5368275SEric Cheng * addresses. 5372311Sseb */ 5388275SEric Cheng if (dsp->ds_promisc & DLS_PROMISC_MULTI) 5392311Sseb goto accept; 5408275SEric Cheng 5418275SEric Cheng rw_enter(&dsp->ds_rw_lock, RW_READER); 5428275SEric Cheng for (dmap = dsp->ds_dmap; dmap != NULL; 5432311Sseb dmap = dmap->dma_nextp) { 5442311Sseb if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 5452311Sseb addr_length) == 0) { 5468275SEric Cheng rw_exit(&dsp->ds_rw_lock); 5472311Sseb goto accept; 5482311Sseb } 5492311Sseb } 5508275SEric Cheng rw_exit(&dsp->ds_rw_lock); 5512311Sseb break; 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate refuse: 5550Sstevel@tonic-gate return (B_FALSE); 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate accept: 558449Sericheng /* 5598275SEric Cheng * the returned ds_rx and ds_rx_arg will always be in sync. 560449Sericheng */ 5618275SEric Cheng mutex_enter(&dsp->ds_lock); 5628275SEric Cheng *ds_rx = dsp->ds_rx; 5638275SEric Cheng *ds_rx_arg = dsp->ds_rx_arg; 5648275SEric Cheng mutex_exit(&dsp->ds_lock); 5658275SEric Cheng 5660Sstevel@tonic-gate return (B_TRUE); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5692760Sdg199075 /* ARGSUSED */ 5700Sstevel@tonic-gate boolean_t 5718275SEric Cheng dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 5728275SEric Cheng void **ds_rx_arg) 5730Sstevel@tonic-gate { 5748275SEric Cheng return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE, 5758275SEric Cheng B_FALSE)); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate boolean_t 5798275SEric Cheng dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 5808275SEric Cheng void **ds_rx_arg, boolean_t loopback) 5818275SEric Cheng { 5828275SEric Cheng return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE, 5838275SEric Cheng loopback)); 5848275SEric Cheng } 5858275SEric Cheng 5868275SEric Cheng int 5875895Syz147064 dls_mac_active_set(dls_link_t *dlp) 5885895Syz147064 { 5898275SEric Cheng int err = 0; 5905895Syz147064 5915895Syz147064 /* 5928275SEric Cheng * First client; add the primary unicast address. 5935895Syz147064 */ 5948275SEric Cheng if (dlp->dl_nactive == 0) { 5958275SEric Cheng /* 5968275SEric Cheng * First client; add the primary unicast address. 5978275SEric Cheng */ 5988275SEric Cheng mac_diag_t diag; 5998275SEric Cheng 6008275SEric Cheng /* request the primary MAC address */ 6018275SEric Cheng if ((err = mac_unicast_primary_add(dlp->dl_mch, &dlp->dl_mah, 6028275SEric Cheng &diag)) != 0) { 6038275SEric Cheng return (err); 6048275SEric Cheng } 6058275SEric Cheng 6068275SEric Cheng /* 6078275SEric Cheng * Set the function to start receiving packets. 6088275SEric Cheng */ 6098275SEric Cheng mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp); 6105895Syz147064 } 6115895Syz147064 dlp->dl_nactive++; 6128275SEric Cheng return (0); 6135895Syz147064 } 6145895Syz147064 6155895Syz147064 void 6165895Syz147064 dls_mac_active_clear(dls_link_t *dlp) 6175895Syz147064 { 6188275SEric Cheng if (--dlp->dl_nactive == 0) { 6198275SEric Cheng ASSERT(dlp->dl_mah != NULL); 6208275SEric Cheng (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah); 6218275SEric Cheng dlp->dl_mah = NULL; 6228275SEric Cheng mac_rx_clear(dlp->dl_mch); 6238275SEric Cheng } 6245895Syz147064 } 6255895Syz147064 6268275SEric Cheng int 6278275SEric Cheng dls_active_set(dld_str_t *dsp) 6280Sstevel@tonic-gate { 6298275SEric Cheng int err = 0; 6300Sstevel@tonic-gate 6318275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* If we're already active, then there's nothing more to do. */ 6348275SEric Cheng if (dsp->ds_active) 6358275SEric Cheng return (0); 6368275SEric Cheng 6378275SEric Cheng if ((err = dls_mac_active_set(dsp->ds_dlp)) != 0) { 6388275SEric Cheng /* except for ENXIO all other errors are mapped to EBUSY */ 6398275SEric Cheng if (err != ENXIO) 6408275SEric Cheng return (EBUSY); 6418275SEric Cheng return (err); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6448275SEric Cheng dsp->ds_active = B_TRUE; 6458275SEric Cheng return (0); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate void 6498275SEric Cheng dls_active_clear(dld_str_t *dsp) 6500Sstevel@tonic-gate { 6518275SEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 6520Sstevel@tonic-gate 6538275SEric Cheng if (!dsp->ds_active) 6548275SEric Cheng return; 6550Sstevel@tonic-gate 6568275SEric Cheng dls_mac_active_clear(dsp->ds_dlp); 6578275SEric Cheng dsp->ds_active = B_FALSE; 6580Sstevel@tonic-gate } 659