Deleted Added
full compact
sctp_pcb.c (205629) sctp_pcb.c (206137)
1/*-
2 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * a) Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.

--- 17 unchanged lines hidden (view full) ---

26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/* $KAME: sctp_pcb.c,v 1.38 2005/03/06 16:04:18 itojun Exp $ */
32
33#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * a) Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.

--- 17 unchanged lines hidden (view full) ---

26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/* $KAME: sctp_pcb.c,v 1.38 2005/03/06 16:04:18 itojun Exp $ */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 205629 2010-03-24 20:02:40Z rrs $");
34__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 206137 2010-04-03 15:40:14Z tuexen $");
35
36#include <netinet/sctp_os.h>
37#include <sys/proc.h>
38#include <netinet/sctp_var.h>
39#include <netinet/sctp_sysctl.h>
40#include <netinet/sctp_pcb.h>
41#include <netinet/sctputil.h>
42#include <netinet/sctp.h>

--- 3912 unchanged lines hidden (view full) ---

3955
3956/*
3957 * allocate an association and add it to the endpoint. The caller must be
3958 * careful to add all additional addresses once they are know right away or
3959 * else the assoc will be may experience a blackout scenario.
3960 */
3961struct sctp_tcb *
3962sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
35
36#include <netinet/sctp_os.h>
37#include <sys/proc.h>
38#include <netinet/sctp_var.h>
39#include <netinet/sctp_sysctl.h>
40#include <netinet/sctp_pcb.h>
41#include <netinet/sctputil.h>
42#include <netinet/sctp.h>

--- 3912 unchanged lines hidden (view full) ---

3955
3956/*
3957 * allocate an association and add it to the endpoint. The caller must be
3958 * careful to add all additional addresses once they are know right away or
3959 * else the assoc will be may experience a blackout scenario.
3960 */
3961struct sctp_tcb *
3962sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
3963 int for_a_init, int *error, uint32_t override_tag, uint32_t vrf_id,
3963 int *error, uint32_t override_tag, uint32_t vrf_id,
3964 struct thread *p
3965)
3966{
3967 /* note the p argument is only valid in unbound sockets */
3968
3969 struct sctp_tcb *stcb;
3970 struct sctp_association *asoc;
3971 struct sctpasochead *head;

--- 103 unchanged lines hidden (view full) ---

4075
4076 asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
4077 SCTP_TCB_LOCK_INIT(stcb);
4078 SCTP_TCB_SEND_LOCK_INIT(stcb);
4079 stcb->rport = rport;
4080 /* setup back pointer's */
4081 stcb->sctp_ep = inp;
4082 stcb->sctp_socket = inp->sctp_socket;
3964 struct thread *p
3965)
3966{
3967 /* note the p argument is only valid in unbound sockets */
3968
3969 struct sctp_tcb *stcb;
3970 struct sctp_association *asoc;
3971 struct sctpasochead *head;

--- 103 unchanged lines hidden (view full) ---

4075
4076 asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
4077 SCTP_TCB_LOCK_INIT(stcb);
4078 SCTP_TCB_SEND_LOCK_INIT(stcb);
4079 stcb->rport = rport;
4080 /* setup back pointer's */
4081 stcb->sctp_ep = inp;
4082 stcb->sctp_socket = inp->sctp_socket;
4083 if ((err = sctp_init_asoc(inp, stcb, for_a_init, override_tag, vrf_id))) {
4083 if ((err = sctp_init_asoc(inp, stcb, override_tag, vrf_id))) {
4084 /* failed */
4085 SCTP_TCB_LOCK_DESTROY(stcb);
4086 SCTP_TCB_SEND_LOCK_DESTROY(stcb);
4087 LIST_REMOVE(stcb, sctp_tcbasocidhash);
4088 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
4089 SCTP_DECR_ASOC_COUNT();
4090 *error = err;
4091 return (NULL);

--- 584 unchanged lines hidden (view full) ---

4676 SCTP_ITERATOR_UNLOCK();
4677 }
4678 /* pull from vtag hash */
4679 LIST_REMOVE(stcb, sctp_asocs);
4680 sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_BASE_SYSCTL(sctp_vtag_time_wait),
4681 inp->sctp_lport, stcb->rport);
4682
4683 /*
4084 /* failed */
4085 SCTP_TCB_LOCK_DESTROY(stcb);
4086 SCTP_TCB_SEND_LOCK_DESTROY(stcb);
4087 LIST_REMOVE(stcb, sctp_tcbasocidhash);
4088 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb);
4089 SCTP_DECR_ASOC_COUNT();
4090 *error = err;
4091 return (NULL);

