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_input.c


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



#ident "@(#) $RCSfile: sctp_input.c,v $ $Name:  $($Revision: 0.8.2.10 $) $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"
#include "sctp_route.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"
#include "sctp_input.h"
#include "sctp_output.h"

#include <linux/skbuff.h>

/* 
 *  =========================================================================
 *
 *  IP Packet Handling
 *
 *  =========================================================================
 */

STATIC int sctp_rcv_ootb(mblk_t * mp)
{
	struct iphdr *iph = (struct iphdr *) mp->b_datap->db_base;
	struct sctphdr *sh = (struct sctphdr *) (mp->b_datap->db_base + (iph->ihl << 2));
	struct sctpchdr *ch = (struct sctpchdr *) mp->b_rptr;
	int sat = inet_addr_type(iph->saddr);
	seldom();
	ensure(mp, return (-EFAULT));
	if (sat != RTN_UNICAST && sat != RTN_LOCAL) {
		/* RFC 2960 8.4(1). */
		freemsg(mp);
		return (0);
	}
	switch (ch->type) {
	case SCTP_CTYPE_COOKIE_ACK:	/* RFC 2960 8.4(7).  */
	case SCTP_CTYPE_ERROR:	/* RFC 2960 8.4(7).  */
	case SCTP_CTYPE_ABORT:	/* RFC 2960 8.4(2).  */
	case SCTP_CTYPE_SHUTDOWN_COMPLETE:	/* RFC 2960 8.4(6).  */
	case SCTP_CTYPE_INIT:	/* RFC 2960 8.4(3) and (8). */
	case SCTP_CTYPE_INIT_ACK:	/* RFC 2960 8.4(8).  */
	case SCTP_CTYPE_COOKIE_ECHO:	/* RFC 2960 8.4(4) and (8). */
	default:
		seldom();
		break;
	case SCTP_CTYPE_SHUTDOWN:	/* RFC 2960 8.4(8).  */
	case SCTP_CTYPE_SACK:	/* RFC 2960 8.4(8).  */
	case SCTP_CTYPE_HEARTBEAT:	/* RFC 2960 8.4(8).  */
	case SCTP_CTYPE_HEARTBEAT_ACK:	/* RFC 2960 8.4(8).  */
	case SCTP_CTYPE_DATA:	/* RFC 2960 8.4(8).  */
		seldom();
		sctp_send_abort_ootb(iph->saddr, iph->daddr, sh);
		break;
	case SCTP_CTYPE_SHUTDOWN_ACK:
		seldom();
		sctp_send_shutdown_complete_ootb(iph->saddr, iph->daddr, sh);
		break;
	}
	ptrace(("Freeing mblk %p\n", mp));
	freemsg(mp);
	return (0);
}

/* 
 *  -------------------------------------------------------------------------
 *
 *  SCTP ERR
 *
 *  -------------------------------------------------------------------------
 *  We have received an ICMP error for the protocol number.  Because we don't
 *  want an races here we place a M_ERROR message on the read queue of the
 *  stream to which the message applies.  This distinguishes it from M_DATA
 *  messages.  It is processed within the stream with queues locked.  We have
 *  to copy the information because the skb will go away after this call.
 */
STATIC void sctp_err(struct sk_buff *skb, u32 info)
{
	sctp_t *sp;
	struct sctphdr *sh;
	struct iphdr *iph = (struct iphdr *) skb->data;
	size_t ihl;
	ensure(skb, return);
#define ICMP_MIN_LENGTH 8
	if (skb->len < (ihl = iph->ihl << 2) + ICMP_MIN_LENGTH) {
		seldom();
		return;
	}
	sh = (struct sctphdr *) (skb->data + ihl);
	SCTPHASH_BH_RLOCK();
	sp = sh->v_tag ? sctp_lookup_ptag(sh->v_tag, sh->srce, sh->dest, iph->saddr,
					  iph->daddr) : sctp_lookup_tcb(sh->srce, sh->dest, iph->saddr,
									iph->daddr);
	SCTPHASH_BH_RUNLOCK();
	usual(sp);
	if (sp) {
		mblk_t *mp;
		size_t mlen;
		mlen = sizeof(uint32_t) + sizeof(struct icmphdr *);
		if ((mp = allocb(mlen, BPRI_MED))) {
			mp->b_datap->db_type = M_ERROR;
			*((uint32_t *) mp->b_wptr)++ = iph->daddr;
			*((struct icmphdr *) mp->b_wptr)++ = *(skb->h.icmph);
			if (canput(sp->rq)) {
				putq(sp->rq, mp);
				return;
			}
			freemsg(mp);
			return;
		}
		rare();
		return;
	} else
		usual(sp);
	return;
}

/* 
 *  -------------------------------------------------------------------------
 *
 *  SCTP RCV
 *
 *  -------------------------------------------------------------------------
 *  This is the received frame handler for SCTP IPv4.  All packets received by
 *  IPv4 with the protocol number IPPROTO_SCTP will arrive here first.  We
 *  should be performing the Adler-32 checksum on the packet.  If the Adler-32
 *  checksum fails, then we should silently discard per RFC 2960.
 */
STATIC void sctp_free(char *data)
{
	struct sk_buff *skb = (struct sk_buff *) data;

	trace();
	ensure(skb, return);
	kfree_skb(skb);
	return;
}
STATIC int sctp_rcv(struct sk_buff *skb)
{
	mblk_t *mp;
	sctp_t *sp;
	uint32_t csum0, csum1, csum2;
	struct sctphdr *sh;
	unsigned short len;
	frtn_t fr = { &sctp_free, (char *) skb };
	if (skb->pkt_type == PACKET_HOST) {
		/* For now...  We should actually place non-linear fragments into seperate mblks and pass them up 
		   as a chain. */
		if (!skb_is_nonlinear(skb)
		    || skb_linearize(skb, GFP_ATOMIC) == 0) {
			/* pull up the ip header */
			__skb_pull(skb, skb->h.raw - skb->data);
			sh = (struct sctphdr *) skb->h.raw;
			len = skb->len;
			/* 
			 *  perform the crc-32c checksum per RFC 2960 Appendix B.
			 */
			csum0 = sh->check;
			csum1 = ntohl(csum0);
			sh->check = 0;
			csum2 = crc32c(~0UL, sh, len);
			sh->check = csum0;
			if (csum1 == csum2) {
				/* pull to the ip header */
				__skb_push(skb, skb->data - skb->nh.raw);
				if ((mp = esballoc(skb->data, skb->len, BPRI_MED, &fr))) {
					ptrace(("Allocated mblk %p\n", mp));
					mp->b_datap->db_type = M_DATA;
					mp->b_wptr = mp->b_rptr + skb->len;
					/* trim the ip header */
					mp->b_rptr += skb->h.raw - skb->nh.raw;
					mp->b_rptr += sizeof(struct sctphdr);
					SCTPHASH_BH_RLOCK();
					sp = sctp_lookup(sh, skb->nh.iph->daddr, skb->nh.iph->saddr);
					SCTPHASH_BH_RUNLOCK();
					if (sp) {
						if (canput(sp->rq)) {
							skb->dev = NULL;
							putq(sp->rq, mp);
							return (0);
						}
						freemsg(mp);
						return (0);
					}
					return sctp_rcv_ootb(mp);
				} else
					ptrace(("Couldn't allocate mblk\n"));
			} else
				ptrace(("Bad checksum"));
		} else
			ptrace(("Couldn't linearize skb\n"));
	} else
		ptrace(("Receive non-HOST packet\n"));
	kfree_skb(skb);
	return (0);
}

/* 
 *  =========================================================================
 *
 *  IP Protocol Registration
 *
 *  =========================================================================
 */
#ifndef IPPROTO_SCTP
#define IPPROTO_SCTP 132
#endif

STATIC struct inet_protocol sctp_protocol = {
	sctp_rcv,				/* SCTP data handler */
	sctp_err,				/* SCTP error control */
	NULL,					/* next */
	IPPROTO_SCTP,				/* protocol ID */
	0,					/* copy */
	NULL,					/* data */
	"SCTP"					/* name */
};

void sctp_init_proto(void)
{
	inet_add_protocol(&sctp_protocol);
}

void sctp_term_proto(void)
{
	inet_del_protocol(&sctp_protocol);
}


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

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

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