diff --git a/sys/conf/files b/sys/conf/files index c6f570827439..0073ce28dd4e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -4255,7 +4255,7 @@ netinet/sctp_asconf.c optional inet sctp | inet6 sctp netinet/sctp_auth.c optional inet sctp | inet6 sctp netinet/sctp_bsd_addr.c optional inet sctp | inet6 sctp netinet/sctp_cc_functions.c optional inet sctp | inet6 sctp -netinet/sctp_crc32.c optional inet sctp | inet6 sctp +netinet/sctp_crc32.c optional inet | inet6 netinet/sctp_indata.c optional inet sctp | inet6 sctp netinet/sctp_input.c optional inet sctp | inet6 sctp netinet/sctp_output.c optional inet sctp | inet6 sctp diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c index 9d1f54c7be37..da5df194b8b3 100644 --- a/sys/netinet/sctp_crc32.c +++ b/sys/netinet/sctp_crc32.c @@ -35,29 +35,36 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_sctp.h" + +#ifdef SCTP #include #include #include #include +#else +#include +#include +#include - +#include +#endif static uint32_t sctp_finalize_crc32c(uint32_t crc32c) { uint32_t result; - #if BYTE_ORDER == BIG_ENDIAN uint8_t byte0, byte1, byte2, byte3; - #endif + /* Complement the result */ result = ~crc32c; #if BYTE_ORDER == BIG_ENDIAN /* - * For BIG-ENDIAN.. aka Motorola byte order the result is in - * little-endian form. So we must manually swap the bytes. Then we - * can call htonl() which does nothing... + * For BIG-ENDIAN platforms the result is in little-endian form. So + * we must swap the bytes to return the result in network byte + * order. */ byte0 = result & 0x000000ff; byte1 = (result >> 8) & 0x000000ff; @@ -66,56 +73,54 @@ sctp_finalize_crc32c(uint32_t crc32c) crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); #else /* - * For INTEL platforms the result comes out in network order. No - * htonl is required or the swap above. So we optimize out both the - * htonl and the manual swap above. + * For LITTLE ENDIAN platforms the result is in already in network + * byte order. */ crc32c = result; #endif return (crc32c); } +/* + * Compute the SCTP checksum in network byte order for a given mbuf chain m + * which contains an SCTP packet starting at offset. + * Since this function is also called by ipfw, don't assume that + * it is compiled on a kernel with SCTP support. + */ 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 (offset > 0) { + KASSERT(m != NULL, ("sctp_calculate_cksum, offset > length of mbuf chain")); + if (offset < (uint32_t)m->m_len) { + break; + } + offset -= m->m_len; + m = m->m_next; } - while (at != NULL) { - if ((SCTP_BUF_LEN(at) - offset) > 0) { - base = calculate_crc32c(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } - if (offset) { - /* we only offset once into the first mbuf */ - if (offset < (uint32_t)SCTP_BUF_LEN(at)) - offset = 0; - else - offset -= SCTP_BUF_LEN(at); - } - at = SCTP_BUF_NEXT(at); + if (offset > 0) { + base = calculate_crc32c(base, + (unsigned char *)(m->m_data + offset), + (unsigned int)(m->m_len - offset)); + m = m->m_next; + } + while (m != NULL) { + base = calculate_crc32c(base, + (unsigned char *)m->m_data, + (unsigned int)m->m_len); + m = m->m_next; } base = sctp_finalize_crc32c(base); return (base); } - +#ifdef SCTP +/* + * Compute and insert the SCTP checksum in network byte order for a given + * mbuf chain m which contains an SCTP packet starting at offset. + */ void sctp_delayed_cksum(struct mbuf *m, uint32_t offset) { @@ -127,14 +132,15 @@ sctp_delayed_cksum(struct mbuf *m, uint32_t offset) offset += offsetof(struct sctphdr, checksum); if (offset + sizeof(uint32_t) > (uint32_t)(m->m_len)) { - SCTP_PRINTF("sctp_delayed_cksum(): m->len: %d, off: %d.\n", - (uint32_t)m->m_len, offset); - /* - * 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. - */ +#ifdef INVARIANTS + panic("sctp_delayed_cksum(): m->m_len: %d, offset: %u.", + m->m_len, offset); +#else + SCTP_PRINTF("sctp_delayed_cksum(): m->m_len: %d, offset: %u.\n", + m->m_len, offset); +#endif return; } *(uint32_t *)(m->m_data + offset) = checksum; } +#endif diff --git a/sys/netinet/sctp_crc32.h b/sys/netinet/sctp_crc32.h index 23d374d64e56..4bdf82650435 100644 --- a/sys/netinet/sctp_crc32.h +++ b/sys/netinet/sctp_crc32.h @@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$"); #if defined(_KERNEL) uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); +#ifdef SCTP void sctp_delayed_cksum(struct mbuf *, uint32_t offset); +#endif #endif /* _KERNEL */ #endif /* __crc32c_h__ */