summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2009-02-03 11:04:03 +0000
committerrrs <rrs@FreeBSD.org>2009-02-03 11:04:03 +0000
commit520c389cb4f290b2acdcff4ed123d33cca39e0d8 (patch)
treead3c3bea4fec4c5a81ac06bbcfcfc640edc88661
parent2688c691800f6933c6b9eeeb46cf522db6f1af5c (diff)
downloadFreeBSD-src-520c389cb4f290b2acdcff4ed123d33cca39e0d8.zip
FreeBSD-src-520c389cb4f290b2acdcff4ed123d33cca39e0d8.tar.gz
- 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
-rw-r--r--sys/netinet/sctp_auth.c6
-rw-r--r--sys/netinet/sctp_constants.h68
-rw-r--r--sys/netinet/sctp_crc32.c215
-rw-r--r--sys/netinet/sctp_crc32.h12
-rw-r--r--sys/netinet/sctp_input.c46
-rw-r--r--sys/netinet/sctp_os_bsd.h5
-rw-r--r--sys/netinet/sctp_output.c806
-rw-r--r--sys/netinet/sctp_pcb.c44
-rw-r--r--sys/netinet/sctp_pcb.h1
-rw-r--r--sys/netinet/sctp_sysctl.c16
-rw-r--r--sys/netinet/sctp_uio.h8
-rw-r--r--sys/netinet/sctp_usrreq.c22
-rw-r--r--sys/netinet/sctputil.c332
-rw-r--r--sys/netinet/sctputil.h2
-rw-r--r--sys/netinet6/sctp6_usrreq.c21
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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+#include <netinet/sctp.h>
#include <netinet/sctp_os.h>
#include <netinet/sctp_crc32.h>
+#include <netinet/sctp_pcb.h>
-#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 <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_timer.h>
+#include <netinet/sctp_crc32.h>
#include <netinet/udp.h>
@@ -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 <netinet/sctp_indata.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_input.h>
+#include <netinet/sctp_crc32.h>
#include <netinet/udp.h>
#include <machine/in_cksum.h>
@@ -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 <netinet/sctp_output.h>
#include <netinet/sctp_uio.h>
#include <netinet/sctp_timer.h>
-#include <netinet/sctp_crc32.h>
#include <netinet/sctp_indata.h>/* for sctp_deliver_data() */
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
@@ -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 <machine/in_cksum.h>
-
-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 <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <sys/proc.h>
+#include <netinet6/sctp6_var.h>
+
+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 <netinet/sctp_input.h>
#include <netinet/sctp_output.h>
#include <netinet/sctp_bsd_addr.h>
+#include <netinet/sctp_crc32.h>
#include <netinet/udp.h>
#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)) {
OpenPOWER on IntegriCloud