From 520c389cb4f290b2acdcff4ed123d33cca39e0d8 Mon Sep 17 00:00:00 2001 From: rrs Date: Tue, 3 Feb 2009 11:04:03 +0000 Subject: - Cleanup checksum code. - Prepare for CRC offloading, add MIB counters (RS/MT). - Bugfix: Disable CRC computation for IPv6 addresses with local scope (MT). - Bugfix: Handle close() with SO_LINGER correctly when notifications are generated during the close() call(MT). - Bugfix: Generate DRY event when sender is dry during subscription. Only for 1-to-1 style sockets (RS/MT) - Bugfix: Put vtags for the correct amount of time into time-wait (MT). - Bugfix: Clear vtag entries correctly on expiration (MT). - Bugfix: shutdown() indicates ENOTCONN when called for unconnected 1-to-1 style sockets (MT). - Bugfix: In sctp Auth code (PL). - Add support for devices that support SCTP csum offload (igb). - Add missing sctp_associd to mib sysctl xsctp_tcb structure (RS) Obtained from: With help from Peter Lei and Michael Tuexen --- sys/netinet/sctp_auth.c | 6 +- sys/netinet/sctp_constants.h | 68 +--- sys/netinet/sctp_crc32.c | 215 +++++++++--- sys/netinet/sctp_crc32.h | 12 +- sys/netinet/sctp_input.c | 46 ++- sys/netinet/sctp_os_bsd.h | 5 +- sys/netinet/sctp_output.c | 806 +++++++++++++++++++++---------------------- sys/netinet/sctp_pcb.c | 44 ++- sys/netinet/sctp_pcb.h | 1 + sys/netinet/sctp_sysctl.c | 16 +- sys/netinet/sctp_uio.h | 8 + sys/netinet/sctp_usrreq.c | 22 ++ sys/netinet/sctputil.c | 332 +++++++++--------- sys/netinet/sctputil.h | 2 - sys/netinet6/sctp6_usrreq.c | 21 +- 15 files changed, 849 insertions(+), 755 deletions(-) diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 71715cc..6da97ec 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -1645,8 +1645,10 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + - sizeof(*hmacs) + hmacs_len; + keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; + if (chunks != NULL) { + keylen += sizeof(*chunks) + num_chunks; + } new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index cc48d2f..ca9c010 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -37,8 +37,15 @@ __FBSDID("$FreeBSD$"); #define __sctp_constants_h__ /* IANA assigned port number for SCTP over UDP encapsulation */ -#define SCTP_OVER_UDP_TUNNELING_PORT 9899 - +/* For freebsd we cannot bind the port at + * startup. Otherwise what will happen is + * we really won't be bound. The user must + * put it into the sysctl... or we need + * to build a special timer for this to allow + * us to wait 1 second or so after the system + * comes up. + */ +#define SCTP_OVER_UDP_TUNNELING_PORT 0 /* Number of packets to get before sack sent by default */ #define SCTP_DEFAULT_SACK_FREQ 2 @@ -310,10 +317,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_PARTIAL_DELIVERY_SHIFT 1 -/* Minimum number of bytes read by user before we - * condsider doing a rwnd update - */ - /* * default HMAC for cookies, etc... use one of the AUTH HMAC id's * SCTP_HMAC is the HMAC_ID to use @@ -323,21 +326,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_SIGNATURE_SIZE SCTP_AUTH_DIGEST_LEN_SHA1 #define SCTP_SIGNATURE_ALOC_SIZE SCTP_SIGNATURE_SIZE -/* DEFINE HERE WHAT CRC YOU WANT TO USE */ -#define SCTP_USECRC_RFC2960 1 -/* #define SCTP_USECRC_FLETCHER 1 */ -/* #define SCTP_USECRC_SSHCRC32 1 */ -/* #define SCTP_USECRC_FASTCRC32 1 */ -/* #define SCTP_USECRC_CRC32 1 */ -/* #define SCTP_USECRC_TCP32 1 */ -/* #define SCTP_USECRC_CRC16SMAL 1 */ -/* #define SCTP_USECRC_CRC16 1 */ -/* #define SCTP_USECRC_MODADLER 1 */ - -#ifndef SCTP_ADLER32_BASE -#define SCTP_ADLER32_BASE 65521 -#endif - /* * the SCTP protocol signature this includes the version number encoded in * the last 4 bits of the signature. @@ -619,43 +607,16 @@ __FBSDID("$FreeBSD$"); -/* - * Number of ticks before the soxwakeup() event that is delayed is sent AFTER - * the accept() call - */ - -/* - * Of course we really don't collect stale cookies, being folks of decerning - * taste. However we do count them, if we get too many before the association - * comes up.. we give up. Below is the constant that dictates when we give it - * up...this is a implemenation dependent treatment. In ours we do not ask - * for a extension of time, but just retry this many times... - */ - /* max number of TSN's dup'd that I will hold */ #define SCTP_MAX_DUP_TSNS 20 /* * Here we define the types used when setting the retry amounts. */ -/* constants for type of set */ - -/* Maximum TSN's we will summarize in a drop report */ - /* How many drop re-attempts we make on INIT/COOKIE-ECHO */ #define SCTP_RETRY_DROPPED_THRESH 4 /* - * And the max we will keep a history of in the tcb which MUST be lower than - * 256. - */ - -/* - * Here we define the default timers and the default number of attemts we - * make for each respective side (send/init). - */ - -/* * Maxmium number of chunks a single association can have on it. Note that * this is a squishy number since the count can run over this if the user * sends a large message down .. the fragmented chunks don't count until @@ -763,7 +724,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_DEBUG_INDATA1 0x01000000 #define SCTP_DEBUG_INDATA2 0x02000000 /* unused */ #define SCTP_DEBUG_INDATA3 0x04000000 /* unused */ -#define SCTP_DEBUG_INDATA4 0x08000000 /* unused */ +#define SCTP_DEBUG_CRCOFFLOAD 0x08000000 /* unused */ #define SCTP_DEBUG_USRREQ1 0x10000000 /* unused */ #define SCTP_DEBUG_USRREQ2 0x20000000 /* unused */ #define SCTP_DEBUG_PEEL1 0x40000000 @@ -783,7 +744,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_INITIAL_CWND 4380 -#define SCTP_DEFAULT_MTU 1500 /* emegency default MTU */ +#define SCTP_DEFAULT_MTU 1500 /* emergency default MTU */ /* amount peer is obligated to have in rwnd or I will abort */ #define SCTP_MIN_RWND 1500 @@ -996,13 +957,6 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_STACK_VTAG_HASH_SIZE 32 - -/* - * If we use the per-endpoint model than we do not have a hash table of - * entries but instead have a single head pointer and we must crawl through - * the entire list. - */ - /* * Number of seconds of time wait for a vtag. */ diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c index 7f0e742..b85ccdd 100644 --- a/sys/netinet/sctp_crc32.c +++ b/sys/netinet/sctp_crc32.c @@ -34,12 +34,16 @@ #include __FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include #include #include +#include -#ifndef SCTP_USE_ADLER32 - - +#if !defined(SCTP_WITH_NO_CSUM) /** * * Routine Description: @@ -80,12 +84,14 @@ __FBSDID("$FreeBSD$"); * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o32[256] = @@ -134,12 +140,14 @@ uint32_t sctp_crc_tableil8_o32[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o40[256] = @@ -188,12 +196,14 @@ uint32_t sctp_crc_tableil8_o40[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o48[256] = @@ -242,12 +252,14 @@ uint32_t sctp_crc_tableil8_o48[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o56[256] = @@ -296,12 +308,14 @@ uint32_t sctp_crc_tableil8_o56[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o64[256] = @@ -350,12 +364,14 @@ uint32_t sctp_crc_tableil8_o64[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o72[256] = @@ -404,12 +420,14 @@ uint32_t sctp_crc_tableil8_o72[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o80[256] = @@ -458,12 +476,14 @@ uint32_t sctp_crc_tableil8_o80[256] = * The following CRC lookup table was generated automagically using the * following model parameters: * - * Generator Polynomial = ................. 0x1EDC6F41 Generator Polynomial - * Length = .......... 32 bits Reflected Bits = ....................... TRUE - * Table Generation Offset = .............. 32 bits Number of Slices = - * ..................... 8 slices Slice Lengths = ........................ 8 - * 8 8 8 8 8 8 8 Directory Name = ....................... .\ File Name = - * ............................ 8x256_tables.c + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Table Generation Offset = .............. 32 bits + * Number of Slices = ..................... 8 slices + * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 + * Directory Name = ....................... .\ + * File Name = ............................ 8x256_tables.c */ uint32_t sctp_crc_tableil8_o88[256] = @@ -506,6 +526,7 @@ uint32_t sctp_crc_tableil8_o88[256] = * end of the CRC lookup table crc_tableil8_o88 */ + static uint32_t sctp_crc32c_sb8_64_bit(uint32_t crc, unsigned char *p_buf, @@ -578,7 +599,7 @@ sctp_crc32c_sb8_64_bit(uint32_t crc, * * none */ -uint32_t +static uint32_t update_crc32(uint32_t crc32c, unsigned char *buffer, unsigned int length) @@ -662,7 +683,7 @@ uint32_t sctp_crc_c[256] = { #define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) -uint32_t +static uint32_t old_update_crc32(uint32_t crc32c, unsigned char *buffer, unsigned int length) @@ -676,8 +697,8 @@ old_update_crc32(uint32_t crc32c, } -uint32_t -sctp_csum_finalize(uint32_t crc32c) +static uint32_t +sctp_finalize_crc32(uint32_t crc32c) { uint32_t result; @@ -709,4 +730,88 @@ sctp_csum_finalize(uint32_t crc32c) return (crc32c); } +#endif /* !defined(SCTP_WITH_NO_CSUM) */ + +#if defined(SCTP_WITH_NO_CSUM) +uint32_t +sctp_calculate_cksum(struct mbuf *m, uint32_t offset) +{ + return (0); +} + +#else +uint32_t +sctp_calculate_cksum(struct mbuf *m, uint32_t offset) +{ + /* + * given a mbuf chain with a packetheader offset by 'offset' + * pointing at a sctphdr (with csum set to 0) go through the chain + * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also + * has a side bonus as it will calculate the total length of the + * mbuf chain. Note: if offset is greater than the total mbuf + * length, checksum=1, pktlen=0 is returned (ie. no real error code) + */ + uint32_t base = 0xffffffff; + struct mbuf *at; + + at = m; + /* find the correct mbuf and offset into mbuf */ + while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) { + offset -= SCTP_BUF_LEN(at); /* update remaining offset + * left */ + at = SCTP_BUF_NEXT(at); + } + while (at != NULL) { + if ((SCTP_BUF_LEN(at) - offset) > 0) { + if ((SCTP_BUF_LEN(at) - offset) < 4) { + /* Use old method if less than 4 bytes */ + base = old_update_crc32(base, + (unsigned char *)(SCTP_BUF_AT(at, offset)), + (unsigned int)(SCTP_BUF_LEN(at) - offset)); + } else { + base = update_crc32(base, + (unsigned char *)(SCTP_BUF_AT(at, offset)), + (unsigned int)(SCTP_BUF_LEN(at) - offset)); + } + /* we only offset once into the first mbuf */ + } + if (offset) { + if (offset < (uint32_t) SCTP_BUF_LEN(at)) + offset = 0; + else + offset -= SCTP_BUF_LEN(at); + } + at = SCTP_BUF_NEXT(at); + } + base = sctp_finalize_crc32(base); + return (base); +} + #endif + +void +sctp_delayed_cksum(struct mbuf *m) +{ + struct ip *ip; + uint32_t checksum; + uint32_t offset; + + ip = mtod(m, struct ip *); + offset = ip->ip_hl << 2; + checksum = sctp_calculate_cksum(m, offset); + SCTP_STAT_DECR(sctps_sendhwcrc); + SCTP_STAT_INCR(sctps_sendswcrc); + offset += offsetof(struct sctphdr, checksum); + + if (offset + sizeof(uint32_t) > (uint32_t) (m->m_len)) { + printf("delayed m_pullup, m->len: %d off: %d p: %d\n", + (uint32_t) m->m_len, offset, ip->ip_p); + /* + * XXX this shouldn't happen, but if it does, the correct + * behavior may be to insert the checksum in the appropriate + * next mbuf in the chain. + */ + return; + } + *(uint32_t *) (m->m_data + offset) = checksum; +} diff --git a/sys/netinet/sctp_crc32.h b/sys/netinet/sctp_crc32.h index 88739ed..634acd4 100644 --- a/sys/netinet/sctp_crc32.h +++ b/sys/netinet/sctp_crc32.h @@ -36,16 +36,10 @@ __FBSDID("$FreeBSD$"); #ifndef __crc32c_h__ #define __crc32c_h__ -#ifndef SCTP_USE_ADLER32 - #if defined(_KERNEL) || defined(__Userspace__) -uint32_t update_crc32(uint32_t, unsigned char *, unsigned int); - -uint32_t old_update_crc32(uint32_t, unsigned char *, unsigned int); - -uint32_t sctp_csum_finalize(uint32_t); - +uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); +void sctp_delayed_cksum(struct mbuf *); #endif /* _KERNEL */ -#endif /* !SCTP_USE_ADLER32 */ + #endif /* __crc32c_h__ */ diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index c686fac..2d8a1f2 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -1384,14 +1385,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* FOOBAR */ return (NULL); } - /* pre-reserve some space */ -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); /* Set the len */ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); ph = mtod(op_err, struct sctp_paramhdr *); @@ -2504,15 +2497,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* FOOBAR */ return (NULL); } - /* pre-reserve some space */ -#ifdef INET6 - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); -#else - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); -#endif - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); - /* Set the len */ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg); scm = mtod(op_err, struct sctp_stale_cookie_msg *); @@ -2598,9 +2582,9 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, } } } - if (to == NULL) + if (to == NULL) { return (NULL); - + } cookie_len -= SCTP_SIGNATURE_SIZE; if (*stcb == NULL) { /* this is the "normal" case... get a new TCB */ @@ -5594,7 +5578,6 @@ sctp_input_with_port(i_pak, off, port) int refcount_up = 0; int length, mlen, offset; - if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) { SCTP_RELEASE_PKT(i_pak); return; @@ -5642,6 +5625,11 @@ sctp_input_with_port(i_pak, off, port) } ip = mtod(m, struct ip *); } + /* validate mbuf chain length with IP payload length */ + if (mlen < (SCTP_GET_IPV4_LENGTH(ip) - iphlen)) { + SCTP_STAT_INCR(sctps_hdrops); + goto bad; + } sh = (struct sctphdr *)((caddr_t)ip + iphlen); ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh)); SCTPDBG(SCTP_DEBUG_INPUT1, @@ -5659,15 +5647,26 @@ sctp_input_with_port(i_pak, off, port) goto bad; } /* validate SCTP checksum */ + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, + "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", + m->m_pkthdr.len, + if_name(m->m_pkthdr.rcvif), + m->m_pkthdr.csum_flags); + if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { + SCTP_STAT_INCR(sctps_recvhwcrc); + goto sctp_skip_csum_4; + } check = sh->checksum; /* save incoming checksum */ if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && ((ip->ip_src.s_addr == ip->ip_dst.s_addr) || (SCTP_IS_IT_LOOPBACK(m))) ) { + SCTP_STAT_INCR(sctps_recvnocrc); goto sctp_skip_csum_4; } sh->checksum = 0; /* prepare for calc */ - calc_check = sctp_calculate_sum(m, &mlen, iphlen); + calc_check = sctp_calculate_cksum(m, iphlen); + SCTP_STAT_INCR(sctps_recvswcrc); if (calc_check != check) { SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", calc_check, check, m, mlen, iphlen); @@ -5699,11 +5698,6 @@ sctp_skip_csum_4: SCTP_STAT_INCR(sctps_hdrops); goto bad; } - /* validate mbuf chain length with IP payload length */ - if (mlen < (SCTP_GET_IPV4_LENGTH(ip) - iphlen)) { - SCTP_STAT_INCR(sctps_hdrops); - goto bad; - } /* * Locate pcb and tcb for datagram sctp_findassociation_addr() wants * IP/SCTP/first chunk header... diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index d0e7a18..fcaf715 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -154,11 +154,8 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT); #define MOD_IPSEC ipsec /* then define the macro(s) that hook into the vimage macros */ -#if defined(__FreeBSD__) && __FreeBSD_version >= 800056 #define MODULE_GLOBAL(__MODULE, __SYMBOL) V_ ## __SYMBOL -#else -#define MODULE_GLOBAL(__MODULE, __SYMBOL) (__SYMBOL) -#endif + /* * */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 9efff50..eac896c 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -5213,6 +5214,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, int ecn_ok, struct sctp_tmit_chunk *chk, int out_of_asoc_ok, + uint16_t src_port, + uint16_t dest_port, + uint32_t v_tag, uint16_t port, int so_locked, #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) @@ -5237,7 +5241,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, struct mbuf *newm; struct sctphdr *sctphdr; int packet_length; - uint32_t csum; int ret; uint32_t vrf_id; sctp_route_t *ro = NULL; @@ -5263,51 +5266,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, if ((auth != NULL) && (stcb != NULL)) { sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid); } - /* Calculate the csum and fill in the length of the packet */ - sctphdr = mtod(m, struct sctphdr *); - if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (to->sa_family == AF_INET) && - (stcb->asoc.loopback_scope)) { - sctphdr->checksum = 0; - /* - * This can probably now be taken out since my audit shows - * no more bad pktlen's coming in. But we will wait a while - * yet. - */ - packet_length = sctp_calculate_len(m); - } else { - sctphdr->checksum = 0; - csum = sctp_calculate_sum(m, &packet_length, 0); - sctphdr->checksum = csum; - } - if (to->sa_family == AF_INET) { struct ip *ip = NULL; sctp_route_t iproute; uint8_t tos_value; + int len; + len = sizeof(struct ip) + sizeof(struct sctphdr); if (port) { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA); + len += sizeof(struct udphdr); } + newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } - if (port) { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip) + sizeof(struct udphdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip) + sizeof(struct udphdr); - packet_length += sizeof(struct ip) + sizeof(struct udphdr); - } else { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip)); - SCTP_BUF_LEN(newm) = sizeof(struct ip); - packet_length += sizeof(struct ip); - } + SCTP_ALIGN_TO_END(newm, len); + SCTP_BUF_LEN(newm) = len; SCTP_BUF_NEXT(newm) = m; m = newm; + packet_length = sctp_calculate_len(m); ip = mtod(m, struct ip *); ip->ip_v = IPVERSION; ip->ip_hl = (sizeof(struct ip) >> 2); @@ -5401,12 +5380,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } } if (port) { - udp = (struct udphdr *)(ip + 1); + udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_ulen = htons(packet_length - sizeof(struct ip)); udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); + sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip)); } + + sctphdr->src_port = src_port; + sctphdr->dest_port = dest_port; + sctphdr->v_tag = v_tag; + sctphdr->checksum = 0; + /* * If source address selection fails and we find no route * then the ip_output should fail as well with a @@ -5517,7 +5505,25 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + m->m_pkthdr.csum_flags = CSUM_SCTP; + m->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -5591,6 +5597,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, struct sockaddr_in6 lsa6_storage; int error; u_short prev_port = 0; + int len; if (net != NULL) { flowlabel = net->tos_flowlabel; @@ -5598,27 +5605,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; } + len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr); if (port) { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); + len += sizeof(struct udphdr); } + newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } - if (port) { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr) + sizeof(struct udphdr); - packet_length += sizeof(struct ip6_hdr) + sizeof(struct udphdr); - } else { - SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr)); - SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr); - packet_length += sizeof(struct ip6_hdr); - } + SCTP_ALIGN_TO_END(newm, len); + SCTP_BUF_LEN(newm) = len; SCTP_BUF_NEXT(newm) = m; m = newm; + packet_length = sctp_calculate_len(m); ip6h = mtod(m, struct ip6_hdr *); /* @@ -5763,12 +5764,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ip6h->ip6_src = lsa6->sin6_addr; if (port) { - udp = (struct udphdr *)(ip6h + 1); + udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr)); udp->uh_sum = 0; + sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); + } else { + sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); } + + sctphdr->src_port = src_port; + sctphdr->dest_port = dest_port; + sctphdr->v_tag = v_tag; + sctphdr->checksum = 0; + /* * We set the hop limit now since there is a good chance * that our ro pointer is now filled @@ -5805,9 +5815,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } + } else { + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && + (stcb->asoc.loopback_scope))) { + m->m_pkthdr.csum_flags = CSUM_SCTP; + m->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); + } else { + SCTP_STAT_INCR(sctps_sendnocrc); + } } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -5905,7 +5933,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked { struct mbuf *m, *m_at, *mp_last; struct sctp_nets *net; - struct sctp_init_msg *initm; + struct sctp_init_chunk *init; struct sctp_supported_addr_param *sup_addr; struct sctp_adaptation_layer_indication *ali; struct sctp_ecn_supported_param *ecn; @@ -5961,7 +5989,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n"); return; } - SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg); + SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk); /* * assume peer supports asconf in order to be able to queue local * address changes while an INIT is in flight and before the assoc @@ -5969,28 +5997,24 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked */ stcb->asoc.peer_supports_asconf = 1; /* Now lets put the SCTP header in place */ - initm = mtod(m, struct sctp_init_msg *); - initm->sh.src_port = inp->sctp_lport; - initm->sh.dest_port = stcb->rport; - initm->sh.v_tag = 0; - initm->sh.checksum = 0; /* calculate later */ + init = mtod(m, struct sctp_init_chunk *); /* now the chunk header */ - initm->msg.ch.chunk_type = SCTP_INITIATION; - initm->msg.ch.chunk_flags = 0; + init->ch.chunk_type = SCTP_INITIATION; + init->ch.chunk_flags = 0; /* fill in later from mbuf we build */ - initm->msg.ch.chunk_length = 0; + init->ch.chunk_length = 0; /* place in my tag */ - initm->msg.init.initiate_tag = htonl(stcb->asoc.my_vtag); + init->init.initiate_tag = htonl(stcb->asoc.my_vtag); /* set up some of the credits. */ - initm->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), + init->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND)); - initm->msg.init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); - initm->msg.init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); - initm->msg.init.initial_tsn = htonl(stcb->asoc.init_seq_number); + init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); + init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); + init->init.initial_tsn = htonl(stcb->asoc.init_seq_number); /* now the address restriction */ - sup_addr = (struct sctp_supported_addr_param *)((caddr_t)initm + - sizeof(*initm)); + sup_addr = (struct sctp_supported_addr_param *)((caddr_t)init + + sizeof(*init)); sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE); #ifdef INET6 /* we support 2 types: IPv6/IPv4 */ @@ -6004,7 +6028,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked sup_addr->addr_type[1] = htons(0); /* this is the padding */ #endif SCTP_BUF_LEN(m) += sizeof(*sup_addr) + sizeof(uint16_t); - /* adaptation layer indication parameter */ ali = (struct sctp_adaptation_layer_indication *)((caddr_t)sup_addr + sizeof(*sup_addr) + sizeof(uint16_t)); ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); @@ -6013,6 +6036,16 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTP_BUF_LEN(m) += sizeof(*ali); ecn = (struct sctp_ecn_supported_param *)((caddr_t)ali + sizeof(*ali)); + if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { + /* Add NAT friendly parameter */ + struct sctp_paramhdr *ph; + + ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); + ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); + ph->param_length = htons(sizeof(struct sctp_paramhdr)); + SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr); + ecn = (struct sctp_ecn_supported_param *)((caddr_t)ph + sizeof(*ph)); + } /* now any cookie time extensions */ if (stcb->asoc.cookie_preserve_req) { struct sctp_cookie_perserve_param *cookie_preserve; @@ -6052,19 +6085,22 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) + if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; + } /* * EY if the initiator supports nr_sacks, need to report that to * responder in INIT chunk */ - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; + } p_len = sizeof(*pr_supported) + num_ext; pr_supported->ph.param_length = htons(p_len); bzero((caddr_t)pr_supported + p_len, SCTP_SIZE32(p_len) - p_len); SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len); + /* ECN nonce: And now tell the peer we support ECN nonce */ if (SCTP_BASE_SYSCTL(sctp_ecn_nonce)) { ecn_nonce = (struct sctp_ecn_nonce_supported_param *) @@ -6073,15 +6109,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked ecn_nonce->ph.param_length = htons(sizeof(*ecn_nonce)); SCTP_BUF_LEN(m) += sizeof(*ecn_nonce); } - if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { - /* Add NAT friendly parameter */ - struct sctp_paramhdr *ph; - - ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); - ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); - ph->param_length = htons(sizeof(struct sctp_paramhdr)); - SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr)); - } /* add authentication parameters */ if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { struct sctp_auth_random *randp; @@ -6160,7 +6187,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked mp_last = m_at; p_len += SCTP_BUF_LEN(m_at); } - initm->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr))); + init->ch.chunk_length = htons(p_len); /* * We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return * here since the timer will drive a retranmission. @@ -6185,7 +6212,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); ret = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m, 0, NULL, 0, 0, 0, NULL, 0, net->port, so_locked, NULL); + m, 0, NULL, 0, 0, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(0), + net->port, so_locked, NULL); SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); @@ -6711,7 +6740,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, { struct sctp_association *asoc; struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last; - struct sctp_init_msg *initackm_out; + struct sctp_init_ack_chunk *initack; struct sctp_adaptation_layer_indication *ali; struct sctp_ecn_supported_param *ecn; struct sctp_prsctp_supported_param *prsctp; @@ -6776,7 +6805,7 @@ do_a_abort: sctp_m_freem(op_err); return; } - SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg); + SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk); /* the time I built cookie */ (void)SCTP_GETTIME_TIMEVAL(&stc.time_entered); @@ -7059,29 +7088,25 @@ do_a_abort: } } /* Now lets put the SCTP header in place */ - initackm_out = mtod(m, struct sctp_init_msg *); - initackm_out->sh.src_port = inp->sctp_lport; - initackm_out->sh.dest_port = sh->src_port; - initackm_out->sh.v_tag = init_chk->init.initiate_tag; + initack = mtod(m, struct sctp_init_ack_chunk *); /* Save it off for quick ref */ stc.peers_vtag = init_chk->init.initiate_tag; - initackm_out->sh.checksum = 0; /* calculate later */ /* who are we */ memcpy(stc.identification, SCTP_VERSION_STRING, min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification))); /* now the chunk header */ - initackm_out->msg.ch.chunk_type = SCTP_INITIATION_ACK; - initackm_out->msg.ch.chunk_flags = 0; + initack->ch.chunk_type = SCTP_INITIATION_ACK; + initack->ch.chunk_flags = 0; /* fill in later from mbuf we build */ - initackm_out->msg.ch.chunk_length = 0; + initack->ch.chunk_length = 0; /* place in my tag */ if ((asoc != NULL) && ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) || (SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) || (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) { /* re-use the v-tags and init-seq here */ - initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); - initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number); + initack->init.initiate_tag = htonl(asoc->my_vtag); + initack->init.initial_tsn = htonl(asoc->init_seq_number); } else { uint32_t vtag, itsn; @@ -7101,17 +7126,17 @@ do_a_abort: */ goto new_tag; } - initackm_out->msg.init.initiate_tag = htonl(vtag); + initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ itsn = sctp_select_initial_TSN(&inp->sctp_ep); - initackm_out->msg.init.initial_tsn = htonl(itsn); + initack->init.initial_tsn = htonl(itsn); SCTP_TCB_LOCK(stcb); atomic_add_int(&asoc->refcnt, -1); } else { vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); - initackm_out->msg.init.initiate_tag = htonl(vtag); + initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ - initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); } if (hold_inp_lock) { SCTP_INP_RLOCK(inp); @@ -7119,7 +7144,7 @@ do_a_abort: } } /* save away my tag to */ - stc.my_vtag = initackm_out->msg.init.initiate_tag; + stc.my_vtag = initack->init.initiate_tag; /* set up some of the credits. */ so = inp->sctp_socket; @@ -7128,7 +7153,7 @@ do_a_abort: sctp_m_freem(m); return; } else { - initackm_out->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); + initack->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); } /* set what I want */ his_limit = ntohs(init_chk->init.num_inbound_streams); @@ -7144,17 +7169,17 @@ do_a_abort: } if (his_limit < i_want) { /* I Want more :< */ - initackm_out->msg.init.num_outbound_streams = init_chk->init.num_inbound_streams; + initack->init.num_outbound_streams = init_chk->init.num_inbound_streams; } else { /* I can have what I want :> */ - initackm_out->msg.init.num_outbound_streams = htons(i_want); + initack->init.num_outbound_streams = htons(i_want); } /* tell him his limt. */ - initackm_out->msg.init.num_inbound_streams = + initack->init.num_inbound_streams = htons(inp->sctp_ep.max_open_streams_intome); /* adaptation layer indication parameter */ - ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initackm_out + sizeof(*initackm_out)); + ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initack + sizeof(*initack)); ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); ali->ph.param_length = htons(sizeof(*ali)); ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator); @@ -7183,7 +7208,7 @@ do_a_abort: ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); ph->param_length = htons(sizeof(struct sctp_paramhdr)); - SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr)); + SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr); } /* And now tell the peer we do all the extensions */ pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m)); @@ -7317,8 +7342,7 @@ do_a_abort: } /* Now we must build a cookie */ - m_cookie = sctp_add_cookie(inp, init_pkt, offset, m, - sizeof(struct sctphdr), &stc, &signature); + m_cookie = sctp_add_cookie(inp, init_pkt, offset, m, 0, &stc, &signature); if (m_cookie == NULL) { /* memory problem */ sctp_m_freem(m); @@ -7339,7 +7363,7 @@ do_a_abort: * Place in the size, but we don't include the last pad (if any) in * the INIT-ACK. */ - initackm_out->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr))); + initack->ch.chunk_length = htons(p_len); /* * Time to sign the cookie, we don't sign over the cookie signature @@ -7370,11 +7394,12 @@ do_a_abort: over_addr = &store1; } else { over_addr = NULL; - } (void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0, - 0, NULL, 0, port, SCTP_SO_NOT_LOCKED, over_addr); + 0, NULL, 0, + inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag, + port, SCTP_SO_NOT_LOCKED, over_addr); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -9164,7 +9189,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_nets *net; struct mbuf *outchain, *endoutchain; struct sctp_tmit_chunk *chk, *nchk; - struct sctphdr *shdr; /* temp arrays for unlinking */ struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; @@ -9177,7 +9201,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, int tsns_sent = 0; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; - uint16_t auth_keyid = 0; + uint16_t auth_keyid; + int override_ok = 1; int data_auth_reqd = 0; /* @@ -9189,6 +9214,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, *num_out = 0; cwnd_full_ind = 0; + auth_keyid = stcb->asoc.authinfo.active_keyid; if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) || @@ -9532,24 +9558,14 @@ again_one_more_time: * it is used to do appropriate * source address selection. */ - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* no memory */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - *reason_code = 7; - continue; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, - outchain, auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { + outchain, auth_offset, auth, + stcb->asoc.authinfo.active_keyid, + no_fragmentflg, 0, NULL, asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -9773,24 +9789,15 @@ again_one_more_time: sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); cookie = 0; } - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* no memory */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - goto error_out_again; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, outchain, - auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { + auth_offset, auth, + stcb->asoc.authinfo.active_keyid, + no_fragmentflg, 0, NULL, asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -9798,7 +9805,6 @@ again_one_more_time: if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } - error_out_again: /* error, could not output */ if (hbflag) { if (*now_filled == 0) { @@ -9948,8 +9954,16 @@ again_one_more_time: &auth_offset, stcb, SCTP_DATA); + auth_keyid = chk->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { + /* + * use this data's + * keyid + */ auth_keyid = chk->auth_keyid; + override_ok = 0; } else if (auth_keyid != chk->auth_keyid) { /* * different keyid, @@ -10072,25 +10086,6 @@ again_one_more_time: sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } /* Now send it, if there is anything to send :> */ - SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); - if (outchain == NULL) { - /* out of mbufs */ - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - error = ENOBUFS; - goto errored_send; - } - shdr = mtod(outchain, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - /* - * if data auth isn't needed, use the assoc active - * key - */ - if (!data_auth_reqd) - auth_keyid = stcb->asoc.authinfo.active_keyid; if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, @@ -10102,7 +10097,10 @@ again_one_more_time: no_fragmentflg, bundle_at, data_list[0], - asconf, net->port, so_locked, NULL))) { + asconf, + inp->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { /* error, we could not output */ if (error == ENOBUFS) { SCTP_STAT_INCR(sctps_lowlevelerr); @@ -10111,7 +10109,6 @@ again_one_more_time: if (from_where == 0) { SCTP_STAT_INCR(sctps_lowlevelerrusr); } - errored_send: SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); if (hbflag) { if (*now_filled == 0) { @@ -10727,7 +10724,6 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; struct sctp_tmit_chunk *chk, *fwd; struct mbuf *m, *endofchain; - struct sctphdr *shdr; struct sctp_nets *net = NULL; uint32_t tsns_sent = 0; int no_fragmentflg, bundle_at, cnt_thru; @@ -10735,7 +10731,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started; struct sctp_auth_chunk *auth = NULL; uint32_t auth_offset = 0; - uint16_t auth_keyid = 0; + uint16_t auth_keyid; + int override_ok = 1; int data_auth_reqd = 0; uint32_t dmtu = 0; @@ -10746,6 +10743,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, *cnt_out = 0; fwd = NULL; endofchain = m = NULL; + auth_keyid = stcb->asoc.authinfo.active_keyid; #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xC3, 1); #endif @@ -10803,24 +10801,13 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo); } else if (chk->rec.chunk_id.id == SCTP_ASCONF) sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo); - - SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); - if (m == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - shdr = mtod(m, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); chk->snd_count++; /* update our count */ - if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, (struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset, auth, stcb->asoc.authinfo.active_keyid, - no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked, NULL))) { + no_fragmentflg, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + chk->whoTo->port, so_locked, NULL))) { SCTP_STAT_INCR(sctps_lowlevelerr); return (error); } @@ -10954,8 +10941,12 @@ one_chunk_around: &auth_offset, stcb, SCTP_DATA); + auth_keyid = chk->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { auth_keyid = chk->auth_keyid; + override_ok = 0; } else if (chk->auth_keyid != auth_keyid) { /* different keyid, so done bundling */ break; @@ -11010,8 +11001,12 @@ one_chunk_around: &auth_offset, stcb, SCTP_DATA); + auth_keyid = fwd->auth_keyid; + override_ok = 0; SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + } else if (override_ok) { auth_keyid = fwd->auth_keyid; + override_ok = 0; } else if (fwd->auth_keyid != auth_keyid) { /* * different keyid, @@ -11059,28 +11054,13 @@ one_chunk_around: sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); tmr_started = 1; } - SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); - if (m == NULL) { - SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); - return (ENOBUFS); - } - shdr = mtod(m, struct sctphdr *); - shdr->src_port = inp->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - /* - * if doing DATA auth, use the data chunk(s) key id, - * otherwise use the assoc's active key id - */ - if (!data_auth_reqd) - auth_keyid = stcb->asoc.authinfo.active_keyid; /* Now lets send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, m, auth_offset, auth, auth_keyid, - no_fragmentflg, 0, NULL, 0, net->port, so_locked, NULL))) { + no_fragmentflg, 0, NULL, 0, + inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + net->port, so_locked, NULL))) { /* error, we could not output */ SCTP_STAT_INCR(sctps_lowlevelerr); return (error); @@ -12401,7 +12381,6 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked int sz; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; - struct sctphdr *shdr; /*- * Add an AUTH chunk, if chunk requires it and save the offset into @@ -12449,23 +12428,12 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked abort->ch.chunk_flags = 0; abort->ch.chunk_length = htons(sizeof(*abort) + sz); - /* prepend and fill in the SCTP header */ - SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT); - if (m_out == NULL) { - /* TSNH: no memory */ - return; - } - shdr = mtod(m_out, struct sctphdr *); - shdr->src_port = stcb->sctp_ep->sctp_lport; - shdr->dest_port = stcb->rport; - shdr->v_tag = htonl(stcb->asoc.peer_vtag); - shdr->checksum = 0; - auth_offset += sizeof(struct sctphdr); - (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, stcb->asoc.primary_destination, (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr, - m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked, NULL); + m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, + stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), + stcb->asoc.primary_destination->port, so_locked, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -12475,26 +12443,24 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, { /* formulate and SEND a SHUTDOWN-COMPLETE */ struct mbuf *m_shutdown_comp; - struct sctp_shutdown_complete_msg *comp_cp; + struct sctp_shutdown_complete_chunk *shutdown_complete; - m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_complete_msg), 0, M_DONTWAIT, 1, MT_HEADER); + m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER); if (m_shutdown_comp == NULL) { /* no mbuf's */ return; } - comp_cp = mtod(m_shutdown_comp, struct sctp_shutdown_complete_msg *); - comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; - comp_cp->shut_cmp.ch.chunk_flags = 0; - comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); - comp_cp->sh.src_port = stcb->sctp_ep->sctp_lport; - comp_cp->sh.dest_port = stcb->rport; - comp_cp->sh.v_tag = htonl(stcb->asoc.peer_vtag); - comp_cp->sh.checksum = 0; - - SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg); + shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *); + shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; + shutdown_complete->ch.chunk_flags = 0; + shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); + SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk); (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED, NULL); + m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0, + stcb->sctp_ep->sctp_lport, stcb->rport, + htonl(stcb->asoc.peer_vtag), + net->port, SCTP_SO_NOT_LOCKED, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); return; } @@ -12532,10 +12498,11 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (port) { len += sizeof(struct udphdr); } - mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); if (mout == NULL) { return; } + SCTP_BUF_RESV_UF(mout, max_linkhdr); SCTP_BUF_LEN(mout) = len; SCTP_BUF_NEXT(mout) = NULL; iph_out = NULL; @@ -12596,6 +12563,7 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, #endif /* INET6 */ default: /* Currently not supported. */ + sctp_m_freem(mout); return; } if (port) { @@ -12621,8 +12589,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); - /* add checksum */ - comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out); if (iph_out != NULL) { sctp_route_t ro; int ret; @@ -12636,10 +12602,16 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, mlen); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, mlen); if (port) { - SCTP_ENABLE_UDP_CSUM(o_pak); + comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ENABLE_UDP_CSUM(mout); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } + SCTP_ATTACH_CHAIN(o_pak, mout, mlen); /* out it goes */ SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); @@ -12660,6 +12632,8 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, mlen); #endif + comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ATTACH_CHAIN(o_pak, mout, mlen); if (port) { if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), @@ -13493,17 +13467,22 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, break; #endif default: + if (err_cause) { + sctp_m_freem(err_cause); + } return; } if (port) { len += sizeof(struct udphdr); } - mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA); + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); if (mout == NULL) { - if (err_cause) + if (err_cause) { sctp_m_freem(err_cause); + } return; } + SCTP_BUF_RESV_UF(mout, max_linkhdr); SCTP_BUF_LEN(mout) = len; SCTP_BUF_NEXT(mout) = err_cause; iph_out = NULL; @@ -13556,8 +13535,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif /* INET6 */ default: /* Currently not supported */ - if (err_cause) - sctp_m_freem(err_cause); sctp_m_freem(mout); return; } @@ -13608,8 +13585,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch)); } - /* add checksum */ - abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out); if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { /* no mbuf's */ sctp_m_freem(mout); @@ -13637,7 +13612,13 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { + abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); @@ -13664,6 +13645,8 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) sctp_packet_log(mout, len); #endif + abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { @@ -13679,6 +13662,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_STAT_INCR(sctps_sendpackets); SCTP_STAT_INCR_COUNTER64(sctps_outpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } void @@ -13686,211 +13670,219 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, uint32_t vrf_id, uint16_t port) { struct mbuf *o_pak; - struct sctphdr *ihdr; - int retcode; - struct sctphdr *ohdr; - struct sctp_chunkhdr *ophdr; - struct ip *iph; + struct sctphdr *sh, *sh_out; + struct sctp_chunkhdr *ch; + struct ip *iph, *iph_out; struct udphdr *udp = NULL; struct mbuf *mout; #ifdef INET6 -#ifdef SCTP_DEBUG - struct sockaddr_in6 lsa6, fsa6; + struct ip6_hdr *ip6, *ip6_out; #endif -#endif - uint32_t val; - struct mbuf *at; - int len; + int iphlen_out, len; iph = mtod(m, struct ip *); - ihdr = (struct sctphdr *)((caddr_t)iph + iphlen); - - SCTP_BUF_PREPEND(scm, (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)), M_DONTWAIT); - if (scm == NULL) { - /* can't send because we can't add a mbuf */ + sh = (struct sctphdr *)((caddr_t)iph + iphlen); + switch (iph->ip_v) { + case IPVERSION: + len = (sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + len = (sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)); + break; +#endif + default: + if (scm) { + sctp_m_freem(scm); + } return; } - ohdr = mtod(scm, struct sctphdr *); - ohdr->src_port = ihdr->dest_port; - ohdr->dest_port = ihdr->src_port; - ohdr->v_tag = vtag; - ohdr->checksum = 0; - ophdr = (struct sctp_chunkhdr *)(ohdr + 1); - ophdr->chunk_type = SCTP_OPERATION_ERROR; - ophdr->chunk_flags = 0; - len = 0; - at = scm; - while (at) { - len += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); + if (port) { + len += sizeof(struct udphdr); } - ophdr->chunk_length = htons(len - sizeof(struct sctphdr)); - if (len % 4) { - /* need padding */ - uint32_t cpthis = 0; - int padlen; - - padlen = 4 - (len % 4); - m_copyback(scm, len, padlen, (caddr_t)&cpthis); - len += padlen; + mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA); + if (mout == NULL) { + if (scm) { + sctp_m_freem(scm); + } + return; } - val = sctp_calculate_sum(scm, NULL, 0); + SCTP_BUF_RESV_UF(mout, max_linkhdr); + SCTP_BUF_LEN(mout) = len; + SCTP_BUF_NEXT(mout) = scm; + iph_out = NULL; #ifdef INET6 - if (port) { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); + ip6_out = NULL; +#endif + switch (iph->ip_v) { + case IPVERSION: + iph_out = mtod(mout, struct ip *); + + /* Fill in the IP header for the ABORT */ + iph_out->ip_v = IPVERSION; + iph_out->ip_hl = (sizeof(struct ip) / 4); + iph_out->ip_tos = (u_char)0; + iph_out->ip_id = 0; + iph_out->ip_off = 0; + iph_out->ip_ttl = MAXTTL; + if (port) { + iph_out->ip_p = IPPROTO_UDP; + } else { + iph_out->ip_p = IPPROTO_SCTP; + } + iph_out->ip_src.s_addr = iph->ip_dst.s_addr; + iph_out->ip_dst.s_addr = iph->ip_src.s_addr; + /* let IP layer calculate this */ + iph_out->ip_sum = 0; + + iphlen_out = sizeof(struct ip); + sh_out = (struct sctphdr *)((caddr_t)iph_out + iphlen_out); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + ip6 = (struct ip6_hdr *)iph; + ip6_out = mtod(mout, struct ip6_hdr *); + + /* Fill in the IP6 header for the ABORT */ + ip6_out->ip6_flow = ip6->ip6_flow; + ip6_out->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim); + if (port) { + ip6_out->ip6_nxt = IPPROTO_UDP; + } else { + ip6_out->ip6_nxt = IPPROTO_SCTP; + } + ip6_out->ip6_src = ip6->ip6_dst; + ip6_out->ip6_dst = ip6->ip6_src; + + iphlen_out = sizeof(struct ip6_hdr); + sh_out = (struct sctphdr *)((caddr_t)ip6_out + iphlen_out); + break; +#endif /* INET6 */ + default: + /* Currently not supported */ + sctp_m_freem(mout); + return; } -#else + + udp = (struct udphdr *)sh_out; if (port) { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA); - } else { - mout = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA); + udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); + udp->uh_dport = port; + /* set udp->uh_ulen later */ + udp->uh_sum = 0; + iphlen_out += sizeof(struct udphdr); + sh_out = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); } -#endif - if (mout == NULL) { - sctp_m_freem(scm); - return; + sh_out->src_port = sh->dest_port; + sh_out->dest_port = sh->src_port; + sh_out->v_tag = vtag; + sh_out->checksum = 0; + + ch = (struct sctp_chunkhdr *)((caddr_t)sh_out + sizeof(struct sctphdr)); + ch->chunk_type = SCTP_OPERATION_ERROR; + ch->chunk_flags = 0; + + if (scm) { + struct mbuf *m_tmp = scm; + int cause_len = 0; + + /* get length of the err_cause chain */ + while (m_tmp != NULL) { + cause_len += SCTP_BUF_LEN(m_tmp); + m_tmp = SCTP_BUF_NEXT(m_tmp); + } + len = SCTP_BUF_LEN(mout) + cause_len; + if (cause_len % 4) { + /* need pad at end of chunk */ + uint32_t cpthis = 0; + int padlen; + + padlen = 4 - (len % 4); + m_copyback(mout, len, padlen, (caddr_t)&cpthis); + len += padlen; + } + ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len); + } else { + len = SCTP_BUF_LEN(mout); + ch->chunk_length = htons(sizeof(struct sctp_chunkhdr)); } - SCTP_BUF_NEXT(mout) = scm; + if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { + /* no mbuf's */ sctp_m_freem(mout); return; } - ohdr->checksum = val; - switch (iph->ip_v) { - case IPVERSION: - { - /* V4 */ - struct ip *out; - sctp_route_t ro; - struct sctp_tcb *stcb = NULL; - - SCTP_BUF_LEN(mout) = sizeof(struct ip); - len += sizeof(struct ip); - if (port) { - SCTP_BUF_LEN(mout) += sizeof(struct udphdr); - len += sizeof(struct udphdr); - } - bzero(&ro, sizeof ro); - out = mtod(mout, struct ip *); - out->ip_v = iph->ip_v; - out->ip_hl = (sizeof(struct ip) / 4); - out->ip_tos = iph->ip_tos; - out->ip_id = iph->ip_id; - out->ip_off = 0; - out->ip_ttl = MAXTTL; - if (port) { - out->ip_p = IPPROTO_UDP; - } else { - out->ip_p = IPPROTO_SCTP; - } - out->ip_sum = 0; - out->ip_src = iph->ip_dst; - out->ip_dst = iph->ip_src; - out->ip_len = len; - if (port) { - udp = (struct udphdr *)(out + 1); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons(len - sizeof(struct ip)); - udp->uh_sum = in_pseudo(out->ip_src.s_addr, out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); - } + if (iph_out != NULL) { + sctp_route_t ro; + struct sctp_tcb *stcb = NULL; + int ret; + + /* zap the stack pointer to the route */ + bzero(&ro, sizeof ro); + if (port) { + udp->uh_ulen = htons(len - sizeof(struct ip)); + udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); + } + /* set IPv4 length */ + iph_out->ip_len = len; + /* out it goes */ #ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(mout, len); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) + sctp_packet_log(mout, len); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, len); - if (port) { - SCTP_ENABLE_UDP_CSUM(o_pak); - } - SCTP_IP_OUTPUT(retcode, o_pak, &ro, stcb, vrf_id); - - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - /* Free the route if we got one back */ - if (ro.ro_rt) - RTFREE(ro.ro_rt); - break; + SCTP_ATTACH_CHAIN(o_pak, mout, len); + if (port) { + sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ENABLE_UDP_CSUM(o_pak); + } else { + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; /* FIXME MT */ + SCTP_STAT_INCR(sctps_sendhwcrc); } + SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); + + /* Free the route if we got one back */ + if (ro.ro_rt) + RTFREE(ro.ro_rt); + } #ifdef INET6 - case IPV6_VERSION >> 4: - { - /* V6 */ - struct route_in6 ro; - int ret; - struct sctp_tcb *stcb = NULL; - struct ifnet *ifp = NULL; - struct ip6_hdr *out6, *in6; - - SCTP_BUF_LEN(mout) = sizeof(struct ip6_hdr); - len += sizeof(struct ip6_hdr); - bzero(&ro, sizeof ro); - if (port) { - SCTP_BUF_LEN(mout) += sizeof(struct udphdr); - len += sizeof(struct udphdr); - } - in6 = mtod(m, struct ip6_hdr *); - out6 = mtod(mout, struct ip6_hdr *); - out6->ip6_flow = in6->ip6_flow; - out6->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim); - if (port) { - out6->ip6_nxt = IPPROTO_UDP; - } else { - out6->ip6_nxt = IPPROTO_SCTP; - } - out6->ip6_src = in6->ip6_dst; - out6->ip6_dst = in6->ip6_src; - out6->ip6_plen = len - sizeof(struct ip6_hdr); - if (port) { - udp = (struct udphdr *)(out6 + 1); - udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - udp->uh_dport = port; - udp->uh_ulen = htons(len - sizeof(struct ip6_hdr)); - udp->uh_sum = 0; - } -#ifdef SCTP_DEBUG - bzero(&lsa6, sizeof(lsa6)); - lsa6.sin6_len = sizeof(lsa6); - lsa6.sin6_family = AF_INET6; - lsa6.sin6_addr = out6->ip6_src; - bzero(&fsa6, sizeof(fsa6)); - fsa6.sin6_len = sizeof(fsa6); - fsa6.sin6_family = AF_INET6; - fsa6.sin6_addr = out6->ip6_dst; -#endif - SCTPDBG(SCTP_DEBUG_OUTPUT2, "sctp_operr_to calling ipv6 output:\n"); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "src: "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&lsa6); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "dst "); - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&fsa6); + if (ip6_out != NULL) { + struct route_in6 ro; + int ret; + struct sctp_tcb *stcb = NULL; + struct ifnet *ifp = NULL; + /* zap the stack pointer to the route */ + bzero(&ro, sizeof(ro)); + if (port) { + udp->uh_ulen = htons(len - sizeof(struct ip6_hdr)); + } + ip6_out->ip6_plen = len - sizeof(*ip6_out); #ifdef SCTP_PACKET_LOGGING - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) - sctp_packet_log(mout, len); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) + sctp_packet_log(mout, len); #endif - SCTP_ATTACH_CHAIN(o_pak, mout, len); - if (port) { - if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { - udp->uh_sum = 0xffff; - } + sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out); + SCTP_STAT_INCR(sctps_sendswcrc); + SCTP_ATTACH_CHAIN(o_pak, mout, len); + if (port) { + if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { + udp->uh_sum = 0xffff; } - SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); - - SCTP_STAT_INCR(sctps_sendpackets); - SCTP_STAT_INCR_COUNTER64(sctps_outpackets); - /* Free the route if we got one back */ - if (ro.ro_rt) - RTFREE(ro.ro_rt); - break; } -#endif /* INET6 */ - default: - /* TSNH */ - break; + SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); + + /* Free the route if we got one back */ + if (ro.ro_rt) + RTFREE(ro.ro_rt); } +#endif + SCTP_STAT_INCR(sctps_sendpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outpackets); + SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } static struct mbuf * diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 5f05dcd..291509e 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2504,7 +2504,9 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, /* Pull the tcb from the old association */ LIST_REMOVE(stcb, sctp_tcbhash); LIST_REMOVE(stcb, sctp_tcblist); - + if (stcb->asoc.in_asocid_hash) { + LIST_REMOVE(stcb, sctp_tcbasocidhash); + } /* Now insert the new_inp into the TCP connected hash */ head = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport), SCTP_BASE_INFO(hashtcpmark))]; @@ -2520,7 +2522,13 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, * only have one connection? Probably not :> so lets get rid of it * and not suck up any kernel memory in that. */ + if (stcb->asoc.in_asocid_hash) { + struct sctpasochead *lhd; + lhd = &new_inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(stcb->asoc.assoc_id, + new_inp->hashasocidmark)]; + LIST_INSERT_HEAD(lhd, stcb, sctp_tcbasocidhash); + } /* Ok. Let's restart timer. */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, new_inp, @@ -4652,7 +4660,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* pull from vtag hash */ LIST_REMOVE(stcb, sctp_asocs); - sctp_add_vtag_to_timewait(asoc->my_vtag, inp->sctp_lport, stcb->rport, SCTP_TIME_WAIT); + sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_TIME_WAIT, inp->sctp_lport, stcb->rport); /* * Now restop the timers to be sure - this is paranoia at is finest! @@ -4763,7 +4771,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from send_queue\n", ccnt); ccnt = 0; } @@ -4788,7 +4796,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from sent_queue\n", ccnt); ccnt = 0; } @@ -4813,7 +4821,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from ctrl_queue\n", ccnt); ccnt = 0; } @@ -4839,7 +4847,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from asconf_queue\n", ccnt); ccnt = 0; } @@ -4863,7 +4871,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* - if(ccnt) { + if (ccnt) { printf("Freed %d from reasm_queue\n", ccnt); ccnt = 0; } @@ -5776,7 +5784,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* ok get the v4 address and check/add */ phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf)); + (struct sctp_paramhdr *)&p4_buf, + sizeof(p4_buf)); if (plen != sizeof(struct sctp_ipv4addr_param) || phdr == NULL) { return (-5); @@ -5858,7 +5867,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, struct sctp_ipv6addr_param *p6, p6_buf; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf)); + (struct sctp_paramhdr *)&p6_buf, + sizeof(p6_buf)); if (plen != sizeof(struct sctp_ipv6addr_param) || phdr == NULL) { return (-14); @@ -5883,8 +5893,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, local_sa, stcb); atomic_add_int(&stcb->asoc.refcnt, -1); - if (stcb_tmp == NULL && (inp == stcb->sctp_ep || - inp == NULL)) { + if (stcb_tmp == NULL && + (inp == stcb->sctp_ep || inp == NULL)) { /* * we must validate the state again * here @@ -5965,7 +5975,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, return (-23); } phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&lstore, min(plen, sizeof(lstore))); + (struct sctp_paramhdr *)&lstore, + min(plen, sizeof(lstore))); if (phdr == NULL) { return (-24); } @@ -6154,6 +6165,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, break; } } + next_param: offset += SCTP_SIZE32(plen); if (offset >= limit) { @@ -6206,8 +6218,10 @@ next_param: bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + - sizeof(*hmacs) + hmacs_len; + keylen = sizeof(*p_random) + random_len + sizeof(*hmacs) + hmacs_len; + if (chunks != NULL) { + keylen += sizeof(*chunks) + num_chunks; + } new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ @@ -6343,6 +6357,8 @@ skip_vtag_check: /* Audit expires this guy */ twait_block->vtag_block[i].tv_sec_at_expire = 0; twait_block->vtag_block[i].v_tag = 0; + twait_block->vtag_block[i].lport = 0; + twait_block->vtag_block[i].rport = 0; } else if ((twait_block->vtag_block[i].v_tag == tag) && (twait_block->vtag_block[i].lport == lport) && (twait_block->vtag_block[i].rport == rport)) { diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 66c5f7b..684ed5a 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -144,6 +144,7 @@ struct sctp_tagblock { struct sctp_epinfo { + struct socket *udp_tun_socket; struct sctpasochead *sctp_asochash; u_long hashasocmark; diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 6703daf..3f26125 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -120,6 +120,7 @@ sctp_init_sysctls() #endif } + /* It returns an upper limit. No filtering is done here */ static unsigned int number_of_addresses(struct sctp_inpcb *inp) @@ -408,6 +409,8 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr; xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay; xstcb.state = SCTP_GET_STATE(&stcb->asoc); /* FIXME */ + /* 7.0 does not support this */ + xstcb.assoc_id = sctp_get_associd(stcb); xstcb.in_streams = stcb->asoc.streamincnt; xstcb.out_streams = stcb->asoc.streamoutcnt; xstcb.max_nr_retrans = stcb->asoc.overall_error_count; @@ -506,7 +509,6 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) } - #define RANGECHK(var, min, max) \ if ((var) < (min)) { (var) = (min); } \ else if ((var) > (max)) { (var) = (max); } @@ -517,10 +519,15 @@ sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS) int error; uint32_t old_sctp_udp_tunneling_port; + SCTP_INP_INFO_WLOCK(); old_sctp_udp_tunneling_port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (error == 0) { RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port), SCTPCTL_UDP_TUNNELING_PORT_MIN, SCTPCTL_UDP_TUNNELING_PORT_MAX); + if (old_sctp_udp_tunneling_port == SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) { + error = 0; + goto out; + } if (old_sctp_udp_tunneling_port) { sctp_over_udp_stop(); } @@ -530,6 +537,8 @@ sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS) } } } +out: + SCTP_INP_INFO_WUNLOCK(); return (error); } @@ -624,14 +633,15 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) static int sysctl_sctp_cleartrace(SYSCTL_HANDLER_ARGS) { + int error = 0; + memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); - return (0); + return (error); } #endif - /* * sysctl definitions */ diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 46e604f..27597ba 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -804,6 +804,10 @@ struct sctpstat { uint32_t sctps_recvexpress; /* total fast path receives all one * chunk */ uint32_t sctps_recvexpressm; /* total fast path multi-part data */ + uint32_t sctps_recvnocrc; + uint32_t sctps_recvswcrc; + uint32_t sctps_recvhwcrc; + /* output statistics: */ uint32_t sctps_sendpackets; /* total output packets */ uint32_t sctps_sendsacks; /* total output SACKs */ @@ -820,6 +824,9 @@ struct sctpstat { uint32_t sctps_sendecne;/* total output ECNE chunks */ uint32_t sctps_sendauth;/* total output AUTH chunks FIXME */ uint32_t sctps_senderrors; /* ip_output error counter */ + uint32_t sctps_sendnocrc; + uint32_t sctps_sendswcrc; + uint32_t sctps_sendhwcrc; /* PCKDROPREP statistics: */ uint32_t sctps_pdrpfmbox; /* Packet drop from middle box */ uint32_t sctps_pdrpfehos; /* P-drop from end host */ @@ -1009,6 +1016,7 @@ struct xsctp_tcb { uint16_t remote_port; /* sctpAssocEntry 4 */ struct sctp_timeval start_time; /* sctpAssocEntry 16 */ struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */ + sctp_assoc_t assoc_id; /* sctpAssocEntry 1 */ }; struct xsctp_laddr { diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index c642762..9d04f56 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -908,6 +908,7 @@ sctp_disconnect(struct socket *so) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); } } + soisdisconnecting(so); SCTP_TCB_UNLOCK(stcb); SCTP_INP_RUNLOCK(inp); return (0); @@ -980,6 +981,11 @@ sctp_shutdown(struct socket *so) struct sctp_tcb *stcb; struct sctp_association *asoc; + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SCTP_INP_RUNLOCK(inp); + return (ENOTCONN); + } socantsendmore(so); stcb = LIST_FIRST(&inp->sctp_asoc_list); @@ -3515,6 +3521,22 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (events->sctp_sender_dry_event) { sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + stcb = LIST_FIRST(&inp->sctp_asoc_list); + if (stcb) { + SCTP_TCB_LOCK(stcb); + } + if (stcb && + TAILQ_EMPTY(&stcb->asoc.send_queue) && + TAILQ_EMPTY(&stcb->asoc.sent_queue) && + (stcb->asoc.stream_queue_cnt == 0)) { + sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); + } + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } + } } else { sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index ce06853..ac13717 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include /* for sctp_deliver_data() */ #include #include @@ -53,9 +52,15 @@ __FBSDID("$FreeBSD$"); #define NUMBER_OF_MTU_SIZES 18 +#if defined(__Windows__) && !defined(SCTP_LOCAL_TRACE_BUF) +#include "eventrace_netinet.h" +#include "sctputil.tmh" /* this is the file that will be auto + * generated */ +#else #ifndef KTR_SCTP #define KTR_SCTP KTR_SUBSYS #endif +#endif void sctp_sblog(struct sockbuf *sb, @@ -2458,48 +2463,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } -#ifdef SCTP_USE_ADLER32 -static uint32_t -update_adler32(uint32_t adler, uint8_t * buf, int32_t len) -{ - uint32_t s1 = adler & 0xffff; - uint32_t s2 = (adler >> 16) & 0xffff; - int n; - - for (n = 0; n < len; n++, buf++) { - /* s1 = (s1 + buf[n]) % BASE */ - /* first we add */ - s1 = (s1 + *buf); - /* - * now if we need to, we do a mod by subtracting. It seems a - * bit faster since I really will only ever do one subtract - * at the MOST, since buf[n] is a max of 255. - */ - if (s1 >= SCTP_ADLER32_BASE) { - s1 -= SCTP_ADLER32_BASE; - } - /* s2 = (s2 + s1) % BASE */ - /* first we add */ - s2 = (s2 + s1); - /* - * again, it is more efficent (it seems) to subtract since - * the most s2 will ever be is (BASE-1 + BASE-1) in the - * worse case. This would then be (2 * BASE) - 2, which will - * still only do one subtract. On Intel this is much better - * to do this way and avoid the divide. Have not -pg'd on - * sparc. - */ - if (s2 >= SCTP_ADLER32_BASE) { - s2 -= SCTP_ADLER32_BASE; - } - } - /* Return the adler32 of the bytes buf[0..len-1] */ - return ((s2 << 16) + s1); -} - -#endif - - uint32_t sctp_calculate_len(struct mbuf *m) { @@ -2514,132 +2477,6 @@ sctp_calculate_len(struct mbuf *m) return (tlen); } -#if defined(SCTP_WITH_NO_CSUM) - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - if (pktlen == NULL) - return (0); - *pktlen = sctp_calculate_len(m); - return (0); -} - -#elif defined(SCTP_USE_INCHKSUM) - -#include - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - struct mbuf *at; - uint32_t the_sum, retsum; - - at = m; - while (at) { - tlen += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); - } - the_sum = (uint32_t) (in_cksum_skip(m, tlen, offset)); - if (pktlen != NULL) - *pktlen = (tlen - offset); - retsum = htons(the_sum); - return (the_sum); -} - -#else - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - -#ifdef SCTP_USE_ADLER32 - uint32_t base = 1L; - -#else - uint32_t base = 0xffffffff; - -#endif - struct mbuf *at; - - at = m; - /* find the correct mbuf and offset into mbuf */ - while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) { - offset -= SCTP_BUF_LEN(at); /* update remaining offset - * left */ - at = SCTP_BUF_NEXT(at); - } - while (at != NULL) { - if ((SCTP_BUF_LEN(at) - offset) > 0) { -#ifdef SCTP_USE_ADLER32 - base = update_adler32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); -#else - if ((SCTP_BUF_LEN(at) - offset) < 4) { - /* Use old method if less than 4 bytes */ - base = old_update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } else { - base = update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } -#endif - tlen += SCTP_BUF_LEN(at) - offset; - /* we only offset once into the first mbuf */ - } - if (offset) { - if (offset < (uint32_t) SCTP_BUF_LEN(at)) - offset = 0; - else - offset -= SCTP_BUF_LEN(at); - } - at = SCTP_BUF_NEXT(at); - } - if (pktlen != NULL) { - *pktlen = tlen; - } -#ifdef SCTP_USE_ADLER32 - /* Adler32 */ - base = htonl(base); -#else - /* CRC-32c */ - base = sctp_csum_finalize(base); -#endif - return (base); -} - - -#endif - void sctp_mtu_size_reset(struct sctp_inpcb *inp, struct sctp_association *asoc, uint32_t mtu) @@ -3428,7 +3265,6 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb) } #endif socantsendmore(stcb->sctp_socket); - socantrcvmore(stcb->sctp_socket); #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -3596,6 +3432,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, /* If the socket is gone we are out of here */ return; } + if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { + return; + } if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || @@ -6708,14 +6547,163 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_ * so we can do UDP tunneling. In * the mean-time, we return error */ +#include +#include +#include +#include + +static void +sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored) +{ + struct ip *iph; + struct mbuf *sp, *last; + struct udphdr *uhdr; + uint16_t port = 0, len; + int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr); + + /* + * Split out the mbuf chain. Leave the IP header in m, place the + * rest in the sp. + */ + if ((m->m_flags & M_PKTHDR) == 0) { + /* Can't handle one that is not a pkt hdr */ + goto out; + } + /* pull the src port */ + iph = mtod(m, struct ip *); + uhdr = (struct udphdr *)((caddr_t)iph + off); + + port = uhdr->uh_sport; + sp = m_split(m, off, M_DONTWAIT); + if (sp == NULL) { + /* Gak, drop packet, we can't do a split */ + goto out; + } + if (sp->m_pkthdr.len < header_size) { + /* Gak, packet can't have an SCTP header in it - to small */ + m_freem(sp); + goto out; + } + /* ok now pull up the UDP header and SCTP header together */ + sp = m_pullup(sp, header_size); + if (sp == NULL) { + /* Gak pullup failed */ + goto out; + } + /* trim out the UDP header */ + m_adj(sp, sizeof(struct udphdr)); + + /* Now reconstruct the mbuf chain */ + /* 1) find last one */ + last = m; + while (last->m_next != NULL) { + last = last->m_next; + } + last->m_next = sp; + m->m_pkthdr.len += sp->m_pkthdr.len; + last = m; + while (last != NULL) { + last = last->m_next; + } + /* Now its ready for sctp_input or sctp6_input */ + iph = mtod(m, struct ip *); + switch (iph->ip_v) { + case IPVERSION: + { + /* its IPv4 */ + len = SCTP_GET_IPV4_LENGTH(iph); + len -= sizeof(struct udphdr); + SCTP_GET_IPV4_LENGTH(iph) = len; + sctp_input_with_port(m, off, port); + break; + } +#ifdef INET6 + case IPV6_VERSION >> 4: + { + /* its IPv6 - NOT supported */ + goto out; + break; + + } +#endif + default: + { + m_freem(m); + break; + } + } + return; +out: + m_freem(m); +} void sctp_over_udp_stop(void) { - return; + struct socket *sop; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + if (SCTP_BASE_INFO(udp_tun_socket) == NULL) { + /* Nothing to do */ + return; + } + sop = SCTP_BASE_INFO(udp_tun_socket); + soclose(sop); + SCTP_BASE_INFO(udp_tun_socket) = NULL; } int sctp_over_udp_start(void) { - return (-1); + uint16_t port; + int ret; + struct sockaddr_in sin; + struct socket *sop = NULL; + struct thread *th; + struct ucred *cred; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); + if (port == 0) { + /* Must have a port set */ + return (EINVAL); + } + if (SCTP_BASE_INFO(udp_tun_socket) != NULL) { + /* Already running -- must stop first */ + return (EALREADY); + } + th = curthread; + cred = th->td_ucred; + if ((ret = socreate(PF_INET, &sop, + SOCK_DGRAM, IPPROTO_UDP, cred, th))) { + return (ret); + } + SCTP_BASE_INFO(udp_tun_socket) = sop; + /* call the special UDP hook */ + ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet); + if (ret) { + goto exit_stage_left; + } + /* Ok we have a socket, bind it to the port */ + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + ret = sobind(sop, (struct sockaddr *)&sin, th); + if (ret) { + /* Close up we cant get the port */ +exit_stage_left: + sctp_over_udp_stop(); + return (ret); + } + /* + * Ok we should now get UDP packets directly to our input routine + * sctp_recv_upd_tunneled_packet(). + */ + return (0); } diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index cc940b3..56c6729 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -94,8 +94,6 @@ sctp_timer_stop(int, struct sctp_inpcb *, struct sctp_tcb *, int sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id); -uint32_t sctp_calculate_sum(struct mbuf *, int32_t *, uint32_t); - void sctp_mtu_size_reset(struct sctp_inpcb *, struct sctp_association *, uint32_t); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index c6fc3cf..9597528 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #ifdef IPSEC @@ -75,7 +76,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) uint32_t vrf_id = 0; struct inpcb *in6p_ip; struct sctp_chunkhdr *ch; - int length, mlen, offset, iphlen; + int length, offset, iphlen; uint8_t ecn_bits; struct sctp_tcb *stcb = NULL; int pkt_len = 0; @@ -126,16 +127,28 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) /* destination port of 0 is illegal, based on RFC2960. */ if (sh->dest_port == 0) goto bad; + + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, + "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", + m->m_pkthdr.len, + if_name(m->m_pkthdr.rcvif), + m->m_pkthdr.csum_flags); + if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { + SCTP_STAT_INCR(sctps_recvhwcrc); + goto sctp_skip_csum; + } check = sh->checksum; /* save incoming checksum */ if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))) { + SCTP_STAT_INCR(sctps_recvnocrc); goto sctp_skip_csum; } sh->checksum = 0; /* prepare for calc */ - calc_check = sctp_calculate_sum(m, &mlen, iphlen); + calc_check = sctp_calculate_cksum(m, iphlen); + SCTP_STAT_INCR(sctps_recvswcrc); if (calc_check != check) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", - calc_check, check, m, mlen, iphlen); + SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p phlen:%d\n", + calc_check, check, m, iphlen); stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), sh, ch, &in6p, &net, vrf_id); if ((net) && (port)) { -- cgit v1.1