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 --- |