aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/input.c')
-rw-r--r--net/sctp/input.c75
1 files changed, 62 insertions, 13 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 4aa6fc60357c..cb78b50868ee 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -257,20 +257,26 @@ int sctp_rcv(struct sk_buff *skb)
257 */ 257 */
258 sctp_bh_lock_sock(sk); 258 sctp_bh_lock_sock(sk);
259 259
260 /* It is possible that the association could have moved to a different
261 * socket if it is peeled off. If so, update the sk.
262 */
263 if (sk != rcvr->sk) {
264 sctp_bh_lock_sock(rcvr->sk);
265 sctp_bh_unlock_sock(sk);
266 sk = rcvr->sk;
267 }
268
260 if (sock_owned_by_user(sk)) 269 if (sock_owned_by_user(sk))
261 sk_add_backlog(sk, skb); 270 sk_add_backlog(sk, skb);
262 else 271 else
263 sctp_backlog_rcv(sk, skb); 272 sctp_backlog_rcv(sk, skb);
264 273
265 /* Release the sock and any reference counts we took in the 274 /* Release the sock and the sock ref we took in the lookup calls.
266 * lookup calls. 275 * The asoc/ep ref will be released in sctp_backlog_rcv.
267 */ 276 */
268 sctp_bh_unlock_sock(sk); 277 sctp_bh_unlock_sock(sk);
269 if (asoc)
270 sctp_association_put(asoc);
271 else
272 sctp_endpoint_put(ep);
273 sock_put(sk); 278 sock_put(sk);
279
274 return ret; 280 return ret;
275 281
276discard_it: 282discard_it:
@@ -296,12 +302,50 @@ discard_release:
296int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) 302int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
297{ 303{
298 struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; 304 struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
299 struct sctp_inq *inqueue = &chunk->rcvr->inqueue; 305 struct sctp_inq *inqueue = NULL;
300 306 struct sctp_ep_common *rcvr = NULL;
301 sctp_inq_push(inqueue, chunk); 307
308 rcvr = chunk->rcvr;
309
310 BUG_TRAP(rcvr->sk == sk);
311
312 if (rcvr->dead) {
313 sctp_chunk_free(chunk);
314 } else {
315 inqueue = &chunk->rcvr->inqueue;
316 sctp_inq_push(inqueue, chunk);
317 }
318
319 /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */
320 if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
321 sctp_association_put(sctp_assoc(rcvr));
322 else
323 sctp_endpoint_put(sctp_ep(rcvr));
324
302 return 0; 325 return 0;
303} 326}
304 327
328void sctp_backlog_migrate(struct sctp_association *assoc,
329 struct sock *oldsk, struct sock *newsk)
330{
331 struct sk_buff *skb;
332 struct sctp_chunk *chunk;
333
334 skb = oldsk->sk_backlog.head;
335 oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL;
336 while (skb != NULL) {
337 struct sk_buff *next = skb->next;
338
339 chunk = SCTP_INPUT_CB(skb)->chunk;
340 skb->next = NULL;
341 if (&assoc->base == chunk->rcvr)
342 sk_add_backlog(newsk, skb);
343 else
344 sk_add_backlog(oldsk, skb);
345 skb = next;
346 }
347}
348
305/* Handle icmp frag needed error. */ 349/* Handle icmp frag needed error. */
306void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, 350void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
307 struct sctp_transport *t, __u32 pmtu) 351 struct sctp_transport *t, __u32 pmtu)
@@ -544,10 +588,16 @@ int sctp_rcv_ootb(struct sk_buff *skb)
544 sctp_errhdr_t *err; 588 sctp_errhdr_t *err;
545 589
546 ch = (sctp_chunkhdr_t *) skb->data; 590 ch = (sctp_chunkhdr_t *) skb->data;
547 ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
548 591
549 /* Scan through all the chunks in the packet. */ 592 /* Scan through all the chunks in the packet. */
550 while (ch_end > (__u8 *)ch && ch_end < skb->tail) { 593 do {
594 /* Break out if chunk length is less then minimal. */
595 if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
596 break;
597
598 ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
599 if (ch_end > skb->tail)
600 break;
551 601
552 /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the 602 /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
553 * receiver MUST silently discard the OOTB packet and take no 603 * receiver MUST silently discard the OOTB packet and take no
@@ -578,8 +628,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
578 } 628 }
579 629
580 ch = (sctp_chunkhdr_t *) ch_end; 630 ch = (sctp_chunkhdr_t *) ch_end;
581 ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); 631 } while (ch_end < skb->tail);
582 }
583 632
584 return 0; 633 return 0;
585 634