OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sctp/sctp_cache.c


File /code/strss7/drivers/sctp/sctp_cache.c



#ident "@(#) $RCSfile: sctp_cache.c,v $ $Name:  $($Revision: 0.8.2.11 $) $Date: 2003/05/30 21:15:52 $"

static char const ident[] =
    "$RCSfile: sctp_cache.c,v $ $Name:  $($Revision: 0.8.2.11 $) $Date: 2003/05/30 21:15:52 $";

#define __NO_VERSION__

#include <linux/config.h>
#include <linux/version.h>
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/module.h>

#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/cmn_err.h>
#include <sys/dki.h>

#include "../debug.h"
#include "../bufq.h"

#include "sctp.h"
#include "sctp_defs.h"
#include "sctp_hash.h"
#include "sctp_cache.h"

#undef min			/* LiS should not have defined these */
#undef max			/* LiS should not have defined these */

#define sctp_daddr sctp_daddr__
#define sctp_saddr sctp_saddr__
#define sctp_strm  sctp_strm__
#define sctp_dup   sctp_dup__
#ifdef ASSERT
#undef ASSERT
#endif

#include <net/ip.h>
#include <net/icmp.h>
#include <net/route.h>

#undef sctp_daddr
#undef sctp_saddr
#undef sctp_strm
#undef sctp_dup
#ifdef ASSERT
#undef ASSERT
#endif

#include "sctp_msg.h"

/* ip defaults */
uint sctp_default_ip_tos = SCTP_DEFAULT_IP_TOS;
uint sctp_default_ip_ttl = SCTP_DEFAULT_IP_TTL;
uint sctp_default_ip_proto = SCTP_DEFAULT_IP_PROTO;
uint sctp_default_ip_dontroute = SCTP_DEFAULT_IP_DONTROUTE;
uint sctp_default_ip_broadcast = SCTP_DEFAULT_IP_BROADCAST;
uint sctp_default_ip_priority = SCTP_DEFAULT_IP_PRIORITY;

/* per association defaults */
size_t sctp_default_max_init_retries = SCTP_DEFAULT_MAX_INIT_RETRIES;
size_t sctp_default_valid_cookie_life = SCTP_DEFAULT_VALID_COOKIE_LIFE;
size_t sctp_default_max_sack_delay = SCTP_DEFAULT_MAX_SACK_DELAY;
size_t sctp_default_assoc_max_retrans = SCTP_DEFAULT_ASSOC_MAX_RETRANS;
size_t sctp_default_mac_type = SCTP_DEFAULT_MAC_TYPE;
size_t sctp_default_cookie_inc = SCTP_DEFAULT_COOKIE_INC;
size_t sctp_default_throttle_itvl = SCTP_DEFAULT_THROTTLE_ITVL;
size_t sctp_default_req_ostreams = SCTP_DEFAULT_REQ_OSTREAMS;
size_t sctp_default_max_istreams = SCTP_DEFAULT_MAX_ISTREAMS;
size_t sctp_default_rmem = SCTP_DEFAULT_RMEM;
size_t sctp_default_ppi = SCTP_DEFAULT_PPI;
size_t sctp_default_sid = SCTP_DEFAULT_SID;

/* per destination defaults */
size_t sctp_default_path_max_retrans = SCTP_DEFAULT_PATH_MAX_RETRANS;
size_t sctp_default_rto_initial = SCTP_DEFAULT_RTO_INITIAL;
size_t sctp_default_rto_min = SCTP_DEFAULT_RTO_MIN;
size_t sctp_default_rto_max = SCTP_DEFAULT_RTO_MAX;
size_t sctp_default_heartbeat_itvl = SCTP_DEFAULT_HEARTBEAT_ITVL;

/*
 *  Cache pointers
 *  -------------------------------------------------------------------------
 */
kmem_cache_t *sctp_sctp_cachep = NULL;
kmem_cache_t *sctp_dest_cachep = NULL;
kmem_cache_t *sctp_srce_cachep = NULL;
kmem_cache_t *sctp_strm_cachep = NULL;

