2005-04-17 02:20:36 +04:00
/* SCTP kernel reference Implementation
* Copyright ( c ) 1999 - 2000 Cisco , Inc .
* Copyright ( c ) 1999 - 2001 Motorola , Inc .
* Copyright ( c ) 2002 International Business Machines , Corp .
2007-02-09 17:25:18 +03:00
*
2005-04-17 02:20:36 +04:00
* This file is part of the SCTP kernel reference Implementation
2007-02-09 17:25:18 +03:00
*
2005-04-17 02:20:36 +04:00
* These functions are the methods for accessing the SCTP inqueue .
*
* An SCTP inqueue is a queue into which you push SCTP packets
* ( which might be bundles or fragments of chunks ) and out of which you
* pop SCTP whole chunks .
2007-02-09 17:25:18 +03:00
*
* The SCTP reference implementation is free software ;
* you can redistribute it and / or modify it under the terms of
2005-04-17 02:20:36 +04:00
* the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
2007-02-09 17:25:18 +03:00
*
* The SCTP reference implementation is distributed in the hope that it
2005-04-17 02:20:36 +04:00
* will be useful , but WITHOUT ANY WARRANTY ; without even the implied
* * * * * * * * * * * * * * * * * * * * * * * * *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details .
2007-02-09 17:25:18 +03:00
*
2005-04-17 02:20:36 +04:00
* You should have received a copy of the GNU General Public License
* along with GNU CC ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
2007-02-09 17:25:18 +03:00
* Boston , MA 02111 - 1307 , USA .
*
2005-04-17 02:20:36 +04:00
* Please send any bug reports or fixes you make to the
* email address ( es ) :
* lksctp developers < lksctp - developers @ lists . sourceforge . net >
2007-02-09 17:25:18 +03:00
*
2005-04-17 02:20:36 +04:00
* Or submit a bug report through the following website :
* http : //www.sf.net/projects/lksctp
*
2007-02-09 17:25:18 +03:00
* Written or modified by :
2005-04-17 02:20:36 +04:00
* La Monte H . P . Yarroll < piggy @ acm . org >
* Karl Knutson < karl @ athena . chicago . il . us >
2007-02-09 17:25:18 +03:00
*
2005-04-17 02:20:36 +04:00
* Any bugs reported given to us we will try to fix . . . any fixes shared will
* be incorporated into the next SCTP release .
*/
# include <net/sctp/sctp.h>
# include <net/sctp/sm.h>
# include <linux/interrupt.h>
/* Initialize an SCTP inqueue. */
void sctp_inq_init ( struct sctp_inq * queue )
{
2005-07-09 08:47:49 +04:00
INIT_LIST_HEAD ( & queue - > in_chunk_list ) ;
2005-04-17 02:20:36 +04:00
queue - > in_progress = NULL ;
/* Create a task for delivering data. */
2006-11-22 17:57:56 +03:00
INIT_WORK ( & queue - > immediate , NULL ) ;
2005-04-17 02:20:36 +04:00
queue - > malloced = 0 ;
}
/* Release the memory associated with an SCTP inqueue. */
void sctp_inq_free ( struct sctp_inq * queue )
{
2005-07-09 08:47:49 +04:00
struct sctp_chunk * chunk , * tmp ;
2005-04-17 02:20:36 +04:00
/* Empty the queue. */
2005-07-09 08:47:49 +04:00
list_for_each_entry_safe ( chunk , tmp , & queue - > in_chunk_list , list ) {
list_del_init ( & chunk - > list ) ;
2005-04-17 02:20:36 +04:00
sctp_chunk_free ( chunk ) ;
2005-07-09 08:47:49 +04:00
}
2005-04-17 02:20:36 +04:00
/* If there is a packet which is currently being worked on,
* free it as well .
*/
2006-01-17 22:51:28 +03:00
if ( queue - > in_progress ) {
2005-04-17 02:20:36 +04:00
sctp_chunk_free ( queue - > in_progress ) ;
2006-01-17 22:51:28 +03:00
queue - > in_progress = NULL ;
}
2005-04-17 02:20:36 +04:00
if ( queue - > malloced ) {
/* Dump the master memory segment. */
kfree ( queue ) ;
}
}
/* Put a new packet in an SCTP inqueue.
* We assume that packet - > sctp_hdr is set and in host byte order .
*/
2006-08-22 11:15:33 +04:00
void sctp_inq_push ( struct sctp_inq * q , struct sctp_chunk * chunk )
2005-04-17 02:20:36 +04:00
{
/* Directly call the packet handling routine. */
2007-11-07 19:39:27 +03:00
if ( chunk - > rcvr - > dead ) {
sctp_chunk_free ( chunk ) ;
return ;
}
2005-04-17 02:20:36 +04:00
/* We are now calling this either from the soft interrupt
* or from the backlog processing .
* Eventually , we should clean up inqueue to not rely
* on the BH related data structures .
*/
2006-08-22 11:15:33 +04:00
list_add_tail ( & chunk - > list , & q - > in_chunk_list ) ;
2006-11-22 17:57:56 +03:00
q - > immediate . func ( & q - > immediate ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-04 04:51:34 +04:00
/* Peek at the next chunk on the inqeue. */
struct sctp_chunkhdr * sctp_inq_peek ( struct sctp_inq * queue )
{
struct sctp_chunk * chunk ;
sctp_chunkhdr_t * ch = NULL ;
chunk = queue - > in_progress ;
/* If there is no more chunks in this packet, say so */
if ( chunk - > singleton | |
chunk - > end_of_packet | |
chunk - > pdiscard )
return NULL ;
ch = ( sctp_chunkhdr_t * ) chunk - > chunk_end ;
return ch ;
}
2005-04-17 02:20:36 +04:00
/* Extract a chunk from an SCTP inqueue.
*
* WARNING : If you need to put the chunk on another queue , you need to
* make a shallow copy ( clone ) of it .
*/
struct sctp_chunk * sctp_inq_pop ( struct sctp_inq * queue )
{
struct sctp_chunk * chunk ;
sctp_chunkhdr_t * ch = NULL ;
/* The assumption is that we are safe to process the chunks
* at this time .
*/
if ( ( chunk = queue - > in_progress ) ) {
/* There is a packet that we have been working on.
* Any post processing work to do before we move on ?
*/
if ( chunk - > singleton | |
chunk - > end_of_packet | |
chunk - > pdiscard ) {
sctp_chunk_free ( chunk ) ;
chunk = queue - > in_progress = NULL ;
} else {
/* Nothing to do. Next chunk in the packet, please. */
ch = ( sctp_chunkhdr_t * ) chunk - > chunk_end ;
/* Force chunk->skb->data to chunk->chunk_end. */
skb_pull ( chunk - > skb ,
chunk - > chunk_end - chunk - > skb - > data ) ;
2007-09-05 23:53:58 +04:00
/* Verify that we have at least chunk headers
* worth of buffer left .
*/
if ( skb_headlen ( chunk - > skb ) < sizeof ( sctp_chunkhdr_t ) ) {
sctp_chunk_free ( chunk ) ;
chunk = queue - > in_progress = NULL ;
}
2005-04-17 02:20:36 +04:00
}
}
/* Do we need to take the next packet out of the queue to process? */
if ( ! chunk ) {
2005-07-09 08:47:49 +04:00
struct list_head * entry ;
2005-04-17 02:20:36 +04:00
/* Is the queue empty? */
2005-07-09 08:47:49 +04:00
if ( list_empty ( & queue - > in_chunk_list ) )
2005-04-17 02:20:36 +04:00
return NULL ;
2005-07-09 08:47:49 +04:00
entry = queue - > in_chunk_list . next ;
2005-04-17 02:20:36 +04:00
chunk = queue - > in_progress =
2005-07-09 08:47:49 +04:00
list_entry ( entry , struct sctp_chunk , list ) ;
list_del_init ( entry ) ;
2005-04-17 02:20:36 +04:00
/* This is the first chunk in the packet. */
chunk - > singleton = 1 ;
ch = ( sctp_chunkhdr_t * ) chunk - > skb - > data ;
2006-05-06 04:02:09 +04:00
chunk - > data_accepted = 0 ;
2005-04-17 02:20:36 +04:00
}
2007-02-09 17:25:18 +03:00
chunk - > chunk_hdr = ch ;
chunk - > chunk_end = ( ( __u8 * ) ch ) + WORD_ROUND ( ntohs ( ch - > length ) ) ;
2005-04-17 02:20:36 +04:00
/* In the unlikely case of an IP reassembly, the skb could be
* non - linear . If so , update chunk_end so that it doesn ' t go past
* the skb - > tail .
*/
if ( unlikely ( skb_is_nonlinear ( chunk - > skb ) ) ) {
2007-04-20 07:29:13 +04:00
if ( chunk - > chunk_end > skb_tail_pointer ( chunk - > skb ) )
chunk - > chunk_end = skb_tail_pointer ( chunk - > skb ) ;
2005-04-17 02:20:36 +04:00
}
skb_pull ( chunk - > skb , sizeof ( sctp_chunkhdr_t ) ) ;
chunk - > subh . v = NULL ; /* Subheader is no longer valid. */
2007-04-20 07:29:13 +04:00
if ( chunk - > chunk_end < skb_tail_pointer ( chunk - > skb ) ) {
2005-04-17 02:20:36 +04:00
/* This is not a singleton */
chunk - > singleton = 0 ;
2007-04-20 07:29:13 +04:00
} else if ( chunk - > chunk_end > skb_tail_pointer ( chunk - > skb ) ) {
2007-02-09 17:25:18 +03:00
/* RFC 2960, Section 6.10 Bundling
2005-04-17 02:20:36 +04:00
*
* Partial chunks MUST NOT be placed in an SCTP packet .
* If the receiver detects a partial chunk , it MUST drop
2007-02-09 17:25:18 +03:00
* the chunk .
2005-04-17 02:20:36 +04:00
*
* Since the end of the chunk is past the end of our buffer
* ( which contains the whole packet , we can freely discard
* the whole packet .
*/
sctp_chunk_free ( chunk ) ;
chunk = queue - > in_progress = NULL ;
return NULL ;
} else {
/* We are at the end of the packet, so mark the chunk
* in case we need to send a SACK .
*/
chunk - > end_of_packet = 1 ;
}
SCTP_DEBUG_PRINTK ( " +++sctp_inq_pop+++ chunk %p[%s], "
" length %d, skb->len %d \n " , chunk ,
sctp_cname ( SCTP_ST_CHUNK ( chunk - > chunk_hdr - > type ) ) ,
ntohs ( chunk - > chunk_hdr - > length ) , chunk - > skb - > len ) ;
return chunk ;
}
/* Set a top-half handler.
*
* Originally , we the top - half handler was scheduled as a BH . We now
* call the handler directly in sctp_inq_push ( ) at a time that
* we know we are lock safe .
* The intent is that this routine will pull stuff out of the
* inqueue and process it .
*/
2006-11-22 17:57:56 +03:00
void sctp_inq_set_th_handler ( struct sctp_inq * q , work_func_t callback )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:57:56 +03:00
INIT_WORK ( & q - > immediate , callback ) ;
2005-04-17 02:20:36 +04:00
}