mac.c revision 98b1442a0c93823c4eb547288dc55de7a294ee73
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* MAC Services Module
*/
#include <sys/mac_impl.h>
#include <sys/dld_impl.h>
static kmem_cache_t *i_mac_impl_cachep;
static ght_t i_mac_impl_hash;
/*
* Private functions.
*/
/*ARGSUSED*/
static boolean_t
{
/*
* Check the address is not a group address.
*/
if (addr[0] & 0x01)
return (B_FALSE);
return (B_TRUE);
}
static boolean_t
{
/*
* Check the address is a group address.
*/
if (!(addr[0] & 0x01))
return (B_FALSE);
/*
* Check the address is not the media broadcast address.
*/
return (B_FALSE);
return (B_TRUE);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static void
{
}
int
{
int err;
/*
* Allocate a new mac_impl_t.
*/
/*
* Construct a name.
*/
/*
* Set the mac_t/mac_impl_t cross-references.
*/
/*
* Allocate a hash table entry.
*/
/*
* Insert the hash table entry.
*/
goto done;
}
/*
* Copy the fixed 'factory' MAC address from the immutable info.
* This is taken to be the MAC address currently in use.
*/
/*
* Set up the address verification functions.
*/
/*
* Set up the two possible transmit routines.
*/
/*
* Initialize the kstats for this device.
*/
done:
return (err);
}
static void
{
mac_multicst_addr_t *p, *nextp;
/*
* Destroy the kstats.
*/
/*
* Remove and destroy the hash table entry.
*/
/*
* Free the list of multicast addresses.
*/
kmem_free(p, sizeof (mac_multicst_addr_t));
}
/*
* Clean up the mac_impl_t ready to go back into the cache.
*/
/*
* Free the structure back to the cache.
*/
}
static void
{
void *arg;
/*
* Walk the list of notifications.
*/
}
}
/*
* Module initialization functions.
*/
void
mac_init(void)
{
int err;
}
int
mac_fini(void)
{
int err;
return (err);
return (0);
}
/*
* Client functions.
*/
int
{
char name[MAXNAMELEN];
char driver[MAXNAMELEN];
int err;
/*
* Check the device name length to make sure it won't overflow our
* buffer.
*/
return (EINVAL);
/*
* Split the device name into driver and instance components.
*/
return (EINVAL);
/*
* Get the major number of the driver.
*/
return (EINVAL);
/*
* Hold the given instance to prevent it from being detached.
* (This will also attach it if it is not currently attached).
*/
return (EINVAL);
/*
* Construct the name of the MAC interface.
*/
/*
* Look up its entry in the global hash table.
*/
goto failed;
if (mip->mi_destroying) {
goto again;
}
return (0);
return (err);
}
void
{
}
}
const mac_info_t *
{
/*
* Return a pointer to the mac_info_t embedded in the mac_t.
*/
}
{
/*
* Call the driver to get the given statistic.
*/
}
int
{
int err;
/*
* Check whether the device is already started.
*/
/*
* It's already started so there's nothing more to do.
*/
err = 0;
goto done;
}
/*
* Start the device.
*/
done:
return (err);
}
void
{
/*
* Check whether the device is still needed.
*/
/*
* It's still needed so there's nothing more to do.
*/
goto done;
}
/*
* Stop the device.
*/
done:
}
int
{
int err;
/*
* Verify the address.
*/
return (EINVAL);
/*
* Check whether the given address is already enabled.
*/
/*
* The address is already enabled so just bump the
* reference count.
*/
p->mma_ref++;
err = 0;
goto done;
}
}
/*
* Allocate a new list entry.
*/
if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
KM_NOSLEEP)) == NULL) {
goto done;
}
/*
* Enable a new multicast address.
*/
kmem_free(p, sizeof (mac_multicst_addr_t));
goto done;
}
/*
* Add the address to the list of enabled addresses.
*/
p->mma_ref++;
*pp = p;
done:
return (err);
}
int
{
int err;
/*
* Find the entry in the list for the given address.
*/
if (--p->mma_ref == 0)
break;
/*
* There is still a reference to this address so
* there's nothing more to do.
*/
err = 0;
goto done;
}
}
/*
* We did not find an entry for the given address so it is not
* currently enabled.
*/
if (p == NULL) {
goto done;
}
/*
* Disable the multicast address.
*/
p->mma_ref++;
goto done;
}
/*
* Remove it from the list.
*/
kmem_free(p, sizeof (mac_multicst_addr_t));
done:
return (err);
}
int
{
int err;
/*
* Verify the address.
*/
return (EINVAL);
/*
* Program the new unicast address.
*/
/*
* If address doesn't change, do nothing.
* This check is necessary otherwise it may call into mac_unicst_set
* recursively.
*/
err = 0;
goto done;
}
goto done;
/*
* Save the address and flag that we need to send a notification.
*/
done:
if (notify)
return (err);
}
void
{
/*
* Copy out the current unicast address.
*/
}
int
{
int err = 0;
/*
* Determine whether we should enable or disable promiscuous mode.
* For details on the distinction between "device promiscuous mode"
* and "MAC promiscuous mode", see PSARC/2005/289.
*/
if (on) {
/*
* Enable promiscuous mode on the device if not yet enabled.
*/
if (mip->mi_devpromisc++ == 0) {
mip->mi_devpromisc--;
goto done;
}
}
/*
* Enable promiscuous mode on the MAC if not yet enabled.
*/
} else {
if (mip->mi_devpromisc == 0) {
goto done;
}
/*
* Disable promiscuous mode on the device if this is the last
* enabling.
*/
if (--mip->mi_devpromisc == 0) {
mip->mi_devpromisc++;
goto done;
}
}
/*
* Disable promiscuous mode on the MAC if this is the last
* enabling.
*/
}
done:
return (err);
}
{
/*
* Return the current promiscuity.
*/
if (ptype == MAC_DEVPROMISC)
return (mip->mi_devpromisc != 0);
else
return (mip->mi_promisc != 0);
}
void
{
/*
* Call the driver to register its resources.
*/
}
void
{
/*
* Call the driver to handle the ioctl.
*/
}
const mac_txinfo_t *
{
/*
* Grab the lock to prevent us from racing with MAC_PROMISC being
* changed. This is sufficient since MAC clients are careful to always
* call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
* MAC_PROMISC prior to calling mac_txloop_remove().
*/
} else {
/*
* Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
* because to satisfy the above ASSERT(), we have to disable
* MAC_PROMISC prior to calling mac_txloop_remove().
*/
}
return (mtp);
}
{
/*
* Return the current link state.
*/
}
{
/*
* Add it to the head of the 'notify' callback list.
*/
return ((mac_notify_handle_t)mnfp);
}
void
{
mac_notify_fn_t *p;
/*
* Search the 'notify' callback list for the function closure.
*/
if (p == mnfp)
break;
}
/*
* Remove it from the list.
*/
/*
* Free it.
*/
}
void
{
}
{
/*
* Add it to the head of the 'rx' callback list.
*/
return ((mac_rx_handle_t)mrfp);
}
/*
* Unregister a receive function for this mac. This removes the function
* from the list of receive functions for this mac.
*/
void
{
mac_rx_fn_t **pp;
mac_rx_fn_t *p;
/*
* Search the 'rx' callback list for the function closure.
*/
if (p == mrfp)
break;
}
/* Remove it from the list. */
}
{
/*
* Add it to the head of the 'tx' callback list.
*/
return ((mac_txloop_handle_t)mtfp);
}
/*
* Unregister a transmit function for this mac. This removes the function
* from the list of transmit functions for this mac.
*/
void
{
mac_txloop_fn_t *p;
/*
* Search the 'tx' callback list for the function.
*/
if (p == mtfp)
break;
}
/* Remove it from the list. */
}
void
{
/*
* Update the 'resource_add' callbacks.
*/
}
/*
* Driver support functions.
*/
int
{
int err;
#ifdef DEBUG
#endif /* DEBUG */
/*
* Create a new mac_impl_t to pair with the mac_t.
*/
return (err);
/*
* Create a DDI_NT_MAC minor node such that libdevinfo(3lib) can be
* used to search for mac interfaces.
*/
DDI_NT_MAC, 0) != DDI_SUCCESS) {
return (EEXIST);
}
/*
* Right now only the "aggr" driver creates nodes at mac_register
* time, but it is expected that in the future with some
* enhancement of devfs, all the drivers can create nodes here.
*/
if (err != 0) {
return (err);
}
}
/* set the gldv3 flag in dn_flags */
return (0);
}
int
{
int err;
char name[MAXNAMELEN];
/*
* See if there are any other references to this mac_t (e.g., VLAN's).
* If not, set mi_destroying to prevent any new VLAN's from being
* created before we can perform the i_mac_destroy() below.
*/
return (EBUSY);
}
return (err);
}
/*
* Destroy the mac_impl_t.
*/
/*
* Remove the minor node.
*/
return (0);
}
void
{
/*
* Call all registered receive functions.
*/
/* There are no registered receive functions. */
return;
}
do {
/* XXX Do we bump a counter if copymsgchain() fails? */
} else {
}
}
/*
* Transmit function -- ONLY used when there are registered loopback listeners.
*/
mblk_t *
{
goto noresources;
goto noresources;
}
/* XXX counter bump if copymsg() fails? */
else
}
/*
* It's possible we've raced with the disabling of promiscuous
* mode, in which case we can discard our copy.
*/
}
return (NULL);
return (bp);
}
void
{
/*
* Save the link state.
*/
/*
* Send a MAC_NOTE_LINK notification.
*/
}
void
{
/*
* Save the address.
*/
/*
* Send a MAC_NOTE_UNICST notification.
*/
}
void
{
/*
* Send a MAC_NOTE_TX notification.
*/
}
void
{
/*
* Send a MAC_NOTE_RESOURCE notification.
*/
}
{
void *arg;
return (mrh);
}
void
{
/*
* If no specific refresh function was given then default to the
* driver's m_multicst entry point.
*/
}
/*
* Walk the multicast address list and call the refresh function for
* each address.
*/
}
void
{
/*
* If no specific refresh function was given then default to the
* driver's m_unicst entry point.
*/
}
/*
* Call the refresh function with the current unicast address.
*/
}
void
{
/*
* If no specific refresh function was given then default to the
* driver's m_promisc entry point.
*/
}
/*
* Call the refresh function with the current promiscuity.
*/
}
{
if (mip->mi_activelink) {
return (B_FALSE);
}
return (B_TRUE);
}
void
{
}