void sctp_init_caches(void)
{
	if (!sctp_sctp_cachep &&
	    !(sctp_sctp_cachep =
	      kmem_cache_create("sctp_sctp_cachep", sizeof(sctp_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s:Cannot alloc sctp_sctp_cachep.\n", __FUNCTION__);
	if (!sctp_dest_cachep &&
	    !(sctp_dest_cachep =
	      kmem_cache_create("sctp_dest_cachep", sizeof(sctp_daddr_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s:Cannot alloc sctp_dest_cachep.\n", __FUNCTION__);
	if (!sctp_srce_cachep &&
	    !(sctp_srce_cachep =
	      kmem_cache_create("sctp_srce_cachep", sizeof(sctp_saddr_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s:Cannot alloc sctp_srce_cachep.\n", __FUNCTION__);
	if (!sctp_strm_cachep &&
	    !(sctp_strm_cachep =
	      kmem_cache_create("sctp_strm_cachep", sizeof(sctp_strm_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
		panic("%s:Cannot alloc sctp_strm_cachep.\n", __FUNCTION__);
	return;
}
void sctp_term_caches(void)
{
	if (sctp_sctp_cachep)
		if (kmem_cache_destroy(sctp_sctp_cachep))
			cmn_err(CE_WARN, "%s: did not destroy sctp_sctp_cachep");
	if (sctp_dest_cachep)
		if (kmem_cache_destroy(sctp_dest_cachep))
			cmn_err(CE_WARN, "%s: did not destroy sctp_dest_cachep");
	if (sctp_srce_cachep)
		if (kmem_cache_destroy(sctp_srce_cachep))
			cmn_err(CE_WARN, "%s: did not destroy sctp_srce_cachep");
	if (sctp_strm_cachep)
		if (kmem_cache_destroy(sctp_strm_cachep))
			cmn_err(CE_WARN, "%s: did not destroy sctp_strm_cachep");
	return;
}

/*
 *  -------------------------------------------------------------------------
 *
 *  DESTINATION ADDRESS HANDLING
 *
 *  -------------------------------------------------------------------------
 *
 *  Allocate a Destination Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC sctp_daddr_t *__sctp_daddr_alloc(sp, daddr, errp)
	sctp_t *sp;
	uint32_t daddr;
	int *errp;
{
	sctp_daddr_t *sd;
	assert(errp);
	ensure(sp, *errp = -EFAULT;
	       return (NULL));
	if (!daddr)
		return (NULL);
	if (!(daddr & 0xff000000)) {	/* zeronet is illegal */
		assure(daddr & 0xff000000);
		*errp = -EADDRNOTAVAIL;
		seldom();
		return (NULL);
	}
	/* 
	 *  TODO: need to check permissions (TACCES) for broadcast or multicast addresses
	 *  and whether host addresses are valid (TBADADDR).
	 */
	if ((sd = kmem_cache_alloc(sctp_dest_cachep, SLAB_ATOMIC))) {
		bzero(sd, sizeof(*sd));
		if ((sd->next = sp->daddr))
			sd->next->prev = &sd->next;
		sd->prev = &sp->daddr;
		sp->daddr = sd;
		sp->danum++;
		sd->sp = sp;
		sd->daddr = daddr;
		sd->mtu = 576;	/* fix up after routing */
		sd->ssthresh = 2 * sd->mtu;	/* fix up after routing */
		sd->cwnd = sd->mtu;	/* fix up after routing */
		/* per destination defaults */
		sd->hb_itvl = sp->hb_itvl;	/* heartbeat interval */
		sd->rto_max = sp->rto_max;	/* maximum RTO */
		sd->rto_min = sp->rto_min;	/* minimum RTO */
		sd->rto = sp->rto_ini;	/* initial RTO */
		sd->max_retrans = sp->rtx_path;	/* max path retrans */
		return (sd);
	}
	*errp = -ENOMEM;
	rare();
	return (NULL);
}

/*
 *  Find or Add a Destination Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
sctp_daddr_t *sctp_daddr_include(sp, daddr, errp)
	sctp_t *sp;
	uint32_t daddr;
	int *errp;
{
	sctp_daddr_t *sd;
	assert(errp);
	ensure(sp, *errp = -EFAULT;
	       return (NULL));
	SCTPHASH_WLOCK();
	if (!(sd = sctp_find_daddr(sp, daddr)))
		sd = __sctp_daddr_alloc(sp, daddr, errp);
	SCTPHASH_WUNLOCK();
	usual(sd);
	return (sd);
}

/*
 *  Free a Destination Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void __sctp_daddr_free(sd)
	sctp_daddr_t *sd;
{
	ensure(sd, return);
	/* 
	 *  Need to free any cached IP routes.
	 */
	if (sd->dst_cache) {
		rare();
		dst_release(xchg(&sd->dst_cache, NULL));
	}
	if (sd->timer_idle) {
		rare();
		untimeout(xchg(&sd->timer_idle, 0));
	}
	if (sd->timer_heartbeat) {
		rare();
		untimeout(xchg(&sd->timer_heartbeat, 0));
	}
	if (sd->timer_retrans) {
		rare();
		untimeout(xchg(&sd->timer_retrans, 0));
	}
	if (sd->sp)
		sd->sp->danum--;
	if ((*sd->prev = sd->next))
		sd->next->prev = sd->prev;
	kmem_cache_free(sctp_dest_cachep, sd);
}

/*
 *  Free all Destination Addresses
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void __sctp_free_daddrs(sctp_t * sp)
{
	sctp_daddr_t *sd, *sd_next;
	ensure(sp, return);
	sd_next = sp->daddr;
	usual(sd_next);
	while ((sd = sd_next)) {
		sd_next = sd->next;
		__sctp_daddr_free(sd);
	}
	unless(sp->danum, sp->danum = 0);
	sp->dport = 0;
	sp->taddr = NULL;
	sp->raddr = NULL;
	sp->caddr = NULL;
}

/*
 *  Allocate a group of Destination Addresses
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
int sctp_alloc_daddrs(sctp_t * sp, uint16_t dport, uint32_t * daddrs, size_t dnum)
{
	int err = 0;
	ensure(sp, return (-EFAULT));
	ensure(daddrs || !dnum, return (-EFAULT));
	SCTPHASH_WLOCK();
	if (sp->daddr || sp->danum) {
		rare();
		__sctp_free_daddrs(sp);
	}			/* start clean */
	sp->dport = dport;
	if (dnum) {
		while (dnum--)
			if (!__sctp_daddr_alloc(sp, daddrs[dnum], &err) && err) {
				rare();
				break;
			}
	} else
		usual(dnum);
	if (err) {
		rare();
		__sctp_free_daddrs(sp);
	}
	SCTPHASH_WUNLOCK();
	if (err) {
		abnormal(err);
		ptrace(("Returning error %d\n", err));
	}
	return (err);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  SOURCE ADDRESS HANDLING
 *
 *  -------------------------------------------------------------------------
 *
 *  Allocate a Source Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC sctp_saddr_t *__sctp_saddr_alloc(sp, saddr, errp)
	sctp_t *sp;
	uint32_t saddr;
	int *errp;
{
	sctp_saddr_t *ss;
	assert(errp);
	ensure(sp, *errp = -EFAULT;
	       return (NULL));
	if (!saddr) {
		rare();
		return (NULL);
	}
	if ((ss = kmem_cache_alloc(sctp_srce_cachep, SLAB_ATOMIC))) {
		bzero(ss, sizeof(*ss));
		if ((ss->next = sp->saddr))
			ss->next->prev = &ss->next;
		ss->prev = &sp->saddr;
		sp->saddr = ss;
		sp->sanum++;
		ss->sp = sp;
		ss->saddr = saddr;
		return (ss);
	}
	*errp = -ENOMEM;
	rare();
	return (ss);
}

/*
 *  Find or Add a Source Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
sctp_saddr_t *sctp_saddr_include(sp, saddr, errp)
	sctp_t *sp;
	uint32_t saddr;
	int *errp;
{
	sctp_saddr_t *ss;
	assert(errp);
	ensure(sp, *errp = -EFAULT;
	       return (NULL));
	SCTPHASH_WLOCK();
	if (!(ss = sctp_find_saddr(sp, saddr)))
		ss = __sctp_saddr_alloc(sp, saddr, errp);
	SCTPHASH_WUNLOCK();
	usual(ss);
	return (ss);
}

/*
 *  Free a Source Address
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void __sctp_saddr_free(ss)
	sctp_saddr_t *ss;
{
	assert(ss);
	if (ss->sp)
		ss->sp->sanum--;
	if ((*ss->prev = ss->next))
		ss->next->prev = ss->prev;
	kmem_cache_free(sctp_srce_cachep, ss);
}

/*
 *  Free all Source Addresses
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void __sctp_free_saddrs(sctp_t * sp)
{
	sctp_saddr_t *ss, *ss_next;
	assert(sp);
	ss_next = sp->saddr;
	usual(ss_next);
	while ((ss = ss_next)) {
		ss_next = ss->next;
		__sctp_saddr_free(ss);
	}
	unless(sp->sanum, sp->sanum = 0);
	sp->sport = 0;
}

/*
 *  Allocate a group of Source Addresses
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
int sctp_alloc_saddrs(sp, sport, saddrs, snum)
	sctp_t *sp;
	uint16_t sport;
	uint32_t *saddrs;
	size_t snum;
{
	int err = 0;
	ensure(sp, return (-EFAULT));
	ensure(saddrs || !snum, return (-EFAULT));
	SCTPHASH_WLOCK();
	if (sp->saddr || sp->sanum) {
		rare();
		__sctp_free_saddrs(sp);
	}			/* start clean */
	sp->sport = sport;
	if (snum) {
		while (snum--)
			if (!__sctp_saddr_alloc(sp, saddrs[snum], &err) && err) {
				rare();
				break;
			}
	} else
		usual(snum);
	if (err) {
		rare();
		__sctp_free_saddrs(sp);
	}
	SCTPHASH_WUNLOCK();
	return (err);
}

/*
 *  -------------------------------------------------------------------------
 *
 *  SCTP Stream handling
 *
 *  -------------------------------------------------------------------------
 *
 *  Allocate an Inbound or Outbound Stream
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
sctp_strm_t *sctp_strm_alloc(stp, sid, errp)
	sctp_strm_t **stp;
	uint16_t sid;
	int *errp;
{
	sctp_strm_t *st;
	if ((st = kmem_cache_alloc(sctp_strm_cachep, SLAB_ATOMIC))) {
		bzero(st, sizeof(*st));
		if ((st->next = (*stp)))
			st->next->prev = &st->next;
		st->prev = stp;
		(*stp) = st;
		st->sid = sid;
		return (st);
	}
	*errp = -ENOMEM;
	rare();
	return (NULL);
}

/*
 *  Free a Stream
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void sctp_strm_free(st)
	sctp_strm_t *st;
{
	assert(st);
	if ((*st->prev = st->next))
		st->next->prev = st->prev;
	kmem_cache_free(sctp_strm_cachep, st);
}

/*
 *  Free all Streams
 *  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 */
STATIC void sctp_free_strms(sp)
	sctp_t *sp;
{
	sctp_strm_t *st, *st_next;
	assert(sp);
	st_next = sp->ostrm;
	usual(st_next);
	while ((st = st_next)) {
		st_next = st->next;
		sctp_strm_free(st);
	}
	sp->ostr = NULL;
	st_next = sp->istrm;
	usual(st_next);
	while ((st = st_next)) {
		st_next = st->next;
		sctp_strm_free(st);
	}
	sp->istr = NULL;
}

/*
 *  =========================================================================
 *
 *  SCTP Private Data Structure Functions
 *
 *  =========================================================================
 *
 *  We use Linux hardware aligned cache here for speedy access to information
 *  contained in the private data structure.
 */
sctp_t *sctp_alloc_priv(q, spp, cmajor, cminor, ops)
	queue_t *q;
	sctp_t **spp;
	int cmajor;
	int cminor;
	struct sctp_ifops *ops;
{
	sctp_t *sp;

	assert(q);
	assert(spp);

	/* must have these 4 */
	ensure(ops->sctp_conn_ind, return (NULL));
	ensure(ops->sctp_conn_con, return (NULL));
	ensure(ops->sctp_data_ind, return (NULL));
	ensure(ops->sctp_discon_ind, return (NULL));

	assure(cmajor);
	assure(cminor);

	if ((sp = kmem_cache_alloc(sctp_sctp_cachep, SLAB_ATOMIC))) {
		MOD_INC_USE_COUNT;
		bzero(sp, sizeof(*sp));

		/* link into master list */
		if ((sp->next = *spp))
			sp->next->prev = &sp->next;
		sp->prev = spp;
		*spp = sp;

		RD(q)->q_ptr = WR(q)->q_ptr = sp;
		sp->rq = RD(q);
		sp->wq = WR(q);
		sp->cmajor = cmajor;
		sp->cminor = cminor;
		sp->ops = ops;
		sp->i_state = 0;
		sp->s_state = SCTP_CLOSED;

		/* ip defaults */
		sp->ip_tos = sctp_default_ip_tos;
		sp->ip_ttl = sctp_default_ip_ttl;
		sp->ip_proto = sctp_default_ip_proto;
		sp->ip_dontroute = sctp_default_ip_dontroute;
		sp->ip_broadcast = sctp_default_ip_broadcast;
		sp->ip_priority = sctp_default_ip_priority;

		/* per association defaults */
		sp->max_istr = sctp_default_max_istreams;
		sp->req_ostr = sctp_default_req_ostreams;
		sp->max_inits = sctp_default_max_init_retries;
		sp->max_retrans = sctp_default_assoc_max_retrans;
		sp->a_rwnd = sctp_default_rmem;
		sp->ck_life = sctp_default_valid_cookie_life;
		sp->ck_inc = sctp_default_cookie_inc;
		sp->hmac = sctp_default_mac_type;
		sp->throttle = sctp_default_throttle_itvl;
		sp->sid = sctp_default_sid;
		sp->ppi = sctp_default_ppi;
		sp->max_sack = sctp_default_max_sack_delay;

		/* per destination association defaults */
		sp->rto_ini = sctp_default_rto_initial;
		sp->rto_min = sctp_default_rto_min;
		sp->rto_max = sctp_default_rto_max;
		sp->rtx_path = sctp_default_path_max_retrans;
		sp->hb_itvl = sctp_default_heartbeat_itvl;

		bufq_init(&sp->rcvq);
		bufq_init(&sp->sndq);
		bufq_init(&sp->urgq);
		bufq_init(&sp->errq);

		bufq_init(&sp->oooq);
		bufq_init(&sp->dupq);
		bufq_init(&sp->rtxq);
		bufq_init(&sp->ackq);
		bufq_init(&sp->conq);

		sctp_init_lock(sp);

		sp->pmtu = 576;

		sp->s_state = SCTP_CLOSED;
	}
	usual(sp);
	return (sp);
}

void sctp_free_priv(q)
	queue_t *q;
{
	sctp_t *sp;

	ensure(q, return);

	sp = SCTP_PRIV(q);
	ensure(sp, return);

	SCTPHASH_WLOCK();
	{
		sp->s_state = SCTP_CLOSED;

		__sctp_unhash(sp);

		if (sp->timer_init) {
			rare();
			untimeout(xchg(&sp->timer_init, 0));
		}
		if (sp->timer_cookie) {
			rare();
			untimeout(xchg(&sp->timer_cookie, 0));
		}
		if (sp->timer_shutdown) {
			rare();
			untimeout(xchg(&sp->timer_shutdown, 0));
		}
		if (sp->timer_sack) {
			rare();
			untimeout(xchg(&sp->timer_sack, 0));
		}

		if (sp->saddr) {
			__sctp_free_saddrs(sp);
		}
		if (sp->daddr) {
			__sctp_free_daddrs(sp);
		}
	}
	SCTPHASH_WUNLOCK();

	unusual(sp->retry);
	freechunks(xchg(&sp->retry, NULL));

	sp->sackf = 0;
	sp->in_flight = 0;
	sp->retransmits = 0;
	sp->n_istr = 0;
	sp->n_ostr = 0;
	sp->v_tag = 0;
	sp->p_tag = 0;
	sp->p_rwnd = 0;

	unusual(sp->conq.q_msgs);
	bufq_purge(&sp->conq);

	unusual(sp->rq->q_count);
	flushq(sp->rq, FLUSHALL);
	unusual(sp->wq->q_count);
	flushq(sp->wq, FLUSHALL);

	unusual(sp->rcvq.q_msgs);
	bufq_purge(&sp->rcvq);
	unusual(sp->sndq.q_msgs);
	bufq_purge(&sp->sndq);
	unusual(sp->urgq.q_msgs);
	bufq_purge(&sp->urgq);
	unusual(sp->errq.q_msgs);
	bufq_purge(&sp->errq);

	unusual(sp->dupq.q_msgs);
	bufq_purge(&sp->dupq);
	unusual(sp->dups);
	sp->dups = NULL;
	unusual(sp->ndups);
	sp->ndups = 0;

#ifdef _DEBUG
	if (sp->oooq.q_msgs && sp->oooq.q_head) {
		mblk_t *mp;
		for (mp = sp->oooq.q_head; mp; mp = mp->b_next) {
			sctp_tcb_t *cb = SCTP_TCB(mp);
			printk("oooq tsn = %u\n", cb->tsn);
		}
	}
#endif
	unusual(sp->oooq.q_msgs);
	bufq_purge(&sp->oooq);
	unusual(sp->gaps);
	sp->gaps = NULL;
	unusual(sp->ngaps);
	sp->ngaps = 0;
	unusual(sp->nunds);
	sp->nunds = 0;

#ifdef _DEBUG
	if (sp->rtxq.q_msgs && sp->rtxq.q_head) {
		mblk_t *mp;
		for (mp = sp->rtxq.q_head; mp; mp = mp->b_next) {
			sctp_tcb_t *cb = SCTP_TCB(mp);
			printk("rtxq tsn = %u\n", cb->tsn);
		}
	}
#endif
	unusual(sp->rtxq.q_msgs);
	bufq_purge(&sp->rtxq);
	unusual(sp->nrtxs);
	sp->nrtxs = 0;
	unusual(sp->ackq.q_msgs);
	bufq_purge(&sp->ackq);

	/* do we really need to keep this stuff hanging around for retrieval? */
	if (sp->ostrm || sp->istrm) {
		sctp_free_strms(sp);
	}

	unusual(RD(q)->q_count);
	if (RD(q)->q_count)
		flushq(RD(q), FLUSHALL);
	unusual(WR(q)->q_count);
	if (WR(q)->q_count)
		flushq(WR(q), FLUSHALL);

	RD(q)->q_ptr = WR(q)->q_ptr = NULL;

	if ((*sp->prev = sp->next))
		sp->next->prev = sp->prev;
	sp->next = NULL;
	sp->prev = NULL;

	kmem_cache_free(sctp_sctp_cachep, sp);
	MOD_DEC_USE_COUNT;
}

/*
 *  DISCONNECT
 *  -------------------------------------------------------------------------
 *  Disconnect the STREAM.  The caller must send a disconnect indication to
 *  the user interface if necessary and send an abort if necessary.  This just
 *  pulls the stream out of the hashes, stops timers, frees simple
 *  retransmission, and zeros connection info.  The stream is left bound and
 *  destination addressses are left allocated.  Any connection indications are
 *  left queued against the stream.
 */
void sctp_disconnect(sp)
	sctp_t *sp;
{
	assert(sp);
	SCTPHASH_WLOCK();
	{
		sctp_daddr_t *sd;
		sp->s_state = sp->conind ? SCTP_LISTEN : SCTP_CLOSED;

		/* remove from connected hashes */
		__sctp_conn_unhash(sp);

		/* stop timers */
		if (sp->timer_init) {
			untimeout(xchg(&sp->timer_init, 0));
		}
		if (sp->timer_cookie) {
			untimeout(xchg(&sp->timer_cookie, 0));
		}
		if (sp->timer_shutdown) {
			untimeout(xchg(&sp->timer_shutdown, 0));
		}
		if (sp->timer_sack) {
			untimeout(xchg(&sp->timer_sack, 0));
		}

		for (sd = sp->daddr; sd; sd = sd->next) {
			if (sd->dst_cache) {
				dst_release(xchg(&sd->dst_cache, 0));
			}
			if (sd->timer_idle) {
				untimeout(xchg(&sd->timer_idle, 0));
			}
			if (sd->timer_retrans) {
				seldom();
				untimeout(xchg(&sd->timer_retrans, 0));
			}
			if (sd->timer_heartbeat) {
				seldom();
				untimeout(xchg(&sd->timer_heartbeat, 0));
			}
		}
	}
	SCTPHASH_WUNLOCK();

	unusual(sp->retry);
	freechunks(xchg(&sp->retry, NULL));

	sp->sackf = 0;
	sp->in_flight = 0;
	sp->retransmits = 0;
	sp->n_istr = 0;
	sp->n_ostr = 0;
	sp->v_tag = 0;
	sp->p_tag = 0;
	sp->p_rwnd = 0;
}

/*
 *  Non-locking version for use from within timeouts (runninga at
 *  bottom-half so don't do bottom-half locks).
 */
void __sctp_disconnect(sp)
	sctp_t *sp;
{
	sctp_daddr_t *sd;

	assert(sp);
	SCTPHASH_BH_WLOCK();
	{
		sp->s_state = sp->conind ? SCTP_LISTEN : SCTP_CLOSED;

		/* remove from connected hashes */
		__sctp_conn_unhash(sp);

		/* stop timers */
		if (sp->timer_init) {
			seldom();
			untimeout(xchg(&sp->timer_init, 0));
		}
		if (sp->timer_cookie) {
			seldom();
			untimeout(xchg(&sp->timer_cookie, 0));
		}
		if (sp->timer_shutdown) {
			seldom();
			untimeout(xchg(&sp->timer_shutdown, 0));
		}
		if (sp->timer_sack) {
			seldom();
			untimeout(xchg(&sp->timer_sack, 0));
		}

		for (sd = sp->daddr; sd; sd = sd->next) {
			if (sd->dst_cache) {
				seldom();
				dst_release(xchg(&sd->dst_cache, 0));
			}
			if (sd->timer_idle) {
				seldom();
				untimeout(xchg(&sd->timer_idle, 0));
			}
			if (sd->timer_retrans) {
				rare();
				untimeout(xchg(&sd->timer_retrans, 0));
			}
			if (sd->timer_heartbeat) {
				rare();
				untimeout(xchg(&sd->timer_heartbeat, 0));
			}
		}
	}
	SCTPHASH_BH_WUNLOCK();

	unusual(sp->retry);
	freechunks(xchg(&sp->retry, NULL));

	sp->sackf = 0;
	sp->in_flight = 0;
	sp->retransmits = 0;
	sp->n_istr = 0;
	sp->n_ostr = 0;
	sp->v_tag = 0;
	sp->p_tag = 0;
	sp->p_rwnd = 0;
}

/*
 *  UNBIND
 *  -------------------------------------------------------------------------
 *  We should already be in a disconnected state.  This pulls us from the bind
 *  hashes and deallocates source addresses, any connection indications that
 *  are queued against the stream are purged (these might occur if a
 *  connection indication comes in just before we unbind and we have made an
 *  error somewhere else: normally the response to an X_UNBIND_REQ in a
 *  connection indication state will be a X_ERROR_ACK).
 */
void sctp_unbind(sp)
	sctp_t *sp;
{
	assert(sp);
	SCTPHASH_WLOCK();
	{
		sp->s_state = SCTP_CLOSED;

		__sctp_bind_unhash(sp);
		__sctp_free_saddrs(sp);
	}
	SCTPHASH_WUNLOCK();

	unusual(sp->conq.q_msgs);
	bufq_purge(&sp->conq);
}

/*
 *  RESET
 *  -------------------------------------------------------------------------
 *  Clear the connection information hanging around on a stream.  This include
 *  any queued data blocks that are waitinga around for retrieval.  It is OK
 *  to call this function twice in a row on the same streeam.
 */
void sctp_reset(sp)
	sctp_t *sp;
{
	unusual(sp->rq->q_count);
	flushq(sp->rq, FLUSHALL);
	unusual(sp->wq->q_count);
	flushq(sp->wq, FLUSHALL);

	sp->pmtu = 576;

	/* purge queues */
	unusual(sp->rcvq.q_msgs);
	bufq_purge(&sp->rcvq);
	unusual(sp->sndq.q_msgs);
	bufq_purge(&sp->sndq);
	unusual(sp->urgq.q_msgs);
	bufq_purge(&sp->urgq);
	unusual(sp->errq.q_msgs);
	bufq_purge(&sp->errq);

	unusual(sp->dupq.q_msgs);
	bufq_purge(&sp->dupq);
	unusual(sp->dups);
	sp->dups = NULL;
	unusual(sp->ndups);
	sp->ndups = 0;

	unusual(sp->oooq.q_msgs);
	bufq_purge(&sp->oooq);
	unusual(sp->gaps);
	sp->gaps = NULL;
	unusual(sp->ngaps);
	sp->ngaps = 0;
	unusual(sp->nunds);
	sp->nunds = 0;

	unusual(sp->rtxq.q_msgs);
	bufq_purge(&sp->rtxq);
	unusual(sp->nrtxs);
	sp->nrtxs = 0;
	unusual(sp->ackq.q_msgs);
	bufq_purge(&sp->ackq);

	if (sp->ostrm || sp->istrm) {
		sctp_free_strms(sp);
	}
}


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/sctp/sctp_cache.c

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: