diff options
author | rrs <rrs@FreeBSD.org> | 2007-05-30 17:39:45 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-05-30 17:39:45 +0000 |
commit | 00ab510c7cabe5ff0ee618e3e6b7f48fdf9cdbfa (patch) | |
tree | 88cefe357ba00902c5e5d6c978baeaf9a7205cf6 /sys/netinet/sctp_bsd_addr.c | |
parent | ef5ebf1aa24d4addf10e9ed210cffc0459d3ff10 (diff) | |
download | FreeBSD-src-00ab510c7cabe5ff0ee618e3e6b7f48fdf9cdbfa.zip FreeBSD-src-00ab510c7cabe5ff0ee618e3e6b7f48fdf9cdbfa.tar.gz |
- Fix a memory overwrite when the mapping array
is expanded, size of expansion was not taken int consideration.
- Fix so vtag hash is 1 bigger so that it modulo's out
correctly, avoids a panic when restart with right modulo happens.
- do not dereference stcb when control->do_not_ref_stcb is set
- Fix up packet logging to not often use a lock and also to
add to options.
- Fix some logging option duplication in the sctputil.h
Diffstat (limited to 'sys/netinet/sctp_bsd_addr.c')
-rw-r--r-- | sys/netinet/sctp_bsd_addr.c | 202 |
1 files changed, 96 insertions, 106 deletions
diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c index 1abd772..6b4ca68 100644 --- a/sys/netinet/sctp_bsd_addr.c +++ b/sys/netinet/sctp_bsd_addr.c @@ -374,112 +374,103 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, #ifdef SCTP_PACKET_LOGGING -int packet_log_start = 0; +int packet_log_writers = 0; int packet_log_end = 0; -int packet_log_old_end = SCTP_PACKET_LOG_SIZE; -int packet_log_wrapped = 0; uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE]; void sctp_packet_log(struct mbuf *m, int length) { - int *lenat, needed, thisone; + int *lenat, thisone; void *copyto; uint32_t *tick_tock; - int total_len, spare; + int total_len; + int grabbed_lock = 0; + int value, newval, thisend, thisbegin; - total_len = SCTP_SIZE32((length + (2 * sizeof(int)))); + /* + * Buffer layout. -sizeof this entry (total_len) -previous end + * (value) -ticks of log (ticks) o -ip packet o -as logged - + * where this started (thisbegin) x <--end points here + */ + total_len = SCTP_SIZE32((length + (4 * sizeof(int)))); /* Log a packet to the buffer. */ if (total_len > SCTP_PACKET_LOG_SIZE) { /* Can't log this packet I have not a buffer big enough */ return; } if (length < (SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))) { - printf("Huh, length is %d to small for sctp min:%d\n", - length, - (SCTP_MIN_V4_OVERHEAD + sizeof(struct sctp_cookie_ack_chunk))); return; } - SCTP_IP_PKTLOG_LOCK(); - if ((SCTP_PACKET_LOG_SIZE - packet_log_end) <= total_len) { - /* - * it won't fit on the end. We must go back to the - * beginning. To do this we go back and cahnge - * packet_log_start. - */ - int orig_end; - - lenat = (int *)packet_log_buffer; - orig_end = packet_log_end; - packet_log_old_end = packet_log_end; - packet_log_end = 0; - if (packet_log_start > packet_log_old_end) { - /* calculate the head room */ - spare = packet_log_start - packet_log_old_end; + atomic_add_int(&packet_log_writers, 1); +try_again: + if (packet_log_writers > SCTP_PKTLOG_WRITERS_NEED_LOCK) { + SCTP_IP_PKTLOG_LOCK(); + grabbed_lock = 1; +again_locked: + value = packet_log_end; + newval = packet_log_end + total_len; + if (newval >= SCTP_PACKET_LOG_SIZE) { + /* we wrapped */ + thisbegin = 0; + thisend = total_len; } else { - spare = 0; + thisbegin = packet_log_end; + thisend = newval; } - needed = total_len - spare; - packet_log_wrapped = 1; - /* Now update the start */ - while (needed > 0) { - thisone = (*(int *)(&packet_log_buffer[packet_log_start])); - needed -= thisone; - if (thisone == 0) { - int *foo; - - foo = (int *)(&packet_log_buffer[packet_log_start]); - goto insane; - } - /* move to next one */ - packet_log_start += thisone; + if (!(atomic_cmpset_int(&packet_log_end, value, thisend))) { + goto again_locked; } } else { - lenat = (int *)&packet_log_buffer[packet_log_end]; - if (packet_log_start > packet_log_end) { - if ((packet_log_end + total_len) > packet_log_start) { - /* Now need to update killing some packets */ - needed = total_len - ((packet_log_start - packet_log_end)); - while (needed > 0) { - thisone = (*(int *)(&packet_log_buffer[packet_log_start])); - needed -= thisone; - if (thisone == 0) { - goto insane; - } - /* move to next one */ - packet_log_start += thisone; - if (((packet_log_start + sizeof(struct ip)) > SCTP_PACKET_LOG_SIZE) || - (packet_log_wrapped && (packet_log_start >= packet_log_old_end))) { - packet_log_start = 0; - packet_log_old_end = 0; - packet_log_wrapped = 0; - break; - } - } - } + value = packet_log_end; + newval = packet_log_end + total_len; + if (newval >= SCTP_PACKET_LOG_SIZE) { + /* we wrapped */ + thisbegin = 0; + thisend = total_len; + } else { + thisbegin = packet_log_end; + thisend = newval; + } + if (!(atomic_cmpset_int(&packet_log_end, value, thisend))) { + goto try_again; } } - if (((packet_log_end + total_len) >= SCTP_PACKET_LOG_SIZE) || - ((void *)((caddr_t)lenat) < (void *)packet_log_buffer) || - ((void *)((caddr_t)lenat + total_len) > (void *)&packet_log_buffer[SCTP_PACKET_LOG_SIZE])) { - /* Madness protection */ -insane: - printf("Went mad, end:%d start:%d len:%d wrapped:%d oe:%d - zapping\n", - packet_log_end, packet_log_start, total_len, packet_log_wrapped, packet_log_old_end); - packet_log_start = packet_log_end = packet_log_old_end = packet_log_wrapped = 0; - lenat = (int *)&packet_log_buffer[0]; + /* Sanity check */ + if (thisend >= SCTP_PACKET_LOG_SIZE) { + printf("Insanity stops a log thisbegin:%d thisend:%d writers:%d lock:%d end:%d\n", + thisbegin, + thisend, + packet_log_writers, + grabbed_lock, + packet_log_end); + packet_log_end = 0; + goto no_log; + } + lenat = (int *)&packet_log_buffer[thisbegin]; *lenat = total_len; lenat++; + *lenat = value; + lenat++; tick_tock = (uint32_t *) lenat; lenat++; *tick_tock = sctp_get_tick_count(); copyto = (void *)lenat; - packet_log_end = (((caddr_t)copyto + length) - (caddr_t)packet_log_buffer); - SCTP_IP_PKTLOG_UNLOCK(); + thisone = thisend - sizeof(int); + lenat = (int *)&packet_log_buffer[thisone]; + *lenat = thisbegin; + if (grabbed_lock) { + SCTP_IP_PKTLOG_UNLOCK(); + grabbed_lock = 0; + } m_copydata(m, 0, length, (caddr_t)copyto); - +no_log: + if (grabbed_lock) { + SCTP_IP_PKTLOG_UNLOCK(); + } + atomic_subtract_int(&packet_log_writers, 1); } @@ -490,44 +481,43 @@ sctp_copy_out_packet_log(uint8_t * target, int length) * We wind through the packet log starting at start copying up to * length bytes out. We return the number of bytes copied. */ - int tocopy, this_copy, copied = 0; - void *at; + int tocopy, this_copy; + int *lenat; + int did_delay = 0; tocopy = length; - if (packet_log_start == packet_log_end) { - /* no data */ + if (length < (2 * sizeof(int))) { + /* not enough room */ return (0); } - if (packet_log_wrapped) { - /* - * we have a wrapped buffer, we must copy from start to the - * old end. Then copy from the top of the buffer to the end. - */ - SCTP_IP_PKTLOG_LOCK(); - at = (void *)&packet_log_buffer[packet_log_start]; - this_copy = min(tocopy, (packet_log_old_end - packet_log_start)); - memcpy(target, at, this_copy); - tocopy -= this_copy; - copied += this_copy; - if (tocopy == 0) { - SCTP_IP_PKTLOG_UNLOCK(); - return (copied); + if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { + atomic_add_int(&packet_log_writers, SCTP_PKTLOG_WRITERS_NEED_LOCK); +again: + if ((did_delay == 0) && (packet_log_writers != SCTP_PKTLOG_WRITERS_NEED_LOCK)) { + /* + * we delay here for just a moment hoping the + * writer(s) that were present when we entered will + * have left and we only have locking ones that will + * contend with us for the lock. This does not + * assure 100% access, but its good enough for a + * logging facility like this. + */ + did_delay = 1; + DELAY(10); + goto again; } - this_copy = min(tocopy, packet_log_end); - at = (void *)&packet_log_buffer; - memcpy(&target[copied], at, this_copy); - copied += this_copy; - SCTP_IP_PKTLOG_UNLOCK(); - return (copied); - } else { - /* we have one contiguous buffer */ - SCTP_IP_PKTLOG_LOCK(); - at = (void *)&packet_log_buffer; - this_copy = min(length, packet_log_end); - memcpy(target, at, this_copy); - SCTP_IP_PKTLOG_UNLOCK(); - return (this_copy); } + SCTP_IP_PKTLOG_LOCK(); + lenat = (int *)target; + *lenat = packet_log_end; + lenat++; + this_copy = min((length - sizeof(int)), packet_log_end); + memcpy((void *)lenat, (void *)packet_log_buffer, this_copy); + if (SCTP_PKTLOG_WRITERS_NEED_LOCK) { + atomic_subtract_int(&packet_log_writers, SCTP_PKTLOG_WRITERS_NEED_LOCK); + } + SCTP_IP_PKTLOG_UNLOCK(); + return (this_copy + sizeof(int)); } #endif |