diff options
Diffstat (limited to 'net/sctp/inqueue.c')
-rw-r--r-- | net/sctp/inqueue.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c new file mode 100644 index 000000000000..cedf4351556c --- /dev/null +++ b/net/sctp/inqueue.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* SCTP kernel reference Implementation | ||
2 | * Copyright (c) 1999-2000 Cisco, Inc. | ||
3 | * Copyright (c) 1999-2001 Motorola, Inc. | ||
4 | * Copyright (c) 2002 International Business Machines, Corp. | ||
5 | * | ||
6 | * This file is part of the SCTP kernel reference Implementation | ||
7 | * | ||
8 | * These functions are the methods for accessing the SCTP inqueue. | ||
9 | * | ||
10 | * An SCTP inqueue is a queue into which you push SCTP packets | ||
11 | * (which might be bundles or fragments of chunks) and out of which you | ||
12 | * pop SCTP whole chunks. | ||
13 | * | ||
14 | * The SCTP reference implementation is free software; | ||
15 | * you can redistribute it and/or modify it under the terms of | ||
16 | * the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2, or (at your option) | ||
18 | * any later version. | ||
19 | * | ||
20 | * The SCTP reference implementation is distributed in the hope that it | ||
21 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
22 | * ************************ | ||
23 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
24 | * See the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with GNU CC; see the file COPYING. If not, write to | ||
28 | * the Free Software Foundation, 59 Temple Place - Suite 330, | ||
29 | * Boston, MA 02111-1307, USA. | ||
30 | * | ||
31 | * Please send any bug reports or fixes you make to the | ||
32 | * email address(es): | ||
33 | * lksctp developers <lksctp-developers@lists.sourceforge.net> | ||
34 | * | ||
35 | * Or submit a bug report through the following website: | ||
36 | * http://www.sf.net/projects/lksctp | ||
37 | * | ||
38 | * Written or modified by: | ||
39 | * La Monte H.P. Yarroll <piggy@acm.org> | ||
40 | * Karl Knutson <karl@athena.chicago.il.us> | ||
41 | * | ||
42 | * Any bugs reported given to us we will try to fix... any fixes shared will | ||
43 | * be incorporated into the next SCTP release. | ||
44 | */ | ||
45 | |||
46 | #include <net/sctp/sctp.h> | ||
47 | #include <net/sctp/sm.h> | ||
48 | #include <linux/interrupt.h> | ||
49 | |||
50 | /* Initialize an SCTP inqueue. */ | ||
51 | void sctp_inq_init(struct sctp_inq *queue) | ||
52 | { | ||
53 | skb_queue_head_init(&queue->in); | ||
54 | queue->in_progress = NULL; | ||
55 | |||
56 | /* Create a task for delivering data. */ | ||
57 | INIT_WORK(&queue->immediate, NULL, NULL); | ||
58 | |||
59 | queue->malloced = 0; | ||
60 | } | ||
61 | |||
62 | /* Release the memory associated with an SCTP inqueue. */ | ||
63 | void sctp_inq_free(struct sctp_inq *queue) | ||
64 | { | ||
65 | struct sctp_chunk *chunk; | ||
66 | |||
67 | /* Empty the queue. */ | ||
68 | while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL) | ||
69 | sctp_chunk_free(chunk); | ||
70 | |||
71 | /* If there is a packet which is currently being worked on, | ||
72 | * free it as well. | ||
73 | */ | ||
74 | if (queue->in_progress) | ||
75 | sctp_chunk_free(queue->in_progress); | ||
76 | |||
77 | if (queue->malloced) { | ||
78 | /* Dump the master memory segment. */ | ||
79 | kfree(queue); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /* Put a new packet in an SCTP inqueue. | ||
84 | * We assume that packet->sctp_hdr is set and in host byte order. | ||
85 | */ | ||
86 | void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) | ||
87 | { | ||
88 | /* Directly call the packet handling routine. */ | ||
89 | |||
90 | /* We are now calling this either from the soft interrupt | ||
91 | * or from the backlog processing. | ||
92 | * Eventually, we should clean up inqueue to not rely | ||
93 | * on the BH related data structures. | ||
94 | */ | ||
95 | skb_queue_tail(&(q->in), (struct sk_buff *) packet); | ||
96 | q->immediate.func(q->immediate.data); | ||
97 | } | ||
98 | |||
99 | /* Extract a chunk from an SCTP inqueue. | ||
100 | * | ||
101 | * WARNING: If you need to put the chunk on another queue, you need to | ||
102 | * make a shallow copy (clone) of it. | ||
103 | */ | ||
104 | struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) | ||
105 | { | ||
106 | struct sctp_chunk *chunk; | ||
107 | sctp_chunkhdr_t *ch = NULL; | ||
108 | |||
109 | /* The assumption is that we are safe to process the chunks | ||
110 | * at this time. | ||
111 | */ | ||
112 | |||
113 | if ((chunk = queue->in_progress)) { | ||
114 | /* There is a packet that we have been working on. | ||
115 | * Any post processing work to do before we move on? | ||
116 | */ | ||
117 | if (chunk->singleton || | ||
118 | chunk->end_of_packet || | ||
119 | chunk->pdiscard) { | ||
120 | sctp_chunk_free(chunk); | ||
121 | chunk = queue->in_progress = NULL; | ||
122 | } else { | ||
123 | /* Nothing to do. Next chunk in the packet, please. */ | ||
124 | ch = (sctp_chunkhdr_t *) chunk->chunk_end; | ||
125 | |||
126 | /* Force chunk->skb->data to chunk->chunk_end. */ | ||
127 | skb_pull(chunk->skb, | ||
128 | chunk->chunk_end - chunk->skb->data); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* Do we need to take the next packet out of the queue to process? */ | ||
133 | if (!chunk) { | ||
134 | /* Is the queue empty? */ | ||
135 | if (skb_queue_empty(&queue->in)) | ||
136 | return NULL; | ||
137 | |||
138 | chunk = queue->in_progress = | ||
139 | (struct sctp_chunk *) skb_dequeue(&queue->in); | ||
140 | |||
141 | /* This is the first chunk in the packet. */ | ||
142 | chunk->singleton = 1; | ||
143 | ch = (sctp_chunkhdr_t *) chunk->skb->data; | ||
144 | } | ||
145 | |||
146 | chunk->chunk_hdr = ch; | ||
147 | chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); | ||
148 | /* In the unlikely case of an IP reassembly, the skb could be | ||
149 | * non-linear. If so, update chunk_end so that it doesn't go past | ||
150 | * the skb->tail. | ||
151 | */ | ||
152 | if (unlikely(skb_is_nonlinear(chunk->skb))) { | ||
153 | if (chunk->chunk_end > chunk->skb->tail) | ||
154 | chunk->chunk_end = chunk->skb->tail; | ||
155 | } | ||
156 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
157 | chunk->subh.v = NULL; /* Subheader is no longer valid. */ | ||
158 | |||
159 | if (chunk->chunk_end < chunk->skb->tail) { | ||
160 | /* This is not a singleton */ | ||
161 | chunk->singleton = 0; | ||
162 | } else if (chunk->chunk_end > chunk->skb->tail) { | ||
163 | /* RFC 2960, Section 6.10 Bundling | ||
164 | * | ||
165 | * Partial chunks MUST NOT be placed in an SCTP packet. | ||
166 | * If the receiver detects a partial chunk, it MUST drop | ||
167 | * the chunk. | ||
168 | * | ||
169 | * Since the end of the chunk is past the end of our buffer | ||
170 | * (which contains the whole packet, we can freely discard | ||
171 | * the whole packet. | ||
172 | */ | ||
173 | sctp_chunk_free(chunk); | ||
174 | chunk = queue->in_progress = NULL; | ||
175 | |||
176 | return NULL; | ||
177 | } else { | ||
178 | /* We are at the end of the packet, so mark the chunk | ||
179 | * in case we need to send a SACK. | ||
180 | */ | ||
181 | chunk->end_of_packet = 1; | ||
182 | } | ||
183 | |||
184 | SCTP_DEBUG_PRINTK("+++sctp_inq_pop+++ chunk %p[%s]," | ||
185 | " length %d, skb->len %d\n",chunk, | ||
186 | sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), | ||
187 | ntohs(chunk->chunk_hdr->length), chunk->skb->len); | ||
188 | return chunk; | ||
189 | } | ||
190 | |||
191 | /* Set a top-half handler. | ||
192 | * | ||
193 | * Originally, we the top-half handler was scheduled as a BH. We now | ||
194 | * call the handler directly in sctp_inq_push() at a time that | ||
195 | * we know we are lock safe. | ||
196 | * The intent is that this routine will pull stuff out of the | ||
197 | * inqueue and process it. | ||
198 | */ | ||
199 | void sctp_inq_set_th_handler(struct sctp_inq *q, | ||
200 | void (*callback)(void *), void *arg) | ||
201 | { | ||
202 | INIT_WORK(&q->immediate, callback, arg); | ||
203 | } | ||
204 | |||