dls.c revision 605445d5657096e69d948ccb554c9ff024fa34df
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Data-Link Services Module
*/
#include <sys/sysmacros.h>
#include <sys/ethernet.h>
#include <sys/byteorder.h>
#include <sys/dls_impl.h>
#include <sys/dls_soft_ring.h>
static kmem_cache_t *i_dls_impl_cachep;
static uint32_t i_dls_impl_count;
struct dls_kstats dls_kstat =
{
{ "soft_ring_pkt_drop", KSTAT_DATA_UINT32 },
};
/*
* Private functions.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static void
{
}
static void
{
switch (type) {
case MAC_NOTE_UNICST:
break;
case MAC_NOTE_PROMISC:
/*
* Every time the MAC interface changes promiscuity we
* need to reset our transmit information.
*/
break;
}
}
static void
{
"net", KSTAT_TYPE_NAMED,
sizeof (dls_kstat) / sizeof (kstat_named_t),
KSTAT_FLAG_VIRTUAL)) == NULL) {
"DLS: failed to create kstat structure for dls stats");
return;
}
}
static void
{
}
/*
* Module initialization functions.
*/
void
dls_init(void)
{
/*
* Create a kmem_cache of dls_impl_t.
*/
}
int
dls_fini(void)
{
/*
* If there are any dls_impl_t in use then return EBUSY.
*/
if (i_dls_impl_count != 0)
return (EBUSY);
/*
* Destroy the kmem_cache.
*/
return (0);
}
/*
* Client function.
*/
int
{
}
int
dls_destroy(const char *name)
{
return (dls_vlan_destroy(name));
}
int
{
int err;
/*
* Get a reference to the named dls_vlan_t.
* Tagged vlans get created automatically.
*/
return (err);
/*
* Allocate a new dls_impl_t.
*/
/*
* Cache a copy of the MAC interface handle, a pointer to the
* immutable MAC info and a copy of the current MAC address.
*/
/*
* Set the MAC transmit information.
*/
/*
* Add a notification function so that we get updates from the MAC.
*/
/*
* Bump the kmem_cache count to make sure it is not prematurely
* destroyed.
*/
/*
* Hand back a reference to the dls_impl_t.
*/
return (0);
}
void
{
/*
* Remove the notify function.
*/
/*
* If the dls_impl_t is bound then unbind it.
*/
}
/*
* Walk the list of multicast addresses, disabling each at the MAC.
*/
kmem_free(p, sizeof (dls_multicst_addr_t));
}
/*
* If the MAC has been set in promiscuous mode then disable it.
*/
(void) dls_promisc(dc, 0);
/*
* Free the dls_impl_t back to the cache.
*/
}
dip->di_soft_ring_size = 0;
/*
* Decrement the reference count to allow the cache to be destroyed
* if there are no more dls_impl_t.
*/
/*
* Release our reference to the dls_vlan_t allowing that to be
* destroyed if there are no more dls_impl_t. An unreferenced tagged
* vlan gets destroyed automatically.
*/
}
{
}
{
}
int
{
/*
* Check to see the value is legal for the media type.
*/
return (EINVAL);
/*
* Set up the dls_impl_t to mark it as able to receive packets.
*/
/*
* Now bind the dls_impl_t by adding it into the hash table in the
* dls_link_t.
*
* NOTE: This must be done without the dls_impl_t lock being held
* otherwise deadlock may ensue.
*/
return (0);
}
void
{
/*
* Unbind the dls_impl_t by removing it from the hash table in the
* dls_link_t.
*
* NOTE: This must be done without the dls_impl_t lock being held
* otherise deadlock may enuse.
*/
/*
* Mark the dls_impl_t as unable to receive packets This will make
* sure that 'receives in flight' will not come our way.
*/
}
int
{
int err = 0;
DLS_PROMISC_PHYS)));
/*
* Check if we need to turn on 'all sap' mode.
*/
if ((flags & DLS_PROMISC_SAP) &&
goto multi;
goto multi;
}
/*
* Check if we need to turn off 'all sap' mode.
*/
if (!(flags & DLS_PROMISC_SAP) &&
goto multi;
}
/*
* It's easiest to add the txloop handler up-front; if promiscuous
* mode cannot be enabled, then we'll remove it before returning.
* Use dl_promisc_lock to prevent racing with another thread also
* manipulating the promiscuous state on another dls_impl_t associated
* with the same dls_link_t.
*/
if (dlp->dl_npromisc == 0 &&
}
/*
* Turn on or off 'all multicast' mode, if necessary.
*/
if (flags & DLS_PROMISC_MULTI) {
if (err != 0)
goto done;
dlp->dl_npromisc++;
}
} else {
if (err != 0)
goto done;
dlp->dl_npromisc--;
}
}
/*
* Turn on or off 'all physical' mode, if necessary.
*/
if (flags & DLS_PROMISC_PHYS) {
if (err != 0)
goto done;
dlp->dl_npromisc++;
}
} else {
if (err != 0)
goto done;
dlp->dl_npromisc--;
}
}
done:
}
return (err);
}
int
{
int err;
/*
* Check whether the address is in the list of enabled addresses for
* this dls_impl_t.
*/
/*
* It is there so there's nothing to do.
*/
err = 0;
goto done;
}
}
/*
* Allocate a new list item.
*/
if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t),
KM_NOSLEEP)) == NULL) {
goto done;
}
/*
* Enable the address at the MAC.
*/
kmem_free(p, sizeof (dls_multicst_addr_t));
goto done;
}
/*
* The address is now enabled at the MAC so add it to the list.
*/
*pp = p;
done:
return (err);
}
int
{
int err;
/*
* Find the address in the list of enabled addresses for this
* dls_impl_t.
*/
break;
}
/*
* If we walked to the end of the list then the given address is
* not currently enabled for this dls_impl_t.
*/
if (p == NULL) {
goto done;
}
/*
* Disable the address at the MAC.
*/
goto done;
/*
* Remove the address from the list.
*/
kmem_free(p, sizeof (dls_multicst_addr_t));
done:
return (err);
}
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);
}
int
{
}
void
{
}
mblk_t *
{
}
void **di_rx_arg)
{
/*
* We must not accept packets if the dls_impl_t is not marked as bound
* or is being removed.
*/
goto refuse;
/*
* If the dls_impl_t is in 'all physical' mode then always accept.
*/
goto accept;
switch (mhip->mhi_dsttype) {
case MAC_ADDRTYPE_UNICAST:
/*
* Check to see if the destination address matches the
* dls_impl_t unicast address.
*/
0) {
goto accept;
}
break;
case MAC_ADDRTYPE_MULTICAST:
/*
* Check the address against the list of addresses enabled
* for this dls_impl_t or accept it unconditionally if the
* dls_impl_t is in 'all multicast' mode.
*/
goto accept;
addr_length) == 0) {
goto accept;
}
}
break;
case MAC_ADDRTYPE_BROADCAST:
/*
* If the address is broadcast then the dls_impl_t will
* always accept it.
*/
goto accept;
}
return (B_FALSE);
/*
* Since we hold di_lock here, the returned di_rx and di_rx_arg will
* always be in sync.
*/
return (B_TRUE);
}
/* ARGSUSED */
void **di_rx_arg)
{
/*
* We must not accept packets if the dls_impl_t is not marked as bound
* or is being removed.
*/
goto refuse;
/*
* A dls_impl_t should only accept loopback packets if it is in
* 'all physical' mode.
*/
goto accept;
return (B_FALSE);
/*
* Since we hold di_lock here, the returned di_rx and di_rx_arg will
* always be in sync.
*/
return (B_TRUE);
}
{
/* If we're already active, then there's nothing more to do. */
return (B_TRUE);
}
/*
* If this is the first active client on this link, notify
* the mac that we're becoming an active client.
*/
return (B_FALSE);
}
dlp->dl_nactive++;
return (B_TRUE);
}
void
{
goto out;
if (--dlp->dl_nactive == 0)
out:
}