OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
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); }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |