Home | History | Annotate | Download | only in dls
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   1502   ericheng  * Common Development and Distribution License (the "License").
      6   1502   ericheng  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   8833       Venu  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel /*
     27      0     stevel  * Data-Link Services Module
     28      0     stevel  */
     29      0     stevel 
     30      0     stevel #include	<sys/strsun.h>
     31      0     stevel #include	<sys/vlan.h>
     32   8275       Eric #include	<sys/dld_impl.h>
     33   8893    Michael #include	<sys/mac_client_priv.h>
     34      0     stevel 
     35   8275       Eric int
     36   8275       Eric dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
     37   8275       Eric {
     38   8275       Eric 	zoneid_t	zid = getzoneid();
     39   8275       Eric 	boolean_t	local;
     40   8893    Michael 	int		err;
     41      0     stevel 
     42   8275       Eric 	/*
     43   8275       Eric 	 * Check whether this client belongs to the zone of this dlp. Note that
     44   8275       Eric 	 * a global zone client is allowed to open a local zone dlp.
     45   8275       Eric 	 */
     46   8275       Eric 	if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
     47   8275       Eric 		return (ENOENT);
     48   8893    Michael 
     49   9073      Cathy 	/*
     50   9073      Cathy 	 * mac_start() is required for non-legacy MACs to show accurate
     51   9073      Cathy 	 * kstats even before the interface is brought up. For legacy
     52   9073      Cathy 	 * drivers, this is not needed. Further, calling mac_start() for
     53   9073      Cathy 	 * legacy drivers would make the shared-lower-stream to stay in
     54   9073      Cathy 	 * the DL_IDLE state, which in turn causes performance regression.
     55   9073      Cathy 	 */
     56   9073      Cathy 	if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
     57   9073      Cathy 	    ((err = mac_start(dlp->dl_mh)) != 0)) {
     58   8893    Michael 		return (err);
     59   9073      Cathy 	}
     60   1184     krgopi 
     61   8275       Eric 	local = (zid == dlp->dl_zid);
     62   8275       Eric 	dlp->dl_zone_ref += (local ? 1 : 0);
     63   5895   yz147064 
     64   8275       Eric 	/*
     65   8275       Eric 	 * Cache a copy of the MAC interface handle, a pointer to the
     66   8275       Eric 	 * immutable MAC info.
     67   8275       Eric 	 */
     68   8275       Eric 	dsp->ds_dlp = dlp;
     69   8275       Eric 	dsp->ds_mh = dlp->dl_mh;
     70   8275       Eric 	dsp->ds_mch = dlp->dl_mch;
     71   8275       Eric 	dsp->ds_mip = dlp->dl_mip;
     72   8275       Eric 	dsp->ds_ddh = ddh;
     73   8275       Eric 	dsp->ds_local = local;
     74      0     stevel 
     75   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
     76      0     stevel 	return (0);
     77      0     stevel }
     78      0     stevel 
     79   8275       Eric void
     80   8275       Eric dls_close(dld_str_t *dsp)
     81      0     stevel {
     82   8275       Eric 	dls_link_t		*dlp = dsp->ds_dlp;
     83   8275       Eric 	dls_multicst_addr_t	*p;
     84   8275       Eric 	dls_multicst_addr_t	*nextp;
     85   8275       Eric 	uint32_t		old_flags;
     86      0     stevel 
     87   8275       Eric 	ASSERT(dsp->ds_datathr_cnt == 0);
     88   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
     89      0     stevel 
     90   8275       Eric 	if (dsp->ds_local)
     91   8275       Eric 		dlp->dl_zone_ref--;
     92   8275       Eric 	dsp->ds_local = B_FALSE;
     93      0     stevel 
     94   8275       Eric 	/*
     95   8275       Eric 	 * Walk the list of multicast addresses, disabling each at the MAC.
     96   8275       Eric 	 * Note that we must remove multicast address before
     97   8275       Eric 	 * mac_unicast_remove() (called by dls_active_clear()) because
     98   8275       Eric 	 * mac_multicast_remove() relies on the unicast flows on the mac
     99   8275       Eric 	 * client.
    100   8275       Eric 	 */
    101   8275       Eric 	for (p = dsp->ds_dmap; p != NULL; p = nextp) {
    102   8275       Eric 		(void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
    103   8275       Eric 		nextp = p->dma_nextp;
    104   8275       Eric 		kmem_free(p, sizeof (dls_multicst_addr_t));
    105   8275       Eric 	}
    106   8275       Eric 	dsp->ds_dmap = NULL;
    107      0     stevel 
    108   9073      Cathy 	dls_active_clear(dsp, B_TRUE);
    109      0     stevel 
    110   8275       Eric 	/*
    111   8275       Eric 	 * If the dld_str_t is bound then unbind it.
    112   8275       Eric 	 */
    113   8275       Eric 	if (dsp->ds_dlstate == DL_IDLE) {
    114   9044     Girish 		dls_unbind(dsp);
    115   8275       Eric 		dsp->ds_dlstate = DL_UNBOUND;
    116      0     stevel 	}
    117      0     stevel 
    118   8275       Eric 	/*
    119   8275       Eric 	 * If the MAC has been set in promiscuous mode then disable it.
    120   8275       Eric 	 * This needs to be done before resetting ds_rx.
    121   8275       Eric 	 */
    122   8275       Eric 	old_flags = dsp->ds_promisc;
    123   8275       Eric 	dsp->ds_promisc = 0;
    124   8275       Eric 	(void) dls_promisc(dsp, old_flags);
    125   1184     krgopi 
    126   8275       Eric 	/*
    127   8275       Eric 	 * At this point we have cutoff inbound packet flow from the mac
    128   8275       Eric 	 * for this 'dsp'. The dls_link_remove above cut off packets meant
    129   8275       Eric 	 * for us and waited for upcalls to finish. Similarly the dls_promisc
    130   8275       Eric 	 * reset above waited for promisc callbacks to finish. Now we can
    131   8275       Eric 	 * safely reset ds_rx to NULL
    132   8275       Eric 	 */
    133   8275       Eric 	dsp->ds_rx = NULL;
    134   8275       Eric 	dsp->ds_rx_arg = NULL;
    135   1184     krgopi 
    136   8275       Eric 	dsp->ds_dlp = NULL;
    137   8893    Michael 
    138   9073      Cathy 	if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
    139   9073      Cathy 		mac_stop(dsp->ds_mh);
    140      0     stevel 
    141      0     stevel 	/*
    142   8275       Eric 	 * Release our reference to the dls_link_t allowing that to be
    143   8275       Eric 	 * destroyed if there are no more dls_impl_t.
    144      0     stevel 	 */
    145   8275       Eric 	dls_link_rele(dlp);
    146      0     stevel }
    147      0     stevel 
    148      0     stevel int
    149   8275       Eric dls_bind(dld_str_t *dsp, uint32_t sap)
    150      0     stevel {
    151   8275       Eric 	uint32_t	dls_sap;
    152   8275       Eric 
    153   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    154      0     stevel 
    155      0     stevel 	/*
    156   8275       Eric 	 * Check to see the value is legal for the media type.
    157      0     stevel 	 */
    158   8275       Eric 	if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
    159   8275       Eric 		return (EINVAL);
    160   8275       Eric 
    161   8275       Eric 	if (dsp->ds_promisc & DLS_PROMISC_SAP)
    162   8275       Eric 		dls_sap = DLS_SAP_PROMISC;
    163   8275       Eric 
    164   8275       Eric 	/*
    165   8275       Eric 	 * Set up the dld_str_t to mark it as able to receive packets.
    166   8275       Eric 	 */
    167   8275       Eric 	dsp->ds_sap = sap;
    168   8275       Eric 
    169   8275       Eric 	/*
    170   8275       Eric 	 * The MAC layer does the VLAN demultiplexing and will only pass up
    171   8275       Eric 	 * untagged packets to non-promiscuous primary MAC clients. In order to
    172   8275       Eric 	 * support the binding to the VLAN SAP which is required by DLPI, dls
    173   8275       Eric 	 * needs to get a copy of all tagged packets when the client binds to
    174   8275       Eric 	 * the VLAN SAP. We do this by registering a separate promiscuous
    175   8275       Eric 	 * callback for each dls client binding to that SAP.
    176   8275       Eric 	 *
    177   8275       Eric 	 * Note: even though there are two promiscuous handles in dld_str_t,
    178   8275       Eric 	 * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
    179   8275       Eric 	 * to receive VLAN pkt when promiscuous mode is not on. Only one of
    180   8275       Eric 	 * them can be non-NULL at the same time, to avoid receiving dup copies
    181   8275       Eric 	 * of pkts.
    182   8275       Eric 	 */
    183   8275       Eric 	if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
    184   8275       Eric 		int err;
    185   8275       Eric 
    186   8275       Eric 		if (dsp->ds_vlan_mph != NULL)
    187   8275       Eric 			return (EINVAL);
    188   8275       Eric 		err = mac_promisc_add(dsp->ds_mch,
    189   8275       Eric 		    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
    190   8275       Eric 		    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
    191  11021       Eric 
    192  11021       Eric 		if (err == 0 && dsp->ds_nonip &&
    193  11021       Eric 		    dsp->ds_dlp->dl_nonip_cnt++ == 0)
    194  11021       Eric 			mac_rx_bypass_disable(dsp->ds_mch);
    195  11021       Eric 
    196   8275       Eric 		return (err);
    197   8275       Eric 	}
    198   8275       Eric 
    199   8275       Eric 	/*
    200   8275       Eric 	 * Now bind the dld_str_t by adding it into the hash table in the
    201   8275       Eric 	 * dls_link_t.
    202   8275       Eric 	 */
    203   8275       Eric 	dls_link_add(dsp->ds_dlp, dls_sap, dsp);
    204  11021       Eric 	if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
    205  11021       Eric 		mac_rx_bypass_disable(dsp->ds_mch);
    206  11021       Eric 
    207      0     stevel 	return (0);
    208      0     stevel }
    209      0     stevel 
    210   9044     Girish void
    211   8275       Eric dls_unbind(dld_str_t *dsp)
    212      0     stevel {
    213   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    214  11021       Eric 
    215  11021       Eric 	if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
    216  11021       Eric 		mac_rx_bypass_enable(dsp->ds_mch);
    217   5895   yz147064 
    218   5895   yz147064 	/*
    219   8275       Eric 	 * For VLAN SAP, there was a promisc handle registered when dls_bind.
    220   8275       Eric 	 * When unbind this dls link, we need to remove the promisc handle.
    221   8275       Eric 	 * See comments in dls_bind().
    222   5895   yz147064 	 */
    223   8275       Eric 	if (dsp->ds_vlan_mph != NULL) {
    224   9044     Girish 		mac_promisc_remove(dsp->ds_vlan_mph);
    225   8275       Eric 		dsp->ds_vlan_mph = NULL;
    226   9044     Girish 		return;
    227   8275       Eric 	}
    228   5895   yz147064 
    229   8275       Eric 	/*
    230   8275       Eric 	 * Unbind the dld_str_t by removing it from the hash table in the
    231   8275       Eric 	 * dls_link_t.
    232   8275       Eric 	 */
    233   8275       Eric 	dls_link_remove(dsp->ds_dlp, dsp);
    234   8275       Eric 	dsp->ds_sap = 0;
    235      0     stevel }
    236      0     stevel 
    237      0     stevel int
    238   8275       Eric dls_promisc(dld_str_t *dsp, uint32_t old_flags)
    239      0     stevel {
    240   8275       Eric 	int		err = 0;
    241      0     stevel 
    242   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    243   8275       Eric 	ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
    244   8275       Eric 	    DLS_PROMISC_PHYS)));
    245   5895   yz147064 
    246   8275       Eric 	if (old_flags == 0 && dsp->ds_promisc != 0) {
    247   8275       Eric 		/*
    248   8275       Eric 		 * If only DLS_PROMISC_SAP, we don't turn on the
    249   8275       Eric 		 * physical promisc mode
    250   8275       Eric 		 */
    251   8275       Eric 		err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
    252   8275       Eric 		    dls_rx_promisc, dsp, &dsp->ds_mph,
    253   8275       Eric 		    (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
    254   8275       Eric 		    MAC_PROMISC_FLAGS_NO_PHYS);
    255   8275       Eric 		if (err != 0)
    256   8275       Eric 			return (err);
    257   8275       Eric 
    258   8275       Eric 		/* Remove vlan promisc handle to avoid sending dup copy up */
    259   8275       Eric 		if (dsp->ds_vlan_mph != NULL) {
    260   9044     Girish 			mac_promisc_remove(dsp->ds_vlan_mph);
    261   8275       Eric 			dsp->ds_vlan_mph = NULL;
    262   8275       Eric 		}
    263   8275       Eric 	} else if (old_flags != 0 && dsp->ds_promisc == 0) {
    264   8275       Eric 		ASSERT(dsp->ds_mph != NULL);
    265   9044     Girish 
    266   9044     Girish 		mac_promisc_remove(dsp->ds_mph);
    267   8275       Eric 		dsp->ds_mph = NULL;
    268   8275       Eric 
    269   8275       Eric 		if (dsp->ds_sap == ETHERTYPE_VLAN &&
    270   8275       Eric 		    dsp->ds_dlstate != DL_UNBOUND) {
    271   8275       Eric 			int err;
    272   8275       Eric 
    273   8275       Eric 			if (dsp->ds_vlan_mph != NULL)
    274   8275       Eric 				return (EINVAL);
    275   8275       Eric 			err = mac_promisc_add(dsp->ds_mch,
    276   8275       Eric 			    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
    277   8275       Eric 			    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
    278   8275       Eric 			return (err);
    279   8275       Eric 		}
    280   8275       Eric 	} else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
    281   8275       Eric 	    dsp->ds_promisc != old_flags) {
    282   8275       Eric 		/*
    283   8275       Eric 		 * If the old flag is PROMISC_SAP, but the current flag has
    284   8275       Eric 		 * changed to some new non-zero value, we need to turn the
    285   8275       Eric 		 * physical promiscuous mode.
    286   8275       Eric 		 */
    287   8275       Eric 		ASSERT(dsp->ds_mph != NULL);
    288   9044     Girish 		mac_promisc_remove(dsp->ds_mph);
    289   8275       Eric 		err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
    290   8275       Eric 		    dls_rx_promisc, dsp, &dsp->ds_mph, 0);
    291   5895   yz147064 	}
    292   5895   yz147064 
    293   5895   yz147064 	return (err);
    294   5895   yz147064 }
    295   5895   yz147064 
    296   8275       Eric int
    297   8275       Eric dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
    298   5895   yz147064 {
    299      0     stevel 	int			err;
    300      0     stevel 	dls_multicst_addr_t	**pp;
    301      0     stevel 	dls_multicst_addr_t	*p;
    302      0     stevel 	uint_t			addr_length;
    303      0     stevel 
    304   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    305   8275       Eric 
    306      0     stevel 	/*
    307      0     stevel 	 * Check whether the address is in the list of enabled addresses for
    308   8275       Eric 	 * this dld_str_t.
    309      0     stevel 	 */
    310   8275       Eric 	addr_length = dsp->ds_mip->mi_addr_length;
    311   8275       Eric 
    312   8275       Eric 	/*
    313   8275       Eric 	 * Protect against concurrent access of ds_dmap by data threads using
    314   8275       Eric 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
    315   8275       Eric 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
    316   8275       Eric 	 * ok and is also required by the locking protocol.
    317   8275       Eric 	 */
    318   8275       Eric 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    319   8275       Eric 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
    320      0     stevel 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
    321      0     stevel 			/*
    322      0     stevel 			 * It is there so there's nothing to do.
    323      0     stevel 			 */
    324      0     stevel 			err = 0;
    325      0     stevel 			goto done;
    326      0     stevel 		}
    327      0     stevel 	}
    328      0     stevel 
    329      0     stevel 	/*
    330   8275       Eric 	 * Allocate a new list item and add it to the list.
    331      0     stevel 	 */
    332   8275       Eric 	p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
    333   8275       Eric 	bcopy(addr, p->dma_addr, addr_length);
    334   8275       Eric 	*pp = p;
    335   8275       Eric 	rw_exit(&dsp->ds_rw_lock);
    336      0     stevel 
    337      0     stevel 	/*
    338      0     stevel 	 * Enable the address at the MAC.
    339      0     stevel 	 */
    340   8275       Eric 	err = mac_multicast_add(dsp->ds_mch, addr);
    341   8275       Eric 	if (err == 0)
    342   8275       Eric 		return (0);
    343      0     stevel 
    344   8275       Eric 	/* Undo the operation as it has failed */
    345   8275       Eric 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    346   8275       Eric 	ASSERT(*pp == p && p->dma_nextp == NULL);
    347   8275       Eric 	*pp = NULL;
    348   8275       Eric 	kmem_free(p, sizeof (dls_multicst_addr_t));
    349      0     stevel done:
    350   8275       Eric 	rw_exit(&dsp->ds_rw_lock);
    351      0     stevel 	return (err);
    352      0     stevel }
    353      0     stevel 
    354      0     stevel int
    355   8275       Eric dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
    356      0     stevel {
    357      0     stevel 	dls_multicst_addr_t	**pp;
    358      0     stevel 	dls_multicst_addr_t	*p;
    359      0     stevel 	uint_t			addr_length;
    360      0     stevel 
    361   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    362   8275       Eric 
    363      0     stevel 	/*
    364      0     stevel 	 * Find the address in the list of enabled addresses for this
    365   8275       Eric 	 * dld_str_t.
    366      0     stevel 	 */
    367   8275       Eric 	addr_length = dsp->ds_mip->mi_addr_length;
    368   8275       Eric 
    369   8275       Eric 	/*
    370   8275       Eric 	 * Protect against concurrent access to ds_dmap by data threads using
    371   8275       Eric 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
    372   8275       Eric 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
    373   8275       Eric 	 * ok and is also required by the locking protocol.
    374   8275       Eric 	 */
    375   8275       Eric 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    376   8275       Eric 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
    377      0     stevel 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
    378      0     stevel 			break;
    379      0     stevel 	}
    380      0     stevel 
    381      0     stevel 	/*
    382      0     stevel 	 * If we walked to the end of the list then the given address is
    383   8275       Eric 	 * not currently enabled for this dld_str_t.
    384      0     stevel 	 */
    385      0     stevel 	if (p == NULL) {
    386   8275       Eric 		rw_exit(&dsp->ds_rw_lock);
    387   8275       Eric 		return (ENOENT);
    388      0     stevel 	}
    389      0     stevel 
    390      0     stevel 	/*
    391      0     stevel 	 * Remove the address from the list.
    392      0     stevel 	 */
    393      0     stevel 	*pp = p->dma_nextp;
    394   8275       Eric 	rw_exit(&dsp->ds_rw_lock);
    395   8275       Eric 
    396   8275       Eric 	/*
    397   8275       Eric 	 * Disable the address at the MAC.
    398   8275       Eric 	 */
    399   8275       Eric 	mac_multicast_remove(dsp->ds_mch, addr);
    400      0     stevel 	kmem_free(p, sizeof (dls_multicst_addr_t));
    401   8275       Eric 	return (0);
    402      0     stevel }
    403      0     stevel 
    404      0     stevel mblk_t *
    405   8275       Eric dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
    406   2760   dg199075     mblk_t **payloadp)
    407      0     stevel {
    408   2760   dg199075 	uint16_t vid;
    409   2760   dg199075 	size_t extra_len;
    410   2760   dg199075 	uint16_t mac_sap;
    411   2760   dg199075 	mblk_t *mp, *payload;
    412   8275       Eric 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
    413   2311        seb 	struct ether_vlan_header *evhp;
    414      0     stevel 
    415   8275       Eric 	vid = mac_client_vid(dsp->ds_mch);
    416   2760   dg199075 	payload = (payloadp == NULL) ? NULL : (*payloadp);
    417   2760   dg199075 
    418   2760   dg199075 	/*
    419   8874  Sebastien 	 * In the case of Ethernet, we need to tell mac_header() if we need
    420   8874  Sebastien 	 * extra room beyond the Ethernet header for a VLAN header.  We'll
    421   8874  Sebastien 	 * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
    422   8874  Sebastien 	 * (because such streams will be handling VLAN headers on their own)
    423   8874  Sebastien 	 * and one of the following conditions is satisfied:
    424   2760   dg199075 	 *
    425   8874  Sebastien 	 * - This is a VLAN stream
    426   8874  Sebastien 	 * - This is a physical stream, the priority is not 0, and user
    427   8874  Sebastien 	 *   priority tagging is allowed.
    428   2760   dg199075 	 */
    429   2760   dg199075 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
    430   8874  Sebastien 	    (vid != VLAN_ID_NONE ||
    431   8874  Sebastien 	    (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
    432   2311        seb 		extra_len = sizeof (struct ether_vlan_header) -
    433   2311        seb 		    sizeof (struct ether_header);
    434   2760   dg199075 		mac_sap = ETHERTYPE_VLAN;
    435   2311        seb 	} else {
    436   2311        seb 		extra_len = 0;
    437   2311        seb 		mac_sap = sap;
    438   2311        seb 	}
    439   2311        seb 
    440   8275       Eric 	mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
    441   2760   dg199075 	if (mp == NULL)
    442   2760   dg199075 		return (NULL);
    443   2760   dg199075 
    444   8874  Sebastien 	if ((vid == VLAN_ID_NONE && (pri == 0 ||
    445   8874  Sebastien 	    dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
    446   2311        seb 		return (mp);
    447   2311        seb 
    448   2760   dg199075 	/*
    449   2760   dg199075 	 * Fill in the tag information.
    450   2760   dg199075 	 */
    451   2311        seb 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
    452   2760   dg199075 	if (extra_len != 0) {
    453   2760   dg199075 		mp->b_wptr += extra_len;
    454   2760   dg199075 		evhp = (struct ether_vlan_header *)mp->b_rptr;
    455   2760   dg199075 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
    456   2760   dg199075 		evhp->ether_type = htons(sap);
    457   2760   dg199075 	} else {
    458   2760   dg199075 		/*
    459   2760   dg199075 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
    460   2760   dg199075 		 * in the payload. Update the priority.
    461   2760   dg199075 		 */
    462   2760   dg199075 		struct ether_vlan_extinfo *extinfo;
    463   2760   dg199075 		size_t len = sizeof (struct ether_vlan_extinfo);
    464   2760   dg199075 
    465   2760   dg199075 		ASSERT(sap == ETHERTYPE_VLAN);
    466   2760   dg199075 		ASSERT(payload != NULL);
    467   2760   dg199075 
    468   2760   dg199075 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
    469   2760   dg199075 			mblk_t *newmp;
    470   2760   dg199075 
    471   2760   dg199075 			/*
    472   2760   dg199075 			 * Because some DLS consumers only check the db_ref
    473   2760   dg199075 			 * count of the first mblk, we pullup 'payload' into
    474   2760   dg199075 			 * a single mblk.
    475   2760   dg199075 			 */
    476   2760   dg199075 			newmp = msgpullup(payload, -1);
    477   2760   dg199075 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
    478   2760   dg199075 				freemsg(newmp);
    479   2760   dg199075 				freemsg(mp);
    480   2760   dg199075 				return (NULL);
    481   2760   dg199075 			} else {
    482   2760   dg199075 				freemsg(payload);
    483   2760   dg199075 				*payloadp = payload = newmp;
    484   2760   dg199075 			}
    485   2760   dg199075 		}
    486   2760   dg199075 
    487   2760   dg199075 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
    488   2760   dg199075 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
    489   2760   dg199075 		    VLAN_ID(ntohs(extinfo->ether_tci))));
    490   2760   dg199075 	}
    491   2311        seb 	return (mp);
    492      0     stevel }
    493      0     stevel 
    494   8275       Eric void
    495   8275       Eric dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
    496      0     stevel {
    497   8275       Eric 	mutex_enter(&dsp->ds_lock);
    498   8275       Eric 	dsp->ds_rx = rx;
    499   8275       Eric 	dsp->ds_rx_arg = arg;
    500   8275       Eric 	mutex_exit(&dsp->ds_lock);
    501      0     stevel }
    502      0     stevel 
    503   8275       Eric static boolean_t
    504   8275       Eric dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    505   8275       Eric     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
    506      0     stevel {
    507      0     stevel 	dls_multicst_addr_t	*dmap;
    508   8275       Eric 	size_t			addr_length = dsp->ds_mip->mi_addr_length;
    509      0     stevel 
    510      0     stevel 	/*
    511   8275       Eric 	 * We must not accept packets if the dld_str_t is not marked as bound
    512      0     stevel 	 * or is being removed.
    513      0     stevel 	 */
    514   8275       Eric 	if (dsp->ds_dlstate != DL_IDLE)
    515      0     stevel 		goto refuse;
    516      0     stevel 
    517   8275       Eric 	if (dsp->ds_promisc != 0) {
    518   8275       Eric 		/*
    519   8275       Eric 		 * Filter out packets that arrived from the data path
    520   8275       Eric 		 * (i_dls_link_rx) when promisc mode is on.
    521   8275       Eric 		 */
    522   8275       Eric 		if (!promisc)
    523   8275       Eric 			goto refuse;
    524   8275       Eric 		/*
    525   8275       Eric 		 * If the dls_impl_t is in 'all physical' mode then
    526   8275       Eric 		 * always accept.
    527   8275       Eric 		 */
    528   8275       Eric 		if (dsp->ds_promisc & DLS_PROMISC_PHYS)
    529   8275       Eric 			goto accept;
    530      0     stevel 
    531   8275       Eric 		/*
    532   8275       Eric 		 * Loopback packets i.e. packets sent out by DLS on a given
    533   8275       Eric 		 * mac end point, will be accepted back by DLS on loopback
    534   8275       Eric 		 * from the mac, only in the 'all physical' mode which has been
    535   8275       Eric 		 * covered by the previous check above
    536   8275       Eric 		 */
    537   8275       Eric 		if (promisc_loopback)
    538   8275       Eric 			goto refuse;
    539   8275       Eric 	}
    540   5895   yz147064 
    541   2311        seb 	switch (mhip->mhi_dsttype) {
    542   2311        seb 	case MAC_ADDRTYPE_UNICAST:
    543   8275       Eric 	case MAC_ADDRTYPE_BROADCAST:
    544   2311        seb 		/*
    545   8275       Eric 		 * We can accept unicast and broadcast packets because
    546   8275       Eric 		 * filtering is already done by the mac layer.
    547   2311        seb 		 */
    548   8275       Eric 		goto accept;
    549   2311        seb 	case MAC_ADDRTYPE_MULTICAST:
    550   2311        seb 		/*
    551   8275       Eric 		 * Additional filtering is needed for multicast addresses
    552   8275       Eric 		 * because different streams may be interested in different
    553   8275       Eric 		 * addresses.
    554   2311        seb 		 */
    555   8275       Eric 		if (dsp->ds_promisc & DLS_PROMISC_MULTI)
    556   2311        seb 			goto accept;
    557   8275       Eric 
    558   8275       Eric 		rw_enter(&dsp->ds_rw_lock, RW_READER);
    559   8275       Eric 		for (dmap = dsp->ds_dmap; dmap != NULL;
    560   2311        seb 		    dmap = dmap->dma_nextp) {
    561   2311        seb 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
    562   2311        seb 			    addr_length) == 0) {
    563   8275       Eric 				rw_exit(&dsp->ds_rw_lock);
    564   2311        seb 				goto accept;
    565   2311        seb 			}
    566   2311        seb 		}
    567   8275       Eric 		rw_exit(&dsp->ds_rw_lock);
    568   2311        seb 		break;
    569      0     stevel 	}
    570      0     stevel 
    571      0     stevel refuse:
    572      0     stevel 	return (B_FALSE);
    573      0     stevel 
    574      0     stevel accept:
    575    449   ericheng 	/*
    576   8275       Eric 	 * the returned ds_rx and ds_rx_arg will always be in sync.
    577    449   ericheng 	 */
    578   8275       Eric 	mutex_enter(&dsp->ds_lock);
    579   8275       Eric 	*ds_rx = dsp->ds_rx;
    580   8275       Eric 	*ds_rx_arg = dsp->ds_rx_arg;
    581   8275       Eric 	mutex_exit(&dsp->ds_lock);
    582   8275       Eric 
    583      0     stevel 	return (B_TRUE);
    584      0     stevel }
    585      0     stevel 
    586   2760   dg199075 /* ARGSUSED */
    587      0     stevel boolean_t
    588   8275       Eric dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    589   8275       Eric     void **ds_rx_arg)
    590      0     stevel {
    591   8275       Eric 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
    592   8275       Eric 	    B_FALSE));
    593      0     stevel }
    594      0     stevel 
    595      0     stevel boolean_t
    596   8275       Eric dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    597   8275       Eric     void **ds_rx_arg, boolean_t loopback)
    598   8275       Eric {
    599   8275       Eric 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
    600   8275       Eric 	    loopback));
    601   8275       Eric }
    602   8275       Eric 
    603   8275       Eric int
    604   5895   yz147064 dls_mac_active_set(dls_link_t *dlp)
    605   5895   yz147064 {
    606   8275       Eric 	int err = 0;
    607   5895   yz147064 
    608   5895   yz147064 	/*
    609   8275       Eric 	 * First client; add the primary unicast address.
    610   5895   yz147064 	 */
    611   8275       Eric 	if (dlp->dl_nactive == 0) {
    612   8275       Eric 		/*
    613   8275       Eric 		 * First client; add the primary unicast address.
    614   8275       Eric 		 */
    615   8275       Eric 		mac_diag_t diag;
    616   8275       Eric 
    617   8275       Eric 		/* request the primary MAC address */
    618   9024       Venu 		if ((err = mac_unicast_add(dlp->dl_mch, NULL,
    619   9024       Venu 		    MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
    620   9024       Venu 		    MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
    621   8275       Eric 		    &diag)) != 0) {
    622   8275       Eric 			return (err);
    623   8275       Eric 		}
    624   8275       Eric 
    625   8275       Eric 		/*
    626   8275       Eric 		 * Set the function to start receiving packets.
    627   8275       Eric 		 */
    628   8275       Eric 		mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
    629   5895   yz147064 	}
    630   5895   yz147064 	dlp->dl_nactive++;
    631   8275       Eric 	return (0);
    632   5895   yz147064 }
    633   5895   yz147064 
    634   5895   yz147064 void
    635   5895   yz147064 dls_mac_active_clear(dls_link_t *dlp)
    636   5895   yz147064 {
    637   8275       Eric 	if (--dlp->dl_nactive == 0) {
    638   8275       Eric 		ASSERT(dlp->dl_mah != NULL);
    639   8275       Eric 		(void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
    640   8275       Eric 		dlp->dl_mah = NULL;
    641   8275       Eric 		mac_rx_clear(dlp->dl_mch);
    642   8275       Eric 	}
    643   5895   yz147064 }
    644   5895   yz147064 
    645   8275       Eric int
    646   8275       Eric dls_active_set(dld_str_t *dsp)
    647      0     stevel {
    648   8275       Eric 	int err = 0;
    649      0     stevel 
    650   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    651      0     stevel 
    652   9073      Cathy 	if (dsp->ds_passivestate == DLD_PASSIVE)
    653   8275       Eric 		return (0);
    654   8275       Eric 
    655   9073      Cathy 	/* If we're already active, then there's nothing more to do. */
    656   9073      Cathy 	if ((dsp->ds_nactive == 0) &&
    657   9073      Cathy 	    ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
    658   8275       Eric 		/* except for ENXIO all other errors are mapped to EBUSY */
    659   8275       Eric 		if (err != ENXIO)
    660   8275       Eric 			return (EBUSY);
    661   8275       Eric 		return (err);
    662      0     stevel 	}
    663      0     stevel 
    664   9073      Cathy 	dsp->ds_passivestate = DLD_ACTIVE;
    665   9073      Cathy 	dsp->ds_nactive++;
    666   8275       Eric 	return (0);
    667      0     stevel }
    668      0     stevel 
    669   9073      Cathy /*
    670   9073      Cathy  * Note that dls_active_set() is called whenever an active operation
    671   9073      Cathy  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
    672   9073      Cathy  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
    673   9073      Cathy  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
    674   9073      Cathy  * a stream is closed without every active operation being undone and we
    675   9073      Cathy  * need to clear all the "active" states by calling
    676   9073      Cathy  * dls_active_clear(dsp, B_TRUE).
    677   9073      Cathy  */
    678      0     stevel void
    679   9073      Cathy dls_active_clear(dld_str_t *dsp, boolean_t all)
    680      0     stevel {
    681   8275       Eric 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    682      0     stevel 
    683   9073      Cathy 	if (dsp->ds_passivestate == DLD_PASSIVE)
    684   8275       Eric 		return;
    685      0     stevel 
    686   9073      Cathy 	if (all && dsp->ds_nactive == 0)
    687   9073      Cathy 		return;
    688   9073      Cathy 
    689   9073      Cathy 	ASSERT(dsp->ds_nactive > 0);
    690   9073      Cathy 
    691   9073      Cathy 	dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
    692   9073      Cathy 	if (dsp->ds_nactive != 0)
    693   9073      Cathy 		return;
    694   9073      Cathy 
    695   9073      Cathy 	ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
    696   8275       Eric 	dls_mac_active_clear(dsp->ds_dlp);
    697   9073      Cathy 	dsp->ds_passivestate = DLD_UNINITIALIZED;
    698      0     stevel }
    699