diff options
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r-- | net/sctp/outqueue.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 084718f9b3da..72e54a416af6 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -326,6 +326,9 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp) | |||
326 | 326 | ||
327 | sctp_chunk_hold(chunk); | 327 | sctp_chunk_hold(chunk); |
328 | sctp_outq_tail_data(q, chunk); | 328 | sctp_outq_tail_data(q, chunk); |
329 | if (chunk->asoc->prsctp_enable && | ||
330 | SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags)) | ||
331 | chunk->asoc->sent_cnt_removable++; | ||
329 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) | 332 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) |
330 | SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS); | 333 | SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS); |
331 | else | 334 | else |
@@ -372,6 +375,96 @@ static void sctp_insert_list(struct list_head *head, struct list_head *new) | |||
372 | list_add_tail(new, head); | 375 | list_add_tail(new, head); |
373 | } | 376 | } |
374 | 377 | ||
378 | static int sctp_prsctp_prune_sent(struct sctp_association *asoc, | ||
379 | struct sctp_sndrcvinfo *sinfo, | ||
380 | struct list_head *queue, int msg_len) | ||
381 | { | ||
382 | struct sctp_chunk *chk, *temp; | ||
383 | |||
384 | list_for_each_entry_safe(chk, temp, queue, transmitted_list) { | ||
385 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || | ||
386 | chk->prsctp_param <= sinfo->sinfo_timetolive) | ||
387 | continue; | ||
388 | |||
389 | list_del_init(&chk->transmitted_list); | ||
390 | sctp_insert_list(&asoc->outqueue.abandoned, | ||
391 | &chk->transmitted_list); | ||
392 | |||
393 | asoc->sent_cnt_removable--; | ||
394 | asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; | ||
395 | |||
396 | if (!chk->tsn_gap_acked) { | ||
397 | if (chk->transport) | ||
398 | chk->transport->flight_size -= | ||
399 | sctp_data_size(chk); | ||
400 | asoc->outqueue.outstanding_bytes -= sctp_data_size(chk); | ||
401 | } | ||
402 | |||
403 | msg_len -= SCTP_DATA_SNDSIZE(chk) + | ||
404 | sizeof(struct sk_buff) + | ||
405 | sizeof(struct sctp_chunk); | ||
406 | if (msg_len <= 0) | ||
407 | break; | ||
408 | } | ||
409 | |||
410 | return msg_len; | ||
411 | } | ||
412 | |||
413 | static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, | ||
414 | struct sctp_sndrcvinfo *sinfo, | ||
415 | struct list_head *queue, int msg_len) | ||
416 | { | ||
417 | struct sctp_chunk *chk, *temp; | ||
418 | |||
419 | list_for_each_entry_safe(chk, temp, queue, list) { | ||
420 | if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || | ||
421 | chk->prsctp_param <= sinfo->sinfo_timetolive) | ||
422 | continue; | ||
423 | |||
424 | list_del_init(&chk->list); | ||
425 | asoc->sent_cnt_removable--; | ||
426 | asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; | ||
427 | |||
428 | msg_len -= SCTP_DATA_SNDSIZE(chk) + | ||
429 | sizeof(struct sk_buff) + | ||
430 | sizeof(struct sctp_chunk); | ||
431 | sctp_chunk_free(chk); | ||
432 | if (msg_len <= 0) | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | return msg_len; | ||
437 | } | ||
438 | |||
439 | /* Abandon the chunks according their priorities */ | ||
440 | void sctp_prsctp_prune(struct sctp_association *asoc, | ||
441 | struct sctp_sndrcvinfo *sinfo, int msg_len) | ||
442 | { | ||
443 | struct sctp_transport *transport; | ||
444 | |||
445 | if (!asoc->prsctp_enable || !asoc->sent_cnt_removable) | ||
446 | return; | ||
447 | |||
448 | msg_len = sctp_prsctp_prune_sent(asoc, sinfo, | ||
449 | &asoc->outqueue.retransmit, | ||
450 | msg_len); | ||
451 | if (msg_len <= 0) | ||
452 | return; | ||
453 | |||
454 | list_for_each_entry(transport, &asoc->peer.transport_addr_list, | ||
455 | transports) { | ||
456 | msg_len = sctp_prsctp_prune_sent(asoc, sinfo, | ||
457 | &transport->transmitted, | ||
458 | msg_len); | ||
459 | if (msg_len <= 0) | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | sctp_prsctp_prune_unsent(asoc, sinfo, | ||
464 | &asoc->outqueue.out_chunk_list, | ||
465 | msg_len); | ||
466 | } | ||
467 | |||
375 | /* Mark all the eligible packets on a transport for retransmission. */ | 468 | /* Mark all the eligible packets on a transport for retransmission. */ |
376 | void sctp_retransmit_mark(struct sctp_outq *q, | 469 | void sctp_retransmit_mark(struct sctp_outq *q, |
377 | struct sctp_transport *transport, | 470 | struct sctp_transport *transport, |
@@ -962,6 +1055,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
962 | 1055 | ||
963 | /* Mark as failed send. */ | 1056 | /* Mark as failed send. */ |
964 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1057 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); |
1058 | if (asoc->prsctp_enable && | ||
1059 | SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags)) | ||
1060 | asoc->sent_cnt_removable--; | ||
965 | sctp_chunk_free(chunk); | 1061 | sctp_chunk_free(chunk); |
966 | continue; | 1062 | continue; |
967 | } | 1063 | } |
@@ -1251,6 +1347,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) | |||
1251 | tsn = ntohl(tchunk->subh.data_hdr->tsn); | 1347 | tsn = ntohl(tchunk->subh.data_hdr->tsn); |
1252 | if (TSN_lte(tsn, ctsn)) { | 1348 | if (TSN_lte(tsn, ctsn)) { |
1253 | list_del_init(&tchunk->transmitted_list); | 1349 | list_del_init(&tchunk->transmitted_list); |
1350 | if (asoc->prsctp_enable && | ||
1351 | SCTP_PR_PRIO_ENABLED(chunk->sinfo.sinfo_flags)) | ||
1352 | asoc->sent_cnt_removable--; | ||
1254 | sctp_chunk_free(tchunk); | 1353 | sctp_chunk_free(tchunk); |
1255 | } | 1354 | } |
1256 | } | 1355 | } |