aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/inqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/inqueue.c')
-rw-r--r--net/sctp/inqueue.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 9d87bba0ff1d..5ba08ceda3ab 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -130,7 +130,8 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
130 * at this time. 130 * at this time.
131 */ 131 */
132 132
133 if ((chunk = queue->in_progress)) { 133 chunk = queue->in_progress;
134 if (chunk) {
134 /* There is a packet that we have been working on. 135 /* There is a packet that we have been working on.
135 * Any post processing work to do before we move on? 136 * Any post processing work to do before we move on?
136 */ 137 */
@@ -152,15 +153,29 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
152 if (!chunk) { 153 if (!chunk) {
153 struct list_head *entry; 154 struct list_head *entry;
154 155
156next_chunk:
155 /* Is the queue empty? */ 157 /* Is the queue empty? */
156 if (list_empty(&queue->in_chunk_list)) 158 if (list_empty(&queue->in_chunk_list))
157 return NULL; 159 return NULL;
158 160
159 entry = queue->in_chunk_list.next; 161 entry = queue->in_chunk_list.next;
160 chunk = queue->in_progress = 162 chunk = list_entry(entry, struct sctp_chunk, list);
161 list_entry(entry, struct sctp_chunk, list);
162 list_del_init(entry); 163 list_del_init(entry);
163 164
165 /* Linearize if it's not GSO */
166 if (skb_is_nonlinear(chunk->skb)) {
167 if (skb_linearize(chunk->skb)) {
168 __SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
169 sctp_chunk_free(chunk);
170 goto next_chunk;
171 }
172
173 /* Update sctp_hdr as it probably changed */
174 chunk->sctp_hdr = sctp_hdr(chunk->skb);
175 }
176
177 queue->in_progress = chunk;
178
164 /* This is the first chunk in the packet. */ 179 /* This is the first chunk in the packet. */
165 chunk->singleton = 1; 180 chunk->singleton = 1;
166 ch = (sctp_chunkhdr_t *) chunk->skb->data; 181 ch = (sctp_chunkhdr_t *) chunk->skb->data;
@@ -172,14 +187,6 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
172 187
173 chunk->chunk_hdr = ch; 188 chunk->chunk_hdr = ch;
174 chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); 189 chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
175 /* In the unlikely case of an IP reassembly, the skb could be
176 * non-linear. If so, update chunk_end so that it doesn't go past
177 * the skb->tail.
178 */
179 if (unlikely(skb_is_nonlinear(chunk->skb))) {
180 if (chunk->chunk_end > skb_tail_pointer(chunk->skb))
181 chunk->chunk_end = skb_tail_pointer(chunk->skb);
182 }
183 skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); 190 skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
184 chunk->subh.v = NULL; /* Subheader is no longer valid. */ 191 chunk->subh.v = NULL; /* Subheader is no longer valid. */
185 192