ip_arp.c revision 01685f973ffa404db3bc35b99a86c94e268d6587
/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <netinet/if_ether.h>
(sizeof (dl_unitdata_req_t)) : \
/*
* MAC-specific intelligence. Shouldn't be needed, but the DL_INFO_ACK
* doesn't quite do it for us.
*/
typedef struct arp_m_s {
} arp_m_t;
ncec_t *);
static int arp_modclose(arl_t *);
static void arp_mod_close_tail(arl_t *);
static int ip_sioctl_ifunitsel_arp(queue_t *, int *);
static int ip_sioctl_slifname_arp(queue_t *, void *);
static void arp_ifname_notify(arl_t *);
#define IS_DLPI_DATA(mp) \
struct module_info arp_mod_info = {
};
};
};
};
#define ARH_FIXED_LEN 8
#define AR_LL_HDR_SLACK 32
/*
* pfhooks for ARP.
*/
\
if ((_hook).he_interested) { \
\
} \
} else { \
} \
}
\
if ((_hook).he_interested) { \
\
} \
} else { \
} \
}
};
static void
{
arl->arl_refcnt++;
}
static void
{
arl->arl_refcnt--;
return;
}
/* ill_close or arp_unbind_complete may be waiting */
}
/*
* wake up any pending ip ioctls.
*/
static void
{
arp_replumb_done(ill, 0);
else
}
static int
{
int retv;
int new_state;
retv = AR_NOTFOUND;
goto done;
}
/*
* IP addr and hardware address match what we already
* have, then this is a broadcast packet emitted by one of our
* interfaces, reflected by the switch and received on another
* interface. We return AR_LOOPBACK.
*/
retv = AR_LOOPBACK;
goto done;
}
/*
* If the entry is unverified, then we've just verified that
* someone else already owns this address, because this is a
* message with the same protocol address but different
* hardware address.
*/
goto done;
}
/*
* If the IP address matches ours and we're authoritative for
* this entry, then some other node is using our IP addr, so
* return AR_BOGON. Also reset the transmit count to zero so
* that, if we're currently in initial announcement mode, we
* switch back to the lazier defense mode. Knowing that
* there's at least one duplicate out there, we ought not
* blindly announce.
*
* NCE_F_AUTHORITY is set in one of two ways:
* 2. This is one of my addresses.
*/
ncec->ncec_unsolicit_count = 0;
goto done;
}
/*
* No address conflict was detected, and we are getting
* ready to update the ncec's hwaddr. The nce MUST NOT be on an
* under interface, because all dynamic nce's are created on the
* native interface (in the non-IPMP case) or on the IPMP
* meta-interface (in the IPMP case)
*/
/*
* update ncec with src_haddr, hlen.
*
* So the new_state is at least "STALE". If, in addition,
* this a solicited, unicast ARP_RESPONSE, we can transition
* to REACHABLE.
*/
ip1dbg(("got info for ncec %p from addr %x\n",
ll_changed = B_TRUE;
} else {
if (!ll_changed)
else
retv = AR_CHANGED;
}
/*
* We don't have the equivalent of the IPv6 'S' flag indicating
* a solicited response, so we assume that if we are in
* INCOMPLETE, or got back an unchanged lladdr in PROBE state,
* and this is an ARP_RESPONSE, it must be a
* solicited response allowing us to transtion to REACHABLE.
*/
if (op == ARP_RESPONSE) {
switch (ncec->ncec_state) {
case ND_PROBE:
break;
case ND_INCOMPLETE:
break;
}
}
/*
* Call nce_update() to refresh fastpath information on any
* dependent nce_t entries.
*/
done:
return (retv);
}
/* Find an entry for a particular MAC type in the arp_m_tbl. */
static arp_m_t *
{
return (arm);
}
return (NULL);
}
static uint32_t
{
return (arm->arp_mac_arp_hw_type);
}
/*
* Called when an DLPI control message has been acked; send down the next
* queued message (if any).
* The DLPI messages of interest being bind, attach and unbind since
* these are the only ones sent by ARP via arp_dlpi_send.
*/
static void
{
int err;
else
err = 0;
ill->ill_arl_dlpi_pending = 0;
return;
}
}
/*
* This routine is called during module initialization when the DL_INFO_ACK
* comes back from the device. We set up defaults for all the device dependent
* doo-dads we are going to need. This will leave us ready to roll if we are
* attempting auto-configuration. Alternatively, these defaults can be
* overridden by initialization procedures possessing higher intelligence.
*
* Caller will free the mp.
*/
static void
{
/*
* We initialize based on parameters in the (currently) not too
* exhaustive arp_m_tbl.
*/
} else {
}
/*
* Note: the arp_hw_type in the arp header may be derived from
* the ill_mac_type and arp_m_lookup().
*/
}
static void
{
case M_IOCTL:
char *, "<some ioctl>", char *, "-",
return;
}
if (err == 0)
else
return;
default:
char *, "default mblk", char *, "-",
return;
}
}
/*
* similar to ill_dlpi_pending(): verify that the received DLPI response
* matches the one that is pending for the arl.
*/
static boolean_t
{
return (B_TRUE);
}
return (B_FALSE);
}
if (pending == DL_PRIM_INVAL) {
ip0dbg(("arl_dlpi_pending unsolicited ack for %s on %s",
} else {
ip0dbg(("arl_dlpi_pending ack for %s on %s expect %s",
}
return (B_FALSE);
}
/* DLPI messages, other than DL_UNITDATA_IND are handled here. */
static void
{
union DL_primitives *dlp;
return;
}
/*
* If we received an ACK but didn't send a request for it, then it
* can't be part of any pending operation; discard up-front.
*/
switch (prim) {
case DL_ERROR_ACK:
/*
* ce is confused about how DLPI works, so we have to interpret
* an "error" on DL_NOTIFY_ACK (which we never could have sent)
* as really meaning an error on DL_NOTIFY_REQ.
*
* Note that supporting DL_NOTIFY_REQ is optional, so printing
* out an error message on the console isn't warranted except
* for debug.
*/
} else {
}
break;
case DL_INFO_ACK:
break;
case DL_OK_ACK:
break;
case DL_BIND_ACK:
break;
default:
union DL_primitives *, dlp);
return;
}
return;
}
switch (reqprim) {
case DL_INFO_REQ:
/*
* ill has not been set up yet for this case. This is the
* DL_INFO_ACK for the first DL_INFO_REQ sent from
* arp_modopen(). There should be no other arl_dlpi_deferred
* messages pending. We initialize the arl here.
*/
return;
case DL_UNBIND_REQ:
/*
* This is not an error, so we don't set ARL_LL_DOWN
*/
/*
* if this is part of the unplumb the arl may
* vaporize any moment after we cv_signal the
* arl_cv so we reset arl_dlpi_pending here.
* All other cases (including replumb) will
* have the arl_dlpi_pending reset in
* arp_dlpi_done.
*/
}
break;
}
/*
* ill ref obtained by arl_to_ill() will be released
* by qwriter_ip()
*/
return;
}
}
/*
* Handling of DLPI messages that require exclusive access to the ipsq.
*/
/* ARGSUSED */
static void
{
/*
* happens as a result arp_modclose triggering unbind.
* arp_rput_dlpi will cv_signal the arl_cv and the modclose
* will complete, but when it does ipsq_exit, the waiting
* qwriter_ip gets into the ipsq but will find the arl null.
* There should be no deferred messages in this case, so
* just complete and exit.
*/
return;
}
switch (dlp->dl_primitive) {
case DL_ERROR_ACK:
case DL_UNBIND_REQ:
break;
case DL_BIND_REQ:
break;
case DL_ATTACH_REQ:
break;
default:
/* If it's anything else, we didn't send it. */
return;
}
break;
case DL_OK_ACK:
case DL_UNBIND_REQ:
case DL_ATTACH_REQ:
break;
default:
ip0dbg(("Dropping unrecognized DL_OK_ACK for %s",
return;
}
break;
case DL_BIND_ACK:
arl->arl_state_flags &=
break;
case DL_UDERROR_IND:
return;
default:
union DL_primitives *, dlp);
return;
}
}
void
{
if (((arl->arl_state_flags &
(ARL_CONDEMNED | ARL_LL_REPLUMBING)) != 0)) {
/*
* Only allow high priority DLPI messages during unplumb or
* replumb, and we don't take an arl_refcnt for that case.
*/
return;
}
} else {
}
case M_PCPROTO:
case M_PROTO: {
/*
* could be one of
* (i) real message from the wire, (DLPI_DATA)
* (ii) DLPI message
* Take a ref on the ill associated with this arl to
* prevent the ill from being unplumbed until this thread
* is done.
*/
if (IS_DLPI_DATA(mp)) {
break;
}
break;
}
/* Miscellaneous DLPI messages get shuffled off. */
arp_rput_dlpi(q, mp);
break;
}
case M_ERROR:
case M_HANGUP:
break;
default:
break;
}
if (need_refrele)
}
static void
{
int op;
int err;
return;
}
/*
* What we should have at this point is a DL_UNITDATA_IND message
* followed by an ARP packet. We do some initial checks and then
* get to work.
*/
/*
* multicast or broadcast packet. Only accept on the ipmp
* nominated interface for multicasts ('cast_ill').
* If we have no cast_ill we are liberal and accept everything.
*/
if (IS_UNDER_IPMP(ill)) {
/* For an under ill_grp can change under lock */
arp_drop_packet("Interface is not nominated "
"for multicast sends and receives",
return;
}
}
}
return;
}
/* No fooling around with funny messages. */
arp_drop_packet("Funny message: pullup failed",
return;
}
}
return;
}
/*
* hlen 0 is used for RFC 1868 UnARP.
*
* Note that the rest of the code checks that hlen is what we expect
* for this hardware address type, so might as well discard packets
* here that don't match.
*/
return;
}
/*
* Historically, Solaris has been lenient about hardware type numbers.
* We should check here, but don't.
*/
/*
* If ill is in an ipmp group, it will be the under ill. If we want
* to report the packet as coming up the IPMP interface, we should
* convert it to the ipmp ill.
*/
return;
arhp += IP_ADDR_LEN;
/* Determine if this is just a probe */
/*
* The following test for loopback is faster than
* IP_LOOPBACK_ADDR(), because it avoids any bitwise
* operations.
* Note that these addresses are always in network byte order
*/
return;
}
/*
* ira_ill is the only field used down the arp_notify path.
*/
/*
* RFC 826: first check if the <protocol, sender protocol address> is
* in the cache, if there is a sender protocol address. Note that this
* step also handles resolutions based on source.
*/
/* Note: after here we need to freeb(mp) and freemsg(mp1) separately */
if (is_probe) {
err = AR_NOTFOUND;
} else {
if (plen != 4) {
return;
}
switch (err) {
case AR_BOGON:
break;
case AR_FAILED:
src_ncec);
break;
case AR_LOOPBACK:
arh);
break;
default:
goto update;
}
return;
}
/*
* Now look up the destination address. By RFC 826, we ignore the
* packet at this step if the target isn't one of our addresses (i.e.,
* one we have been asked to PUBLISH). This is true even if the
* target is something we're trying to resolve and the packet
* is a response.
*/
/*
* Let the client know if the source mapping has changed, even
* if the destination provides no useful information for the
* client.
*/
if (err == AR_CHANGED) {
NULL);
} else {
}
return;
}
/*
* Check for a reflection. Some misbehaving bridges will
* reflect our own transmitted packets back to us.
*/
return;
}
return;
}
/*
* Responses targeting our HW address that are not responses to
* our DAD probe must be ignored as they are related to requests
* sent before DAD was restarted.
*/
if (op == ARP_RESPONSE &&
"Response to request that was sent before DAD",
return;
}
/*
* Responses targeted to HW addresses which are not ours but
* sent to our unverified proto address are also conflicts.
* These may be reported by a proxy rather than the interface
* with the conflicting address, dst_paddr is in conflict
* rather than src_paddr. To ensure IP can locate the correct
* ipif to take down, it is necessary to copy dst_paddr to
* the src_paddr field before sending it to IP. The same is
* required for probes, where src_paddr will be INADDR_ANY.
*/
NULL);
} else if (err == AR_CHANGED) {
NULL);
} else {
}
return;
}
/*
* If it's a request, then we reply to this, and if we think the
* sender's unknown, then we create an entry to avoid unnecessary ARPs.
* The design assumption is that someone ARPing us is likely to send us
* a packet soon, and that we'll want to reply to it.
*/
if (op == ARP_REQUEST) {
const uchar_t *nce_hwaddr;
/*
* Ignore senders who are deliberately or accidentally
* confused.
*/
goto bail;
}
if (IS_UNDER_IPMP(under_ill)) {
/*
* create the ncec for the sender on ipmp_ill.
* We pass in the ipmp_ill itself to avoid
* creating an nce_t on the under_ill.
*/
else
}
switch (err) {
case 0:
case EEXIST:
ip1dbg(("added ncec %p in state %d ill %s\n",
break;
default:
/*
* Either no memory, or the outgoing interface
* latter case, we will fail the send anyway,
* and in the former case, we should try to send
* the ARP response.
*/
goto send_response;
}
/* set up cleanup interval on ncec */
}
/*
* This implements periodic address defense based on a modified
* version of the RFC 3927 requirements. Instead of sending a
* broadcasted reply every time, as demanded by the RFC, we
* send at most one broadcast reply per arp_broadcast_interval.
*/
now = ddi_get_lbolt();
/*
* If this is one of the long-suffering entries,
* pull it out now. It no longer needs separate
* defense, because we're now doing that with this
* broadcasted reply.
*/
}
} else {
}
}
bail:
}
}
if (err == AR_CHANGED) {
}
if (need_ill_refrele)
done:
}
/*
* Basic initialization of the arl_t and the arl_common structure shared with
* the ill_t that is done after SLIFNAME/IF_UNITSEL.
*/
static int
{
return (ENXIO);
/*
* By the time we set up the arl, we expect the ETHERTYPE_IP
*
* The following should have been set up in arp_ll_set_defaults()
* after the first DL_INFO_ACK was received.
*/
/* First ensure that the ill is not CONDEMNED. */
return (ENXIO);
}
return (EEXIST);
}
return (0);
}
/* Allocate and do common initializations for DLPI messages. */
static mblk_t *
{
return (NULL);
/*
* DLPIv2 says that DL_INFO_REQ and DL_TOKEN_REQ (the latter
* of which we don't seem to use) are sent with M_PCPROTO, and
* that other DLPI are M_PROTO.
*/
return (mp);
}
int
{
return (EINVAL);
do {
q = q->q_next;
}
int
{
/* ioctl not valid when IP opened as a device */
return (EINVAL);
}
arl_t *
{
return (NULL);
/*
* Find the arl_t that corresponds to this ill_t from the shared
* ill_common structure. We can safely access the ai here as it
* will only be freed in arp_modclose() after we have become
* single-threaded.
*/
} else {
}
}
return (arl);
}
ill_t *
{
/*
* happens when the arp stream is just being opened, and
* arl_ill_init has not been executed yet.
*/
return (NULL);
}
/*
* Find the ill_t that corresponds to this arl_t from the shared
* arl_common structure. We can safely access the ai here as it
* will only be freed in arp_modclose() after we have become
* single-threaded.
*/
if (!ILL_IS_CONDEMNED(ill)) {
} else {
}
}
return (ill);
}
int
{
return (ENXIO);
return (0);
}
goto bad;
}
/* Allocate and initialize a bind message. */
goto bad;
goto bad;
if (arl->arl_needs_attach) {
}
return (EINPROGRESS);
bad:
return (ENOMEM);
}
/*
*/
static void
{
char hbuf[MAC_STR_LEN];
char sbuf[INET_ADDRSTRLEN];
switch (arcn_code) {
case AR_CN_BOGON:
/*
* Someone is sending ARP packets with a source protocol
* address that we have published and for which we believe our
* entry is authoritative and verified to be unique on
* the network.
*
* arp_process_packet() sends AR_CN_FAILED for the case when
* a DAD probe is received and the hardware address of a
* non-authoritative entry has changed. Thus, AR_CN_BOGON
* indicates a real conflict, and we have to do resolution.
*
* We back away quickly from the address if it's from DHCP or
* otherwise temporary and hasn't been used recently (or at
* all). We'd like to include "deprecated" addresses here as
* well (as there's no real reason to defend something we're
* discarding), but IPMP "reuses" this flag to mean something
* other than the standard meaning.
*/
"proxy ARP problem? Node '%s' is using %s on %s",
if (!arp_no_defense)
(void) arp_announce(ncec);
/*
* ncec_last_time_defended has been adjusted in
* ip_nce_conflict.
*/
} else {
}
break;
case AR_CN_ANNOUNCE: {
/*
* ARP gives us a copy of any packet where it thinks
* the address has changed, so that we can update our
* caches. We're responsible for caching known answers
* in the current design. We check whether the
* hardware address really has changed in all of our
* entries that have cached this mapping, and if so, we
* blow them away. This way we will immediately pick
* up the rare case of a host changing hardware
* address.
*/
if (src == 0) {
break;
}
break;
}
case AR_CN_FAILED:
if (arp_no_defense) {
"node %s is using our IP address %s on %s",
break;
}
/*
* mp will be freed by arp_excl.
*/
return;
default:
ASSERT(0);
break;
}
}
/*
* arp_output is called to transmit an ARP Request or Response. The mapping
* to RFC 826 variables is:
* haddr1 == ar$sha
* paddr1 == ar$spa
* haddr2 == ar$tha
* paddr2 == ar$tpa
* The ARP frame is sent to the ether_dst in dst_lladdr.
*/
static int
{
return (ENOMEM);
/* IFF_NOARP flag is set or link down: do not send arp messages */
return (ENXIO);
}
return (ENOMEM);
}
/* Fill in the ARP header. */
cp += ARH_FIXED_LEN;
else
else
return (0);
/* Ship it out. */
return (0);
}
else
return (0);
}
/*
* Process resolve requests.
* If we are not yet reachable then we check and decrease ncec_rcnt; otherwise
* we leave it alone (the caller will check and manage ncec_pcnt in those
* cases.)
*/
int
{
int err;
const uchar_t *target_hwaddr;
/* not allowed any more retransmits. */
return (0);
}
return (0);
if (NCE_ISREACHABLE(ncec)) {
} else {
}
if (err != 0) {
/*
* Some transient error such as ENOMEM or a down link was
* encountered. If the link has been taken down permanently,
* the ncec will eventually be cleaned up (ipif_down_tail()
* will call ipif_nce_down() and flush the ncec), to terminate
* recurring attempts to send ARP requests. In all other cases,
* allow the caller another chance at success next time.
*/
}
if (use_rcnt)
}
/* return B_TRUE if dropped */
{
int err;
/* sent on the cast_ill */
return (B_TRUE);
} else {
}
/*
* broadcast an announce to ill_bcast address.
*/
if (need_refrele)
return (err != 0);
}
/* return B_TRUE if dropped */
{
int err;
return (B_TRUE);
} else {
}
return (err != 0);
}
static mblk_t *
{
}
return (mp);
}
int
{
int err = 0;
return (ENXIO);
err = EINPROGRESS;
if (replumb)
}
return (err);
}
/* ARGSUSED */
int
{
/* This is a module close */
return (arp_modclose(q->q_ptr));
}
qprocsoff(q);
return (0);
}
static int
{
if (!ill_waiter_inc(ill)) {
} else {
}
/*
* could not enter the ipsq because ill is already
* marked CONDEMNED.
*/
}
}
/*
* Either we did not get an ill because it was marked CONDEMNED
* or we could not enter the ipsq because it was unplumbing.
* In both cases, wait for the ill to complete ip_modclose().
*
* If the arp_modclose happened even before SLIFNAME, the ai
* itself would be NULL, in which case we can complete the close
* without waiting.
*/
}
/*
* If the ill had completed unplumbing before arp_modclose(), there
* would be no ill (and therefore, no ipsq) to serialize arp_modclose()
* so that we need to explicitly check for ARL_CONDEMNED and back off
* if it is set.
*/
return (0);
}
/*
* send out all pending dlpi messages, don't wait for the ack (which
* will be ignored in arp_rput when CONDEMNED is set)
*
* We have to check for pending DL_UNBIND_REQ because, in the case
* that ip_modclose() executed before arp_modclose(), the call to
* ill_delete_tail->ipif_arp_down() would have triggered a
* DL_UNBIND_REQ. When arp_modclose() executes ipsq_enter() will fail
* (since ip_modclose() is in the ipsq) but the DL_UNBIND_ACK may not
* have been processed yet. In this scenario, we cannot reset
* related to unbind, and the associated cv_waits must be allowed to
* continue.
*/
}
/* Wait for data paths to quiesce */
while (arl->arl_refcnt != 0)
/*
* unbind, so that nothing else can come up from driver.
*/
/* wait for unbind ack */
qprocsoff(q);
ill->ill_arl_dlpi_pending = 0;
}
} else {
}
}
/* free up the rest */
return (0);
}
static void
{
/*
* credp could be null if the open didn't succeed and ip_modopen
* itself calls ip_close.
*/
/* Free all retained control messages. */
do {
while (mpp[0]) {
}
}
}
/*
* DAD failed. Tear down ipifs with the specified srce address. Note that
* tearing down the ipif also meas deleting the ncec through ipif_down,
* so it is not possible to use nce_timer for recovery. Instead we start
* a timer on the ipif. Caller has to free the mp.
*/
void
{
}
}
/*
* This is for exclusive changes due to ARP. Tear down an interface due
* to AR_CN_FAILED and AR_CN_BOGON.
*/
/* ARGSUSED */
static void
{
/* first try src = ar$spa */
/*
* Ignore conflicts generated by misbehaving switches that
* just reflect our own messages back to us. For IPMP, we may
* see reflections across any ill in the illgrp.
*/
/* For an under ill_grp can change under lock */
goto ignore_conflict;
}
}
/*
* Look up the appropriate ipif.
*/
goto ignore_conflict;
/* Reload the ill to match the ipif */
/* If it's already duplicate or ineligible, then don't do anything. */
goto ignore_conflict;
}
/*
* If we failed on a recovery probe, then restart the timer to
* try again later.
*/
if (!ipif->ipif_was_dup) {
char hbuf[MAC_STR_LEN];
char sbuf[INET_ADDRSTRLEN];
}
(void) ipif_down_tail(ipif);
ipst->ips_ip_dup_recovery > 0) {
}
}
/*
* This is a place for a dtrace hook.
* Note that mp can be either the DL_UNITDATA_IND with a b_cont payload,
* or just the ARP packet payload as an M_DATA.
*/
/* ARGSUSED */
static void
{
}
static boolean_t
{
/*
* check if first module below stream head is IP or UDP.
*/
/*
* module below is not ip or udp, so arp has been pushed
* on the driver.
*/
return (B_TRUE);
}
return (B_FALSE);
}
static int
{
int err;
if (!arp_over_driver(q)) {
}
return (err);
}
/*
* In most cases we must be a writer on the IP stream before coming to
* arp_dlpi_send(), to serialize DLPI sends to the driver. The exceptions
* when we are not a writer are very early duing initialization (in
* arl_init, before the arl has done a SLIFNAME, so that we don't yet know
* the associated ill) or during arp_mod_close, when we could not enter the
* ipsq because the ill has already unplumbed.
*/
static void
{
#ifdef DEBUG
}
#endif /* DEBUG */
/* Must queue message. Tail insertion */
return;
}
== DL_BIND_REQ) {
}
/*
* No need to take the arl_lock to examine ARL_CONDEMNED at this point
* because the only thread that can see ARL_CONDEMNED here is the
* closing arp_modclose() thread which sets the flag after becoming a
* writer on the ipsq. Threads from IP must have finished and
* cannot be active now.
*/
(prim == DL_UNBIND_REQ)) {
if (prim != DL_NOTIFY_CONF) {
}
}
}
}
static void
{
/*
* Till the ill is fully up the ill is not globally visible.
* So no need for a lock.
*/
if (!arl->arl_dlpi_style_set) {
}
}
int
{
/* subset of ill_init */
BPRI_HI);
return (ENOMEM);
/*
* allocate sufficient space to contain device name.
*/
/* Send down the Info Request to the driver. */
qprocson(q);
return (0);
}
int
{
int err;
/*
* Return value of 0 indicates a pending signal.
*/
if (err == 0) {
return (EINTR);
}
}
/*
* ip_rput_other could have set an error in ill_error on
* receipt of M_ERROR.
*/
}
void
{
}
}
int
{
int muxid = 0;
}
return (muxid);
}
static int
{
int err;
netstack_t *ns;
/*
* Prevent unprivileged processes from pushing IP so that
* they can't send raw IP.
*/
if (secpolicy_net_rawaccess(credp) != 0)
return (EPERM);
/*
* For exclusive stacks we set the zoneid to zero
* to make IP operate as if in the global zone.
*/
else
if (err != 0) {
return (err);
}
/*
* Wait for the DL_INFO_ACK if a DL_INFO_REQ was sent.
*/
if (err == 0)
else
goto fail;
fail:
if (err) {
(void) arp_close(q, 0);
return (err);
}
return (0);
}
/*
* Notify any downstream modules (esp softmac and hitbox) of the name
* of this interface using an M_CTL.
*/
static void
{
return;
return;
}
/* Use M_CTL to avoid confusing anyone else who might be listening. */
}
void
{
return;
/*
* arl_got_replumb and arl_got_unbind to be cleared after we complete
* arp_cmd_done.
*/
}
/*
* The unplumb code paths call arp_unbind_complete() to make sure that it is
* safe to tear down the ill. We wait for DL_UNBIND_ACK to complete, and also
* for the arl_refcnt to fall to one so that, when we return from
* arp_unbind_complete(), we know for certain that there are no threads in
* arp_rput() that might access the arl_ill.
*/
void
{
return;
/*
* wait for unbind ack and arl_refcnt to drop to 1. Note that the
* quiescent arl_refcnt for this function is 1 (and not 0) because
* ill_to_arl() will itself return after taking a ref on the arl_t.
*/
}