dls.c revision da14cebe459d3275048785f25bd869cb09b5307f
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Data-Link Services Module
*/
#include <sys/dld_impl.h>
int
{
/*
* Check whether this client belongs to the zone of this dlp. Note that
* a global zone client is allowed to open a local zone dlp.
*/
return (ENOENT);
/*
* Cache a copy of the MAC interface handle, a pointer to the
* immutable MAC info.
*/
return (0);
}
void
{
dlp->dl_zone_ref--;
/*
* Walk the list of multicast addresses, disabling each at the MAC.
* Note that we must remove multicast address before
* mac_unicast_remove() (called by dls_active_clear()) because
* mac_multicast_remove() relies on the unicast flows on the mac
* client.
*/
kmem_free(p, sizeof (dls_multicst_addr_t));
}
/*
* If the dld_str_t is bound then unbind it.
*/
(void) dls_unbind(dsp);
}
/*
* If the MAC has been set in promiscuous mode then disable it.
* This needs to be done before resetting ds_rx.
*/
dsp->ds_promisc = 0;
/*
* At this point we have cutoff inbound packet flow from the mac
* for this 'dsp'. The dls_link_remove above cut off packets meant
* for us and waited for upcalls to finish. Similarly the dls_promisc
* reset above waited for promisc callbacks to finish. Now we can
* safely reset ds_rx to NULL
*/
/*
* Release our reference to the dls_link_t allowing that to be
* destroyed if there are no more dls_impl_t.
*/
}
int
{
/*
* Check to see the value is legal for the media type.
*/
return (EINVAL);
/*
* Set up the dld_str_t to mark it as able to receive packets.
*/
/*
* The MAC layer does the VLAN demultiplexing and will only pass up
* untagged packets to non-promiscuous primary MAC clients. In order to
* support the binding to the VLAN SAP which is required by DLPI, dls
* needs to get a copy of all tagged packets when the client binds to
* the VLAN SAP. We do this by registering a separate promiscuous
* callback for each dls client binding to that SAP.
*
* Note: even though there are two promiscuous handles in dld_str_t,
* ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
* to receive VLAN pkt when promiscuous mode is not on. Only one of
* them can be non-NULL at the same time, to avoid receiving dup copies
* of pkts.
*/
int err;
return (EINVAL);
return (err);
}
/*
* Now bind the dld_str_t by adding it into the hash table in the
* dls_link_t.
*/
return (0);
}
int
{
/*
* For VLAN SAP, there was a promisc handle registered when dls_bind.
* When unbind this dls link, we need to remove the promisc handle.
* See comments in dls_bind().
*/
int err;
return (err);
}
/*
* Unbind the dld_str_t by removing it from the hash table in the
* dls_link_t.
*/
return (0);
}
int
{
int err = 0;
DLS_PROMISC_PHYS)));
/*
* If only DLS_PROMISC_SAP, we don't turn on the
* physical promisc mode
*/
if (err != 0)
return (err);
/* Remove vlan promisc handle to avoid sending dup copy up */
}
/*
* The failure only relates to resetting the device promiscuity
* The mac layer does not fail in freeing up the promiscuous
* data structures, and so we clear the ds_mph. The dld stream
* may be closing and we can't fail that.
*/
if (err != 0)
return (err);
int err;
return (EINVAL);
return (err);
}
/*
* If the old flag is PROMISC_SAP, but the current flag has
* changed to some new non-zero value, we need to turn the
* physical promiscuous mode.
*/
if (err != 0)
return (err);
}
return (err);
}
int
{
int err;
/*
* Check whether the address is in the list of enabled addresses for
* this dld_str_t.
*/
/*
* Protect against concurrent access of ds_dmap by data threads using
* ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
* remove operations. Dropping the ds_rw_lock across mac calls is thus
* ok and is also required by the locking protocol.
*/
/*
* It is there so there's nothing to do.
*/
err = 0;
goto done;
}
}
/*
* Allocate a new list item and add it to the list.
*/
*pp = p;
/*
* Enable the address at the MAC.
*/
if (err == 0)
return (0);
/* Undo the operation as it has failed */
kmem_free(p, sizeof (dls_multicst_addr_t));
done:
return (err);
}
int
{
/*
* Find the address in the list of enabled addresses for this
* dld_str_t.
*/
/*
* Protect against concurrent access to ds_dmap by data threads using
* ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
* remove operations. Dropping the ds_rw_lock across mac calls is thus
* ok and is also required by the locking protocol.
*/
break;
}
/*
* If we walked to the end of the list then the given address is
* not currently enabled for this dld_str_t.
*/
if (p == NULL) {
return (ENOENT);
}
/*
* Remove the address from the list.
*/
/*
* Disable the address at the MAC.
*/
kmem_free(p, sizeof (dls_multicst_addr_t));
return (0);
}
mblk_t *
{
struct ether_vlan_header *evhp;
/*
* If the following conditions are satisfied:
* - This is not a ETHERTYPE_VLAN listener; and
* - This is either a VLAN stream or this is a physical stream
* but the priority is not 0.
*
* then we know ahead of time that we'll need to fill in additional
* VLAN information in the link-layer header. We will tell the MAC
* layer to pre-allocate some space at the end of the Ethernet
* header for us.
*/
extra_len = sizeof (struct ether_vlan_header) -
sizeof (struct ether_header);
} else {
extra_len = 0;
}
return (NULL);
return (mp);
/*
* Fill in the tag information.
*/
if (extra_len != 0) {
} else {
/*
* The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
* in the payload. Update the priority.
*/
struct ether_vlan_extinfo *extinfo;
/*
* Because some DLS consumers only check the db_ref
* count of the first mblk, we pullup 'payload' into
* a single mblk.
*/
return (NULL);
} else {
}
}
}
return (mp);
}
void
{
}
static boolean_t
{
/*
* We must not accept packets if the dld_str_t is not marked as bound
* or is being removed.
*/
goto refuse;
if (dsp->ds_promisc != 0) {
/*
* Filter out packets that arrived from the data path
* (i_dls_link_rx) when promisc mode is on.
*/
if (!promisc)
goto refuse;
/*
* If the dls_impl_t is in 'all physical' mode then
* always accept.
*/
goto accept;
/*
* Loopback packets i.e. packets sent out by DLS on a given
* mac end point, will be accepted back by DLS on loopback
* from the mac, only in the 'all physical' mode which has been
* covered by the previous check above
*/
if (promisc_loopback)
goto refuse;
}
switch (mhip->mhi_dsttype) {
case MAC_ADDRTYPE_UNICAST:
case MAC_ADDRTYPE_BROADCAST:
/*
* We can accept unicast and broadcast packets because
* filtering is already done by the mac layer.
*/
goto accept;
case MAC_ADDRTYPE_MULTICAST:
/*
* Additional filtering is needed for multicast addresses
* because different streams may be interested in different
* addresses.
*/
goto accept;
addr_length) == 0) {
goto accept;
}
}
break;
}
return (B_FALSE);
/*
* the returned ds_rx and ds_rx_arg will always be in sync.
*/
return (B_TRUE);
}
/* ARGSUSED */
void **ds_rx_arg)
{
B_FALSE));
}
{
loopback));
}
int
{
int err = 0;
/*
* First client; add the primary unicast address.
*/
if (dlp->dl_nactive == 0) {
/*
* First client; add the primary unicast address.
*/
/* request the primary MAC address */
&diag)) != 0) {
return (err);
}
/*
* Set the function to start receiving packets.
*/
/*
* We've got a MAC client for this link now.
* Push down the flows that were defined on this link
* hitherto. The flows are added to the active flow table
* and SRS, softrings etc. are created as needed.
*/
}
dlp->dl_nactive++;
return (0);
}
void
{
if (--dlp->dl_nactive == 0) {
/*
* We would have initialized subflows etc. only if we
* brought up the primary client and set the unicast
* unicast address etc. Deactivate the flows. The flow
* entry will be removed from the active flow tables,
* and the associated SRS, softrings etc will be
* deleted. But the flow entry itself won't be
* destroyed, instead it will continue to be
* archived off the the global flow hash list, for a
* possible future activation when say
* IP is plumbed again
*/
}
}
int
{
int err = 0;
/* If we're already active, then there's nothing more to do. */
return (0);
/* except for ENXIO all other errors are mapped to EBUSY */
return (EBUSY);
return (err);
}
return (0);
}
void
{
return;
}