mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-26 11:47:31 +00:00
When adding support for sending SCTP packets containing an ABORT chunk
to ipfw in https://svnweb.freebsd.org/changeset/base/326233, a dependency on the SCTP stack was added to ipfw by accident. This was noted by Kevel Bowling in https://reviews.freebsd.org/D13594 where also a solution was suggested. This patch is based on Kevin's suggestion, but implements the required SCTP checksum computation without any dependency on other SCTP sources. While there, do some cleanups and improve comments. Thanks to Kevin Kevin Browling for reporting the issue and suggesting a fix.
This commit is contained in:
parent
81b5c8ff8d
commit
cd90150413
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327200
@ -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
|
||||
|
@ -35,29 +35,36 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_sctp.h"
|
||||
|
||||
#ifdef SCTP
|
||||
#include <netinet/sctp_os.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include <netinet/sctp_crc32.h>
|
||||
#include <netinet/sctp_pcb.h>
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
|
||||
#include <netinet/sctp_crc32.h>
|
||||
#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
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user