/*
* 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 (c) 1990 Mentat Inc. */
#include <inet/kstatcom.h>
#include <netinet/igmp_var.h>
#include <inet/ip_multi.h>
#include <inet/ip_ftable.h>
#include <inet/ip_listutils.h>
#include <netinet/ip_mroute.h>
#include <inet/ipp_common.h>
#include <inet/ipsec_impl.h>
#include <inet/ip_netinfo.h>
#include <sys/squeue_impl.h>
#include <inet/ipclassifier.h>
#include <inet/udp_impl.h>
/*
* Release a reference on ip_xmit_attr.
* The reference is acquired by conn_get_ixa()
*/
{ \
ixa_inactive(ixa); \
}
{ \
}
/*
* When we need to handle a transmit side asynchronous operation, then we need
* to save sufficient information so that we can call the fragment and postfrag
* functions. That information is captured in an mblk containing this structure.
*
* Since this is currently only used for IPsec, we include information for
* the kernel crypto framework.
*/
typedef struct ixamblk_s {
/*
* When the pointers below are set they have a refhold on the struct.
*/
/* Need these while waiting for SA */
} ixamblk_t;
/*
* When we need to handle a receive side asynchronous operation, then we need
* to save sufficient information so that we can call ip_fanout.
* That information is captured in an mblk containing this structure.
*
* Since this is currently only used for IPsec, we include information for
* the kernel crypto framework.
*/
typedef struct iramblk_s {
/*
* When set these correspond to a refhold on the object.
*/
} iramblk_t;
/*
* Take the information in ip_xmit_attr_t and stick it in an mblk
* that can later be passed to ip_xmit_attr_from_mblk to recreate the
* ip_xmit_attr_t.
*
* Returns NULL on memory allocation failure.
*/
mblk_t *
{
return (NULL);
}
}
}
}
}
}
}
}
return (ixamp);
}
/*
* Extract the ip_xmit_attr_t from the mblk, checking that the
* ip_stack_t, ill_t, and nce_t still exist. Returns B_FALSE if that is
* not the case.
*
* Otherwise ixa is updated.
* Caller needs to release references on the ixa by calling ixa_refrele()
* which will imediately call ixa_inactive to release the references.
*/
{
/* We assume the caller hasn't initialized ixa */
/* Verify the netstack is still around */
/* Disappeared on us */
(void) ip_xmit_attr_free_mblk(ixamp);
return (B_FALSE);
}
/* Verify the ill is still around */
/* We have the ill, hence the netstack can't go away */
/* Disappeared on us */
(void) ip_xmit_attr_free_mblk(ixamp);
return (B_FALSE);
}
/*
* Find the nce. We don't load-spread (only lookup nce's on the ill)
* because we want to find the same nce as the one we had when
* ip_xmit_attr_to_mblk was called.
*/
} else {
}
/* We have the nce, hence the ill can't go away */
/*
* Since this is unusual and we don't know what type of
* nce it was, we drop the packet.
*/
(void) ip_xmit_attr_free_mblk(ixamp);
return (B_FALSE);
}
}
}
return (B_TRUE);
}
/*
* Free the ixm mblk and any references it holds
* Returns b_cont.
*/
mblk_t *
{
/* Consume mp */
}
}
}
}
if (ixm->ixm_ipsec_latch) {
}
}
}
return (mp);
}
/*
* Take the information in ip_recv_attr_t and stick it in an mblk
* that can later be passed to ip_recv_attr_from_mblk to recreate the
* ip_recv_attr_t.
*
* Returns NULL on memory allocation failure.
*/
mblk_t *
{
return (NULL);
/* Internal to IP - preserve ip_stack_t, ill and rill */
irm->irm_stackid =
ira->ira_rifindex);
} else {
/* Let ip_recv_attr_from_stackid know there isn't one */
}
}
}
}
}
}
}
return (iramp);
}
/*
* Extract the ip_recv_attr_t from the mblk. If we are used inside IP
* then irm_stackid is not -1, in which case we check that the
* ip_stack_t and ill_t still exist. Returns B_FALSE if that is
* not the case.
* If irm_stackid is zero then we are used by an ULP (e.g., squeue_enter)
* and we just proceed with ira_ill and ira_rill as NULL.
*
* The caller needs to release any references on the pointers inside the ire
* by calling ira_cleanup.
*/
{
/* We assume the caller hasn't initialized ira */
/* Verify the netstack is still around */
/* Disappeared on us */
(void) ip_recv_attr_free_mblk(iramp);
return (B_FALSE);
}
/* Verify the ill is still around */
} else {
}
/* We have the ill, hence the netstack can't go away */
/* Disappeared on us */
(void) ip_recv_attr_free_mblk(iramp);
return (B_FALSE);
}
}
/* Caller must ill_refele(ira_ill) by using ira_cleanup() */
/* The rest of IP assumes that the rings never go away. */
}
}
return (B_TRUE);
}
/*
* Free the irm mblk and any references it holds
* Returns b_cont.
*/
mblk_t *
{
/* Consume mp */
}
}
}
}
}
return (mp);
}
/*
* Returns true if the mblk contains an ip_recv_attr_t
* For now we just check db_type.
*/
{
/*
* Need to handle the various forms of tcp_timermp which are tagged
* with b_wptr and might have a NULL b_datap.
*/
return (B_FALSE);
#ifdef DEBUG
return (B_FALSE);
return (B_TRUE);
#else
#endif
}
static ip_xmit_attr_t *
{
/* At least one references for the conn_t */
/* No other thread using conn_ixa */
return (ixa);
}
return (NULL);
}
/* Make sure we drop conn_lock before any refrele */
if (replace) {
} else {
}
return (ixa);
}
/*
* Return an ip_xmit_attr_t to use with a conn_t that ensures that only
* the caller can access the ip_xmit_attr_t.
*
* If nobody else is using conn_ixa we return it.
* Otherwise we make a "safe" copy of conn_ixa
* and return it. The "safe" copy has the pointers set to NULL
* (since the pointers might be changed by another thread using
* conn_ixa). The caller needs to check for NULL pointers to see
* if ip_set_destination needs to be called to re-establish the pointers.
*
* If 'replace' is set then we replace conn_ixa with the new ip_xmit_attr_t.
* That is used when we connect() the ULP.
*/
{
}
/*
* Used only when the option is to have the kernel hang due to not
* cleaning up ixa references on ills etc.
*/
{
}
/*
* Replace conn_ixa with the ixa argument.
*
* The caller must hold conn_lock.
*
* We return the old ixa; the caller must ixa_refrele that after conn_lock
* has been dropped.
*/
{
return (oldixa);
}
/*
* Return a ip_xmit_attr_t to use with a conn_t that is based on but
* separate from conn_ixa.
*
* This "safe" copy has the pointers set to NULL
* (since the pointers might be changed by another thread using
* conn_ixa). The caller needs to check for NULL pointers to see
* if ip_set_destination needs to be called to re-establish the pointers.
*/
{
/* At least one references for the conn_t */
/* Make sure conn_ixa doesn't disappear while we copy it */
return (NULL);
}
return (ixa);
}
void
{
/*
* Clear any pointers that have references and might be changed
* by ip_set_destination or the ULP
*/
#ifdef DEBUG
#endif
/* Clear all the IPsec pointers and the flag as well. */
/*
* We leave ixa_tsl unchanged, but if it has a refhold we need
* to get an extra refhold.
*/
/*
* We leave ixa_cred unchanged, but if it has a refhold we need
* to get an extra refhold.
*/
}
/*
* Duplicate an ip_xmit_attr_t.
* Assumes that the caller controls the ixa, hence we do not need to use
* a safe copy. We just have to increase the refcnt on any pointers.
*/
{
return (NULL);
#ifdef DEBUG
#endif
}
}
return (ixa);
}
/*
* Used to replace the ixa_label field.
* The caller should have a reference on the label, which we transfer to
* we will release that reference.
*/
void
{
} else {
}
}
/*
* Replace the ip_recv_attr_t's label.
* Due to kernel RPC's use of db_credp we also need to replace ira_cred;
* This can fail (and return B_FALSE) due to lack of memory.
*/
{
}
/*
* Reset zoneid if we have a shared address. That allows
* ip_fanout_tx_v4/v6 to determine the zoneid again.
*/
/* We update ira_cred for RPC */
return (B_FALSE);
return (B_TRUE);
}
/*
* This needs to be called after ip_set_destination/tsol_check_dest might
* have changed ixa_tsl to be specific for a destination, and we now want to
* send to a different destination.
* We have to restart with crgetlabel() since ip_set_destination/
* tsol_check_dest will start with ixa_tsl.
*/
void
{
if (!is_system_labeled())
return;
}
}
void
{
}
void
{
}
/*
* Release any references contained in the ixa.
* Also clear any fields that are not controlled by ixa_flags.
*/
void
{
}
}
}
}
}
}
ixa->ixa_src_preferences = 0;
ixa->ixa_ifindex = 0;
ixa->ixa_multicast_ifindex = 0;
}
/*
* Release any references contained in the ira.
* Callers which use ip_recv_attr_from_mblk() would pass B_TRUE as the second
* argument.
*/
void
{
/* Caused by async processing */
}
if (refrele_ill)
}
}
}
}
}
/*
* Function to help release any IRE, NCE, or DCEs that
* have been deleted and are marked as condemned.
* The caller is responsible for any serialization which is different
* for TCP, SCTP, and others.
*/
static void
{
#ifdef DEBUG
#endif
}
/* Can make it NULL as long as we set IRE_GENERATION_VERIFY */
}
#ifdef DEBUG
#endif
}
}
static mblk_t *
{
int need_retry;
/*
* It's possible that someone else came in and started cleaning up
* another connection between the time we verified this one is not being
* cleaned up and the time we actually get the shared mblk. If that's
* the case, we've dropped the lock, and some other thread may have
* cleaned up this connection again, and is still waiting for
* notification of that cleanup's completion. Therefore we need to
* recheck.
*/
do {
need_retry = 0;
}
/*
* Multiple concurrent cleanups; need to have the last
* one run since it could be an unplumb.
*/
need_retry = 1;
}
} while (need_retry);
/*
* We now have the lock and the mblk; now make sure that no one else can
* try to clean up this connection or enqueue it for cleanup, clear the
* mblk pointer for this stack, drop the lock, and return the mblk.
*/
return (mp);
}
/*
* Used to run ixa_cleanup_stale inside the tcp squeue.
* When done we hand the mp back by assigning it to tcps_ixa_cleanup_mp
* and waking up the caller.
*/
/* ARGSUSED2 */
static void
{
/*
* It is possible for any number of threads to be waiting for cleanup of
* different connections. Absent a per-connection (or per-IXA) CV, we
* need to wake them all up even though only one can be waiting on this
* particular cleanup.
*/
}
static void
{
}
}
/*
* ipcl_walk() function to help release any IRE, NCE, or DCEs that
* have been deleted and are marked as condemned.
* Note that we can't cleanup the pointers since there can be threads
* in conn_ip_output() sending while we are called.
*/
void
{
if (IPCL_IS_TCP(connp)) {
/* Already on squeue */
} else {
}
} else if (IPCL_IS_SCTP(connp)) {
} else {
/*
* If there is a different thread using conn_ixa then we get a
* new copy and cut the old one loose from conn_ixa. Otherwise
* we use conn_ixa and prevent any other thread from
* conn_ip_output) will do an ixa_refrele which will remove any
* references on the ire etc.
*
* Once we are done other threads can use conn_ixa since the
* refcnt will be back at one.
*
* We are called either because an ill is going away, or
* due to memory reclaim. In the former case we wait for
* memory since we must remove the refcnts on the ill.
*/
if (tryhard) {
} else {
/*
* Somebody else was using it and kmem_alloc
* failed! Next memory reclaim will try to
* clean up.
*/
return;
}
}
}
}
/*
* ixa needs to be an exclusive copy so that no one changes the cookie
* or the ixa_nce.
*/
{
/*
* If `cookie' is zero, ip_xmit() -> canputnext() failed -- i.e., flow
* control is asserted on an ill that does not support direct calls.
* Jump to insert.
*/
if (cookie == 0)
goto tryinsert;
/* TODO: bump kstat for cookie collision */
} else {
/*
* will not suffice since two separate UDP threads may be
* racing to send to different destinations that are
* associated with different cookies and thus may not be
* holding the same txl_lock. Further, since a given conn_t
* can only be on a single drain list, the conn_t will be
* enqueued on whichever thread wins this race.
*/
if (connp->conn_blocked) {
} else {
if (!IPCL_IS_NONSTR(connp))
}
}
return (inserted);
}