mac.c revision 4045d94132614e1de2073685a6cdd4fbd86bec33
/*
* 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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* MAC Services Module
*/
#include <sys/id_space.h>
#include <sys/mac_impl.h>
#include <sys/ethernet.h>
static kmem_cache_t *i_mac_impl_cachep;
static mod_hash_t *i_mac_impl_hash;
static kmem_cache_t *mac_vnic_tx_cache;
static id_space_t *minor_ids;
static uint32_t minor_count;
#define MACTYPE_KMODDIR "mac"
#define MACTYPE_HASHSZ 67
static mod_hash_t *i_mactype_hash;
/*
* i_mactype_lock synchronizes threads that obtain references to mactype_t
* structures through i_mactype_getplugin().
*/
static kmutex_t i_mactype_lock;
static void i_mac_notify_thread(void *);
/*
* Private functions.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static void
{
}
/*
* mac_vnic_tx_t kmem cache support functions.
*/
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static void
{
}
static void
{
if (mip->mi_disabled)
goto exit;
/*
* Guard against incorrect notifications. (Running a newer
* mac client against an older implementation?)
*/
goto exit;
exit:
}
static void
{
/*
* If no change, then it is not interesting.
*/
return;
switch (mip->mi_linkstate) {
case LINK_STATE_UP:
char det[200];
} else {
}
break;
case LINK_STATE_DOWN:
/*
* Only transitions from UP to DOWN are interesting
*/
break;
case LINK_STATE_UNKNOWN:
/*
* This case is normally not interesting.
*/
break;
}
}
static void
i_mac_notify_thread(void *arg)
{
"i_mac_notify_thread");
for (;;) {
if (bits == 0) {
continue;
}
mip->mi_notify_bits = 0;
/* request to quit */
break;
}
/*
* Log link changes.
*/
/*
* Do notification callbacks for each notification type.
*/
continue;
}
/*
* Walk the list of notifications.
*/
}
}
}
thread_exit();
}
static mactype_t *
i_mactype_getplugin(const char *pname)
{
(mod_hash_val_t *)&mtype) != 0) {
if (!tried_modload) {
/*
* If the plugin has not yet been loaded, then
* attempt to load it now. If modload() succeeds,
* the plugin should have registered using
* mactype_register(), in which case we can go back
* and attempt to find it again.
*/
goto find_registered_mactype;
}
}
} else {
/*
* Note that there's no danger that the plugin we've loaded
* could be unloaded between the modload() step and the
* reference count bump here, as we're holding
* i_mactype_lock, which mactype_unregister() also holds.
*/
}
return (mtype);
}
/*
* Module initialization functions.
*/
void
mac_init(void)
{
i_mac_impl_count = 0;
/*
* Allocate an id space to manage minor numbers. The range of the
* space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal
* minor number is MAXMIN, but id_t is type of integer and does not
* allow MAXMIN).
*/
minor_count = 0;
}
int
mac_fini(void)
{
if (i_mac_impl_count > 0 || minor_count > 0)
return (EBUSY);
return (0);
}
/*
* Client functions.
*/
static int
{
int err;
/*
* Check the device name length to make sure it won't overflow our
* buffer.
*/
return (EINVAL);
/*
* Look up its entry in the global hash table.
*/
(mod_hash_val_t *)&mip);
if (err != 0) {
return (ENOENT);
}
if (mip->mi_disabled) {
return (ENOENT);
}
if (mip->mi_exclusive) {
return (EBUSY);
}
return (0);
}
static void
{
}
int
{
/*
* Look up its entry in the global hash table.
*/
if (mip->mi_disabled) {
return (ENOENT);
}
return (EBUSY);
}
return (0);
}
void
{
/*
* Look up its entry in the global hash table.
*/
}
int
{
int err;
/*
* Look up its entry in the global hash table.
*/
return (err);
/*
* Hold the dip associated to the MAC to prevent it from being
* detached. For a softmac, its underlying dip is held by the
* mi_open() callback.
*
* This is done to be more tolerant with some defective drivers,
* which incorrectly handle mac_unregister() failure in their
* xxx_detach() routine. For example, some drivers ignore the
* failure of mac_unregister() and free all resources that
* that are needed for data transmition.
*/
goto done;
}
/*
* Note that we do not hold i_mac_impl_lock when calling the
* mc_open() callback function to avoid deadlock with the
* i_mac_notify() function.
*/
return (err);
}
done:
return (0);
}
int
{
int err;
return (err);
goto done;
}
done:
return (err);
}
int
{
int err;
return (err);
}
void
{
}
}
const mac_info_t *
{
}
{
}
const char *
{
}
{
}
{
int ret;
/*
* The range of stat determines where it is maintained. Stat
* values from 0 up to (but not including) MAC_STAT_MIN are
* mainteined by the mac module itself. Everything else is
* maintained by the driver.
*/
if (stat < MAC_STAT_MIN) {
/* These stats are maintained by the mac module itself. */
switch (stat) {
case MAC_STAT_LINK_STATE:
return (mip->mi_linkstate);
case MAC_STAT_LINK_UP:
case MAC_STAT_PROMISC:
return (mip->mi_devpromisc != 0);
default:
}
}
/*
* Call the driver to get the given statistic.
*/
if (ret != 0) {
/*
* The driver doesn't support this statistic. Get the
* statistic's default value.
*/
}
return (val);
}
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 (err);
}
/*
* Check whether the given address is already enabled.
*/
0) {
/*
* 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.
*/
0) {
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);
}
/*
* mac_unicst_verify: Verifies the passed address. It fails
* if the passed address is a group address or has incorrect length.
*/
{
/*
* Verify the address.
*/
return (B_FALSE);
} else {
return (B_TRUE);
}
}
int
{
int err;
/*
* Verify the address.
*/
return (err);
}
/*
* 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.
*/
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 source address.
*/
}
void
{
/*
* Copy out the current destination 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) {
if (err != 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) {
if (err != 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
{
}
void
{
/*
* If the driver supports resource registration, call the driver to
* ask it to register its resources.
*/
}
void
{
/*
* If ndd props were registered, call them.
* Note that ndd ioctls are Obsolete
*/
return;
}
/*
* Call the driver to handle the ioctl. The driver may not support
* any ioctls, in which case we reply with a NAK on its behalf.
*/
else
}
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 {
}
} else {
} 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);
}
/*
* Invoked by VNIC to obtain the transmit entry point.
*/
const mac_txinfo_t *
{
}
/*
* Invoked by any non-VNIC client to obtain the transmit entry point.
* If a VNIC is present, the VNIC transmit function provided by the VNIC
* will be returned to the MAC client.
*/
const mac_txinfo_t *
{
}
{
}
{
/*
* 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
{
}
/*
* Register a receive function for this mac.
* More information on this function's interaction with mac_rx()
* can be found atop mac_rx().
*/
{
/*
* Add it to the head of the 'rx' callback list.
*/
/*
* mac_rx() will only call callbacks that are marked inuse.
*/
/*
* mac_rx() could be traversing the remainder of the list
* and miss the new callback we're adding here. This is not a problem
* because we do not guarantee the callback to take effect immediately
* after mac_rx_add() returns.
*/
return ((mac_rx_handle_t)mrfp);
}
{
}
{
}
/*
* Unregister a receive function for this mac.
* This function does not block if wait is B_FALSE. This is useful
* for clients who call mac_rx_remove() from a non-blockable context.
* More information on this function's interaction with mac_rx()
* can be found atop mac_rx().
*/
void
{
mac_rx_fn_t **pp;
mac_rx_fn_t *p;
/*
* Search the 'rx' callback list for the function closure.
*/
if (p == mrfp)
break;
}
/*
* If mac_rx() is running, mark callback for deletion
* and return (if wait is false), or wait until mac_rx()
* exits (if wait is true).
*/
mip->mi_rx_removed++;
if (wait)
return;
}
/* Remove it from the list. */
}
/*
* Wait for all pending callback removals to be completed by mac_rx().
* Note that if we call mac_rx_remove() immediately before this, there is no
* guarantee we would wait *only* on the callback that we specified.
* mac_rx_remove() could have been called by other threads and we would have
* to wait for other marked callbacks to be removed as well.
*/
void
{
while (mip->mi_rx_removed > 0) {
}
}
{
/*
* 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.
*/
{
/*
* Make sure there isn't a version mismatch between the driver and
* the framework. In the future, if multiple versions are
* supported, this check could become more sophisticated.
*/
if (mac_version != MAC_VERSION)
return (NULL);
return (mregp);
}
void
{
}
/*
* Allocate a minor number.
*/
{
/*
* Grab a value from the arena.
*/
if (sleep)
else
if (minor == 0) {
return (0);
}
return (minor);
}
/*
* Release a previously allocated minor number.
*/
void
{
/*
* Return the value to the arena.
*/
}
{
return (mip->mi_unsup_note);
}
{
}
/*
* mac_register() is how drivers register new MACs with the GLDv3
* framework. The mregp argument is allocated by drivers using the
* mac_alloc() function, and can be freed using mac_free() immediately upon
* return from mac_register(). Upon success (0 return value), the mhp
* opaque pointer becomes the driver's handle to its MAC interface, and is
* the argument to all other mac module entry points.
*/
int
{
char *driver;
/* Find the required MAC-Type plugin. */
return (EINVAL);
/* Create a mac_impl_t to represent this MAC. */
/*
* The mac is not ready for open yet.
*/
/*
* When a mac is registered, the m_instance field can be set to:
*
* 0: Get the mac's instance number from m_dip.
* This is usually used for physical device dips.
*
* [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
* For example, when an aggregation is created with the key option,
* "key" will be used as the instance number.
*
* -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
* This is often used when a MAC of a virtual link is registered
* (e.g., aggregation when "key" is not specified, or vnic).
*
* Note that the instance number is used to derive the mi_minor field
* of mac_impl_t, which will then be used to derive the name of kstats
* and the devfs nodes. The first 2 cases are needed to preserve
* backward compatibility.
*/
switch (mregp->m_instance) {
case 0:
break;
case ((uint_t)-1):
if (minor == 0) {
goto fail;
}
break;
default:
if (instance >= MAC_MAX_MINOR) {
goto fail;
}
break;
}
/* Construct the MAC name as <drvname><instance> */
goto fail;
/*
* If the media supports a broadcast address, cache a pointer to it
* in the mac_info_t so that upper layers can use it.
*/
/*
* Copy the unicast source address into the mac_info_t, but only if
* the MAC-Type defines a non-zero address length. We need to
* handle MAC-Types that have an address length of 0
* (point-to-point protocol MACs for example).
*/
goto fail;
/*
* Copy the fixed 'factory' MAC address from the immutable
* info. This is taken to be the MAC address currently in
* use.
*/
/* Copy the destination address if one is provided. */
}
goto fail;
}
/*
* The format of the m_pdata is specific to the plugin. It is
* passed in as an argument to all of the plugin callbacks. The
* driver can update this information by calling
* mac_pdata_update().
*/
/*
* Verify that the plugin supports MAC plugin data and that
* the supplied data is valid.
*/
goto fail;
mregp->m_pdata_size)) {
goto fail;
}
}
/*
* Register the private properties.
*/
/*
* Stash the driver callbacks into the mac_impl_t, but first sanity
* check to make sure all mandatory callbacks are set.
*/
goto fail;
}
/*
* Set up the possible transmit routines.
*/
/*
* Legacy device. Messages being sent will be looped back
* by the underlying driver. Therefore the txloop function
* pointer is the same as the tx function pointer.
*/
} else {
/*
* Normal device. The framework needs to do the loopback.
*/
mip->mi_unsup_note = 0;
}
/*
* Allocate a notification thread.
*/
goto fail;
/*
* Initialize the kstats for this device.
*/
/* set the gldv3 flag in dn_flags */
/* Create a style-2 DLPI device */
goto fail;
/* Create a style-1 DLPI device */
goto fail;
}
goto fail;
}
(mac_impl_t *), mip);
/*
* Mark the MAC to be ready for open.
*/
return (0);
fail:
if (style1_created)
if (style2_created)
/* clean up notification thread */
while (mip->mi_notify_bits != 0)
}
}
}
mip->mi_pdata_size = 0;
}
if (minor != 0) {
}
return (err);
}
int
{
/*
* See if there are any other references to this mac_t (e.g., VLAN's).
* If not, set mi_disabled to prevent any new VLAN's from being
* created while we're destroying this mac.
*/
return (EBUSY);
}
return (0);
}
int
{
int err;
mac_multicst_addr_t *p, *nextp;
/*
* See if there are any other references to this mac_t (e.g., VLAN's).
* If not, set mi_disabled to prevent any new VLAN's from being
* created while we're destroying this mac. Once mac_disable() returns
* 0, the rest of mac_unregister() stuff should continue without
* returning an error.
*/
if (!mip->mi_disabled) {
return (err);
}
/*
* Clean up notification thread (wait for it to exit).
*/
while (mip->mi_notify_bits != 0)
}
(void) mod_hash_remove(i_mac_impl_hash,
ASSERT(i_mac_impl_count > 0);
mip->mi_pdata_size = 0;
/*
* Free the list of multicast addresses.
*/
kmem_free(p, sizeof (mac_multicst_addr_t));
}
/*
* Free the list of margin request.
*/
}
return (0);
}
/*
* To avoid potential deadlocks, mac_rx() releases mi_rx_lock
* before invoking its list of upcalls. This introduces races with
* mac_rx_remove() and mac_rx_add(), who can potentially modify the
* upcall list while mi_rx_lock is not being held. The race with
* mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
* mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
* to not modify the list but instead mark an upcall for deletion.
* before mac_rx() exits, mi_rx_ref is decremented and if it
* is 0, the marked upcalls will be removed from the list and freed.
* The race with mac_rx_add() is harmless because mac_rx_add() only
* prepends to the list and since mac_rx() saves the list head
* before releasing mi_rx_lock, any prepended upcall won't be seen
* until the next packet chain arrives.
*
* To minimize lock contention between multiple parallel invocations
* of mac_rx(), mi_rx_lock is acquired as a READER lock. The
* use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
* will be upgraded to WRITER mode when there are marked upcalls to be
* cleaned.
*/
static void
{
/*
* Call all registered receive functions.
*/
/* There are no registered receive functions. */
return;
}
/*
* Call registered receive functions.
*/
do {
/*
* We hit the last receiver, but it's not
* active.
*/
}
continue;
}
/*
* Send bp itself and keep the copy.
* If there's only one active receiver,
* it should get the original message,
* tagged with the hardware checksum flags.
*/
} else {
}
}
mac_rx_fn_t **pp, *p;
/*
* Need to become exclusive before doing cleanup
*/
}
/*
* We return if another thread has already entered and cleaned
* up the list.
*/
return;
}
/*
* Free removed callbacks.
*/
p = *pp;
kmem_free(p, sizeof (*p));
cnt++;
continue;
}
}
/*
* Wake up mac_rx_remove_wait()
*/
mip->mi_rx_removed = 0;
}
}
void
{
}
/*
* Send a packet chain up to the receive callbacks which declared
* themselves as being active.
*/
void
{
}
/*
* Function passed to the active client sharing a VNIC. This function
* is returned by mac_tx_get() when a VNIC is present. It invokes
* the VNIC transmit entry point which was specified by the VNIC when
* it called mac_vnic_set(). The VNIC transmit entry point will
* if needed.
*/
static mblk_t *
{
/*
* There is a race between the notification of the VNIC
* addition and removal, and the processing of the VNIC notification
* by the MAC client. During this window, it is possible for
* an active MAC client to contine invoking mac_vnic_tx() while
* the VNIC has already been removed. So we cannot assume
* that mi_vnic_present will always be true when mac_vnic_tx()
* is invoked.
*/
if (!mip->mi_vnic_present) {
return (NULL);
}
return (NULL);
}
/*
* Transmit function -- ONLY used when there are registered loopback listeners.
*/
mblk_t *
{
if (call_vnic) {
/*
* In promiscous mode, a copy of the sent packet will
* be sent to the client's promiscous receive entry
* points via mac_vnic_tx()->
* mac_active_rx_promisc()->mac_rx_default().
*/
}
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);
}
mblk_t *
{
}
static mblk_t *
{
}
void
{
/*
* Save the link state.
*/
/*
* Send a MAC_NOTE_LINK notification.
*/
}
void
{
return;
/*
* If the address has not changed, do nothing.
*/
return;
/*
* 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;
else
return (mrh);
}
int
{
/*
* Verify that the plugin supports MAC plugin data and that the
* supplied data is valid.
*/
return (EINVAL);
return (EINVAL);
/*
* Since the MAC plugin data is used to construct MAC headers that
* were cached in fast-path headers, we need to flush fast-path
* information for links associated with this mac.
*/
return (0);
}
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 mi_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.
*/
}
/*
* The mac client requests that the mac not to change its margin size to
* be less than the specified value. If "current" is B_TRUE, then the client
* requests the mac not to change its margin size to be smaller than the
* current size. Further, return the current margin size value in this case.
*
* We keep every requested size in an ordered list from largest to smallest.
*/
int
{
mac_margin_req_t **pp, *p;
int err = 0;
if (current)
/*
* If the current margin value cannot satisfy the margin requested,
* return ENOTSUP directly.
*/
goto done;
}
/*
* Check whether the given margin is already in the list. If so,
* bump the reference count.
*/
if (p->mmr_margin == *marginp) {
/*
* The margin requested is already in the list,
* so just bump the reference count.
*/
p->mmr_ref++;
goto done;
}
if (p->mmr_margin < *marginp)
break;
}
goto done;
}
p->mmr_margin = *marginp;
p->mmr_ref++;
*pp = p;
done:
return (err);
}
/*
* The mac client requests to cancel its previous mac_margin_add() request.
* We remove the requested margin size from the list.
*/
int
{
mac_margin_req_t **pp, *p;
int err = 0;
/*
* Find the entry in the list for the given margin.
*/
if (p->mmr_margin == margin) {
if (--p->mmr_ref == 0)
break;
/*
* There is still a reference to this address so
* there's nothing more to do.
*/
goto done;
}
}
/*
* We did not find an entry for the given margin.
*/
if (p == NULL) {
goto done;
}
/*
* Remove it from the list.
*/
kmem_free(p, sizeof (mac_margin_req_t));
done:
return (err);
}
/*
* The mac client requests to get the mac's current margin value.
*/
void
{
}
{
uint32_t margin_needed = 0;
if (margin_needed <= margin)
if (margin_needed <= margin)
return (margin_needed <= margin);
}
{
if (mip->mi_activelink) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Called by MAC clients. By default, active MAC clients cannot
* share the NIC with VNICs.
*/
{
}
/*
* Called by MAC clients which can share the NIC with VNICS, e.g. DLS.
*/
{
}
void
{
}
void *getcapab_arg)
{
/*
* The NIC is already used by an active client which cannot
* share it with VNICs.
*/
return (B_FALSE);
}
return (B_TRUE);
}
void
{
/*
* Setting mi_vnic_tx to NULL here under the lock guarantees
* that no new references to the current VNIC transmit structure
* will be taken by mac_vnic_tx(). This is a necessary condition
* for safely waiting for the reference count to drop to
* zero below.
*/
/*
* Wait for all TX calls referencing the VNIC transmit
* entry point that was removed to complete.
*/
}
/*
* mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
* issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
* the first mac_impl_t with a matching driver name; then we copy its mac_info_t
* to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
* cannot disappear while we are accessing it.
*/
typedef struct i_mac_info_state_s {
const char *mi_name;
/*ARGSUSED*/
static uint_t
{
if (mip->mi_disabled)
return (MH_WALK_CONTINUE);
return (MH_WALK_CONTINUE);
return (MH_WALK_TERMINATE);
}
{
return (B_FALSE);
}
return (B_TRUE);
}
{
if (!is_vnic) {
if (mip->mi_vnic_present) {
return (rv);
}
}
else
return (B_FALSE);
}
{
}
{
}
{
}
mblk_t *
{
}
int
{
mhip));
}
mblk_t *
{
return (NULL);
}
}
return (mp);
}
mblk_t *
{
return (NULL);
}
}
return (mp);
}
void
{
}
void
{
}
/*
* MAC Type Plugin functions.
*/
{
/*
* Make sure there isn't a version mismatch between the plugin and
* the framework. In the future, if multiple versions are
* supported, this check could become more sophisticated.
*/
if (mactype_version != MACTYPE_VERSION)
return (NULL);
return (mtrp);
}
void
{
}
int
{
/* Do some sanity checking before we register this MAC type. */
return (EINVAL);
/*
* Verify that all mandatory callbacks are set in the ops
* vector.
*/
return (EINVAL);
}
mtrp->mtr_addrlen);
}
return (EEXIST);
}
return (0);
}
int
mactype_unregister(const char *ident)
{
int err;
/*
* Let's not allow MAC drivers to use this plugin while we're
* trying to unregister it. Holding i_mactype_lock also prevents a
* plugin from unregistering while a MAC driver is attempting to
* hold a reference to it in i_mactype_getplugin().
*/
(mod_hash_val_t *)&mtp)) != 0) {
/* A plugin is trying to unregister, but it never registered. */
goto done;
}
goto done;
}
if (err != 0) {
/* This should never happen, thus the ASSERT() above. */
goto done;
}
done:
return (err);
}
int
{
}
return (err);
}
int
{
case DLD_PROP_MTU:
return (EINVAL);
return (0);
} else {
return (0);
}
/*
* ask driver for its default.
*/
break;
}
case DLD_PROP_STATUS:
if (valsize < sizeof (link_state))
return (EINVAL);
return (0);
default:
break;
}
}
return (err);
}
int
{
return (EINVAL);
/* Send a MAC_NOTE_SDU_SIZE notification. */
return (0);
}
static void
{
return;
}