--- 584 unchanged lines hidden (view full) ---

4676 SCTP_ITERATOR_UNLOCK();
4677 }
4678 /* pull from vtag hash */
4679 LIST_REMOVE(stcb, sctp_asocs);
4680 sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_BASE_SYSCTL(sctp_vtag_time_wait),
4681 inp->sctp_lport, stcb->rport);
4682
4683 /*
4684 * Now restop the timers to be sure - this is paranoia at is finest!
4684 * Now restop the timers to be sure this is paranoia at is finest!
4685 */
4686 (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
4687 (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
4688 (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
4689 (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
4690 (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
4691 (void)SCTP_OS_TIMER_STOP(&asoc->shut_guard_timer.timer);
4692 (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);

--- 1724 unchanged lines hidden (view full) ---

6417sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
6418{
6419 /*
6420 * We must hunt this association for MBUF's past the cumack (i.e.
6421 * out of order data that we can renege on).
6422 */
6423 struct sctp_association *asoc;
6424 struct sctp_tmit_chunk *chk, *nchk;
4685 */
4686 (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
4687 (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
4688 (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
4689 (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
4690 (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
4691 (void)SCTP_OS_TIMER_STOP(&asoc->shut_guard_timer.timer);
4692 (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);

--- 1724 unchanged lines hidden (view full) ---

6417sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
6418{
6419 /*
6420 * We must hunt this association for MBUF's past the cumack (i.e.
6421 * out of order data that we can renege on).
6422 */
6423 struct sctp_association *asoc;
6424 struct sctp_tmit_chunk *chk, *nchk;
6425 uint32_t cumulative_tsn_p1, tsn;
6425 uint32_t cumulative_tsn_p1;
6426 struct sctp_queued_to_read *ctl, *nctl;
6426 struct sctp_queued_to_read *ctl, *nctl;
6427 int cnt, strmat, gap;
6427 int cnt, strmat;
6428 uint32_t gap, i;
6429 int fnd = 0;
6428
6429 /* We look for anything larger than the cum-ack + 1 */
6430
6431 asoc = &stcb->asoc;
6432 if (asoc->cumulative_tsn == asoc->highest_tsn_inside_map) {
6433 /* none we can reneg on. */
6434 return;
6435 }

--- 4 unchanged lines hidden (view full) ---

6440 chk = TAILQ_FIRST(&asoc->reasmqueue);
6441 while (chk) {
6442 /* Get the next one */
6443 nchk = TAILQ_NEXT(chk, sctp_next);
6444 if (compare_with_wrap(chk->rec.data.TSN_seq,
6445 cumulative_tsn_p1, MAX_TSN)) {
6446 /* Yep it is above cum-ack */
6447 cnt++;
6430
6431 /* We look for anything larger than the cum-ack + 1 */
6432
6433 asoc = &stcb->asoc;
6434 if (asoc->cumulative_tsn == asoc->highest_tsn_inside_map) {
6435 /* none we can reneg on. */
6436 return;
6437 }

--- 4 unchanged lines hidden (view full) ---

6442 chk = TAILQ_FIRST(&asoc->reasmqueue);
6443 while (chk) {
6444 /* Get the next one */
6445 nchk = TAILQ_NEXT(chk, sctp_next);
6446 if (compare_with_wrap(chk->rec.data.TSN_seq,
6447 cumulative_tsn_p1, MAX_TSN)) {
6448 /* Yep it is above cum-ack */
6449 cnt++;
6448 tsn = chk->rec.data.TSN_seq;
6449 if (tsn >= asoc->mapping_array_base_tsn) {
6450 gap = tsn - asoc->mapping_array_base_tsn;
6451 } else {
6452 gap = (MAX_TSN - asoc->mapping_array_base_tsn) +
6453 tsn + 1;
6454 }
6450 SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn);
6455 asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
6456 sctp_ucount_decr(asoc->cnt_on_reasm_queue);
6457 SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
6458 TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
6459 if (chk->data) {
6460 sctp_m_freem(chk->data);
6461 chk->data = NULL;
6462 }

--- 5 unchanged lines hidden (view full) ---

6468 for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
6469 ctl = TAILQ_FIRST(&asoc->strmin[strmat].inqueue);
6470 while (ctl) {
6471 nctl = TAILQ_NEXT(ctl, next);
6472 if (compare_with_wrap(ctl->sinfo_tsn,
6473 cumulative_tsn_p1, MAX_TSN)) {
6474 /* Yep it is above cum-ack */
6475 cnt++;
6451 asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
6452 sctp_ucount_decr(asoc->cnt_on_reasm_queue);
6453 SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
6454 TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
6455 if (chk->data) {
6456 sctp_m_freem(chk->data);
6457 chk->data = NULL;
6458 }

--- 5 unchanged lines hidden (view full) ---

6464 for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
6465 ctl = TAILQ_FIRST(&asoc->strmin[strmat].inqueue);
6466 while (ctl) {
6467 nctl = TAILQ_NEXT(ctl, next);
6468 if (compare_with_wrap(ctl->sinfo_tsn,
6469 cumulative_tsn_p1, MAX_TSN)) {
6470 /* Yep it is above cum-ack */
6471 cnt++;
6476 tsn = ctl->sinfo_tsn;
6477 if (tsn >= asoc->mapping_array_base_tsn) {
6478 gap = tsn -
6479 asoc->mapping_array_base_tsn;
6480 } else {
6481 gap = (MAX_TSN -
6482 asoc->mapping_array_base_tsn) +
6483 tsn + 1;
6484 }
6472 SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn);
6485 asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
6486 sctp_ucount_decr(asoc->cnt_on_all_streams);
6473 asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
6474 sctp_ucount_decr(asoc->cnt_on_all_streams);
6487
6488 SCTP_UNSET_TSN_PRESENT(asoc->mapping_array,
6489 gap);
6490 TAILQ_REMOVE(&asoc->strmin[strmat].inqueue,
6491 ctl, next);
6475 SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
6476 TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next);
6492 if (ctl->data) {
6493 sctp_m_freem(ctl->data);
6494 ctl->data = NULL;
6495 }
6496 sctp_free_remote_addr(ctl->whoFrom);
6497 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
6498 SCTP_DECR_READQ_COUNT();
6499 }
6500 ctl = nctl;
6501 }
6502 }
6477 if (ctl->data) {
6478 sctp_m_freem(ctl->data);
6479 ctl->data = NULL;
6480 }
6481 sctp_free_remote_addr(ctl->whoFrom);
6482 SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl);
6483 SCTP_DECR_READQ_COUNT();
6484 }
6485 ctl = nctl;
6486 }
6487 }
6503 /*
6504 * Question, should we go through the delivery queue? The only
6505 * reason things are on here is the app not reading OR a p-d-api up.
6506 * An attacker COULD send enough in to initiate the PD-API and then
6507 * send a bunch of stuff to other streams... these would wind up on
6508 * the delivery queue.. and then we would not get to them. But in
6509 * order to do this I then have to back-track and un-deliver
6510 * sequence numbers in streams.. el-yucko. I think for now we will
6511 * NOT look at the delivery queue and leave it to be something to
6512 * consider later. An alternative would be to abort the P-D-API with
6513 * a notification and then deliver the data.... Or another method
6514 * might be to keep track of how many times the situation occurs and
6515 * if we see a possible attack underway just abort the association.
6516 */
6517#ifdef SCTP_DEBUG
6518 if (cnt) {
6488 if (cnt) {
6489 /* We must back down to see what the new highest is */
6490 for (i = asoc->highest_tsn_inside_map;
6491 (compare_with_wrap(i, asoc->mapping_array_base_tsn, MAX_TSN) || (i == asoc->mapping_array_base_tsn));
6492 i--) {
6493 SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
6494 if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
6495 asoc->highest_tsn_inside_map = i;
6496 fnd = 1;
6497 break;
6498 }
6499 }
6500 if (!fnd) {
6501 asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
6502 }
6503 /*
6504 * Question, should we go through the delivery queue? The
6505 * only reason things are on here is the app not reading OR
6506 * a p-d-api up. An attacker COULD send enough in to
6507 * initiate the PD-API and then send a bunch of stuff to
6508 * other streams... these would wind up on the delivery
6509 * queue.. and then we would not get to them. But in order
6510 * to do this I then have to back-track and un-deliver
6511 * sequence numbers in streams.. el-yucko. I think for now
6512 * we will NOT look at the delivery queue and leave it to be
6513 * something to consider later. An alternative would be to
6514 * abort the P-D-API with a notification and then deliver
6515 * the data.... Or another method might be to keep track of
6516 * how many times the situation occurs and if we see a
6517 * possible attack underway just abort the association.
6518 */
6519#ifdef SCTP_DEBUG
6519 SCTPDBG(SCTP_DEBUG_PCB1, "Freed %d chunks from reneg harvest\n", cnt);
6520 SCTPDBG(SCTP_DEBUG_PCB1, "Freed %d chunks from reneg harvest\n", cnt);
6520 }
6521#endif
6521#endif
6522 if (cnt) {
6523 /*
6524 * Now do we need to find a new
6525 * asoc->highest_tsn_inside_map?
6526 */
6522 /*
6523 * Now do we need to find a new
6524 * asoc->highest_tsn_inside_map?
6525 */
6527 if (asoc->highest_tsn_inside_map >= asoc->mapping_array_base_tsn) {
6528 gap = asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn;
6529 } else {
6530 gap = (MAX_TSN - asoc->mapping_array_base_tsn) +
6531 asoc->highest_tsn_inside_map + 1;
6532 }
6533 if (gap >= (asoc->mapping_array_size << 3)) {
6534 /*
6535 * Something bad happened or cum-ack and high were
6536 * behind the base, but if so earlier checks should
6537 * have found NO data... wierd... we will start at
6538 * end of mapping array.
6539 */
6540 SCTP_PRINTF("Gap was larger than array?? %d set to max:%d maparraymax:%x\n",
6541 (int)gap,
6542 (int)(asoc->mapping_array_size << 3),
6543 (int)asoc->highest_tsn_inside_map);
6544 gap = asoc->mapping_array_size << 3;
6545 }
6546 while (gap > 0) {
6547 if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
6548 /* found the new highest */
6549 asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn + gap;
6550 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
6551 sctp_log_map(0, 8, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
6552 }
6553 break;
6554 }
6555 gap--;
6556 }
6557 if (gap == 0) {
6558 /* Nothing left in map */
6559 memset(asoc->mapping_array, 0, asoc->mapping_array_size);
6560 asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
6561 asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
6562 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
6563 sctp_log_map(0, 9, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
6564 }
6565 }
6566 asoc->last_revoke_count = cnt;
6567 (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
6568 /* sa_ignore NO_NULL_CHK */
6569 sctp_send_sack(stcb);
6570 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED);
6571 reneged_asoc_ids[reneged_at] = sctp_get_associd(stcb);
6572 reneged_at++;
6573 }

--- 134 unchanged lines hidden ---
6526 asoc->last_revoke_count = cnt;
6527 (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
6528 /* sa_ignore NO_NULL_CHK */
6529 sctp_send_sack(stcb);
6530 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED);
6531 reneged_asoc_ids[reneged_at] = sctp_get_associd(stcb);
6532 reneged_at++;
6533 }

--- 134 unchanged lines hidden ---