Unify sctp_input() and sctp6_input().

MFC after: 3 days
This commit is contained in:
Michael Tuexen 2012-06-25 19:13:43 +00:00
parent f2618bb4d1
commit 6dc5aabcb7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=237569
2 changed files with 114 additions and 182 deletions

View File

@ -5885,12 +5885,12 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
uint8_t ecn_bits;
struct ip *ip;
struct sctphdr *sh;
struct sctp_inpcb *inp = NULL;
struct sctp_nets *net;
struct sctp_tcb *stcb = NULL;
struct sctp_chunkhdr *ch;
struct sctp_inpcb *inp = NULL;
struct sctp_tcb *stcb = NULL;
struct sctp_nets *net = NULL;
int refcount_up = 0;
int length, mlen, offset;
int length, offset;
uint32_t mflowid;
uint8_t use_mflowid;
@ -5899,19 +5899,12 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
#endif
iphlen = off;
if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) {
SCTP_RELEASE_PKT(i_pak);
return;
}
mlen = SCTP_HEADER_LEN(i_pak);
iphlen = off;
m = SCTP_HEADER_TO_CHAIN(i_pak);
net = NULL;
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
#ifdef SCTP_MBUF_LOGGING
/* Log in any input mbufs */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
@ -5925,8 +5918,9 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
}
#endif
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
sctp_packet_log(m);
}
#endif
if (m->m_flags & M_FLOWID) {
mflowid = m->m_pkthdr.flowid;
@ -5935,17 +5929,11 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
mflowid = 0;
use_mflowid = 0;
}
/*
* Must take out the iphlen, since mlen expects this (only effect lb
* case)
*/
mlen -= iphlen;
/*
* Get IP, SCTP, and first chunk header together in first mbuf.
*/
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
/* Get IP, SCTP, and first chunk header together in the first mbuf. */
ip = mtod(m, struct ip *);
offset = iphlen + sizeof(*sh) + sizeof(*ch);
offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
if (SCTP_BUF_LEN(m) < offset) {
if ((m = m_pullup(m, offset)) == 0) {
SCTP_STAT_INCR(sctps_hdrops);
@ -5953,28 +5941,26 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
}
ip = mtod(m, struct ip *);
}
/* validate mbuf chain length with IP payload length */
if (mlen < (SCTP_GET_IPV4_LENGTH(ip) - iphlen)) {
sh = (struct sctphdr *)((caddr_t)ip + iphlen);
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
offset -= sizeof(struct sctp_chunkhdr);
length = ip->ip_len + iphlen;
/* Validate mbuf chain length with IP payload length. */
if (SCTP_HEADER_LEN(i_pak) != length) {
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(i_pak));
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,
"sctp_input() length:%d iphlen:%d\n", mlen, iphlen);
/* SCTP does not allow broadcasts or multicasts */
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
goto bad;
}
if (SCTP_IS_IT_BROADCAST(ip->ip_dst, m)) {
/*
* We only look at broadcast if its a front state, All
* others we will not have a tcb for anyway.
*/
goto bad;
}
/* validate SCTP checksum */
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp_input() length:%d iphlen:%d\n", length, iphlen);
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
m->m_pkthdr.len,
@ -5985,21 +5971,18 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
#else
if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
SCTP_STAT_INCR(sctps_recvhwcrc);
goto sctp_skip_csum_4;
goto sctp_skip_csum;
}
check = sh->checksum; /* save incoming checksum */
sh->checksum = 0; /* prepare for calc */
check = sh->checksum;
sh->checksum = 0;
calc_check = sctp_calculate_cksum(m, iphlen);
sh->checksum = check;
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);
stcb = sctp_findassociation_addr(m,
offset - sizeof(*ch),
sh, ch, &inp, &net,
vrf_id);
calc_check, check, m, length, iphlen);
stcb = sctp_findassociation_addr(m, offset,
sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
@ -6013,7 +5996,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
#endif
}
if ((inp) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, mlen + iphlen, iphlen, 1);
sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
} else if ((inp != NULL) && (stcb == NULL)) {
refcount_up = 1;
@ -6022,18 +6005,14 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
goto bad;
}
sctp_skip_csum_4:
sctp_skip_csum:
#endif
/* destination port of 0 is illegal, based on RFC2960. */
if (sh->dest_port == 0) {
SCTP_STAT_INCR(sctps_hdrops);
goto bad;
}
/*
* Locate pcb and tcb for datagram sctp_findassociation_addr() wants
* IP/SCTP/first chunk header...
*/
stcb = sctp_findassociation_addr(m, offset - sizeof(*ch),
stcb = sctp_findassociation_addr(m, offset,
sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
@ -6047,27 +6026,10 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
net->flowidset = 1;
#endif
}
/* inp's ref-count increased && stcb locked */
if (inp == NULL) {
struct sctp_init_chunk *init_chk, chunk_buf;
SCTP_STAT_INCR(sctps_noport);
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0)
goto bad;
SCTPDBG(SCTP_DEBUG_INPUT1,
"Sending a ABORT from packet entry!\n");
if (ch->chunk_type == SCTP_INITIATION) {
/*
* we do a trick here to get the INIT tag, dig in
* and get the tag from the INIT and put it in the
* common header.
*/
init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
iphlen + sizeof(*sh), sizeof(*init_chk),
(uint8_t *) & chunk_buf);
if (init_chk != NULL)
sh->v_tag = init_chk->init.initiate_tag;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(m, sh,
use_mflowid, mflowid,
@ -6091,7 +6053,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
refcount_up = 1;
}
#ifdef IPSEC
/*
/*-
* I very much doubt any of the IPSEC stuff will work but I have no
* idea, so I will leave it in place.
*/
@ -6100,28 +6062,22 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
SCTP_STAT_INCR(sctps_hdrops);
goto bad;
}
#endif /* IPSEC */
/*
* common chunk processing
*/
length = ip->ip_len + iphlen;
offset -= sizeof(struct sctp_chunkhdr);
#endif
ecn_bits = ip->ip_tos;
/* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
inp, stcb, net, ecn_bits,
use_mflowid, mflowid,
vrf_id, port);
/* inp's ref-count reduced && stcb unlocked */
if (m) {
sctp_m_freem(m);
}
if ((inp) && (refcount_up)) {
/* reduce ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
}
return;
bad:
@ -6130,7 +6086,9 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
}
if ((inp) && (refcount_up)) {
/* reduce ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
}
if (m) {
sctp_m_freem(m);

View File

@ -68,22 +68,17 @@ int
sctp6_input(struct mbuf **i_pak, int *offp, int proto)
{
struct mbuf *m;
int iphlen;
uint32_t vrf_id = 0;
uint8_t ecn_bits;
struct ip6_hdr *ip6;
struct sctphdr *sh;
struct sctp_inpcb *in6p = NULL;
struct sctp_nets *net;
int refcount_up = 0;
uint32_t vrf_id = 0;
#ifdef IPSEC
struct inpcb *in6p_ip;
#endif
struct sctp_chunkhdr *ch;
int length, offset, iphlen;
uint8_t ecn_bits;
struct sctp_inpcb *inp = NULL;
struct sctp_tcb *stcb = NULL;
int pkt_len = 0;
struct sctp_nets *net = NULL;
int refcount_up = 0;
int length, offset;
uint32_t mflowid;
uint8_t use_mflowid;
@ -91,17 +86,26 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
uint32_t check, calc_check;
#endif
int off = *offp;
uint16_t port = 0;
/* get the VRF and table id's */
iphlen = *offp;
if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
SCTP_RELEASE_PKT(*i_pak);
return (-1);
return (IPPROTO_DONE);
}
m = SCTP_HEADER_TO_CHAIN(*i_pak);
pkt_len = SCTP_HEADER_LEN(*i_pak);
#ifdef SCTP_MBUF_LOGGING
/* Log in any input mbufs */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
struct mbuf *mat;
for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
if (SCTP_BUF_IS_EXTENDED(mat)) {
sctp_log_mb(mat, SCTP_MBUF_INPUT);
}
}
}
#endif
#ifdef SCTP_PACKET_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
sctp_packet_log(m);
@ -114,42 +118,38 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
mflowid = 0;
use_mflowid = 0;
}
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
/* Get IP, SCTP, and first chunk header together in the first mbuf. */
ip6 = mtod(m, struct ip6_hdr *);
/* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
IP6_EXTHDR_GET(sh, struct sctphdr *, m, off,
(int)(sizeof(*sh) + sizeof(*ch)));
offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
(int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
if (sh == NULL) {
SCTP_STAT_INCR(sctps_hdrops);
return (IPPROTO_DONE);
}
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
iphlen = off;
offset = iphlen + sizeof(*sh) + sizeof(*ch);
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp6_input() length:%d iphlen:%d\n", pkt_len, iphlen);
#if defined(NFAITH) && NFAITH > 0
offset -= sizeof(struct sctp_chunkhdr);
if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) {
/* XXX send icmp6 host/port unreach? */
goto bad;
}
#endif /* NFAITH defined and > 0 */
SCTP_STAT_INCR(sctps_recvpackets);
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n",
iphlen, pkt_len);
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
/* No multi-cast support in SCTP */
length = ntohs(ip6->ip6_plen) + iphlen;
/* Validate mbuf chain length with IP payload length. */
if (SCTP_HEADER_LEN(*i_pak) != length) {
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(*i_pak));
SCTP_STAT_INCR(sctps_hdrops);
goto bad;
}
/* destination port of 0 is illegal, based on RFC2960. */
if (sh->dest_port == 0)
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
goto bad;
}
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp6_input() length:%d iphlen:%d\n", length, iphlen);
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
"sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
"sctp6_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);
@ -160,15 +160,16 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
SCTP_STAT_INCR(sctps_recvhwcrc);
goto sctp_skip_csum;
}
check = sh->checksum; /* save incoming checksum */
sh->checksum = 0; /* prepare for calc */
check = sh->checksum;
sh->checksum = 0;
calc_check = sctp_calculate_cksum(m, iphlen);
sh->checksum = check;
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 phlen:%d\n",
calc_check, check, m, iphlen);
stcb = sctp_findassociation_addr(m, offset - sizeof(*ch),
sh, ch, &in6p, &net, vrf_id);
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, length, iphlen);
stcb = sctp_findassociation_addr(m, offset,
sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
@ -181,28 +182,25 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
net->flowidset = 1;
#endif
}
/* in6p's ref-count increased && stcb locked */
if ((in6p) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, pkt_len, iphlen, 1);
sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
} else if ((in6p != NULL) && (stcb == NULL)) {
if ((inp) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
} else if ((inp != NULL) && (stcb == NULL)) {
refcount_up = 1;
}
SCTP_STAT_INCR(sctps_badsum);
SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
goto bad;
}
sh->checksum = calc_check;
sctp_skip_csum:
#endif
net = NULL;
/*
* Locate pcb and tcb for datagram sctp_findassociation_addr() wants
* IP/SCTP/first chunk header...
*/
stcb = sctp_findassociation_addr(m, offset - sizeof(*ch),
sh, ch, &in6p, &net, vrf_id);
/* destination port of 0 is illegal, based on RFC2960. */
if (sh->dest_port == 0) {
SCTP_STAT_INCR(sctps_hdrops);
goto bad;
}
stcb = sctp_findassociation_addr(m, offset,
sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
@ -215,25 +213,10 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
net->flowidset = 1;
#endif
}
/* in6p's ref-count increased */
if (in6p == NULL) {
struct sctp_init_chunk *init_chk, chunk_buf;
if (inp == NULL) {
SCTP_STAT_INCR(sctps_noport);
if (ch->chunk_type == SCTP_INITIATION) {
/*
* we do a trick here to get the INIT tag, dig in
* and get the tag from the INIT and put it in the
* common header.
*/
init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
iphlen + sizeof(*sh), sizeof(*init_chk),
(uint8_t *) & chunk_buf);
if (init_chk)
sh->v_tag = init_chk->init.initiate_tag;
else
sh->v_tag = 0;
}
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0)
goto bad;
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(m, sh,
use_mflowid, mflowid,
@ -257,55 +240,46 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
refcount_up = 1;
}
#ifdef IPSEC
/*
* Check AH/ESP integrity.
/*-
* I very much doubt any of the IPSEC stuff will work but I have no
* idea, so I will leave it in place.
*/
in6p_ip = (struct inpcb *)in6p;
if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) {
/* XXX */
if (inp && ipsec6_in_reject(m, &inp->ip_inp.inp)) {
MODULE_GLOBAL(ipsec6stat).in_polvio++;
SCTP_STAT_INCR(sctps_hdrops);
goto bad;
}
#endif /* IPSEC */
#endif
/*
* CONTROL chunk processing
*/
offset -= sizeof(*ch);
ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
/* Length now holds the total packet length payload + iphlen */
length = ntohs(ip6->ip6_plen) + iphlen;
/* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
in6p, stcb, net, ecn_bits,
inp, stcb, net, ecn_bits,
use_mflowid, mflowid,
vrf_id, port);
/* inp's ref-count reduced && stcb unlocked */
/* XXX this stuff below gets moved to appropriate parts later... */
if (m)
if (m) {
sctp_m_freem(m);
if ((in6p) && refcount_up) {
}
if ((inp) && (refcount_up)) {
/* reduce ref-count */
SCTP_INP_WLOCK(in6p);
SCTP_INP_DECR_REF(in6p);
SCTP_INP_WUNLOCK(in6p);
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
}
return (IPPROTO_DONE);
bad:
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
}
if ((in6p) && refcount_up) {
if ((inp) && (refcount_up)) {
/* reduce ref-count */
SCTP_INP_WLOCK(in6p);
SCTP_INP_DECR_REF(in6p);
SCTP_INP_WUNLOCK(in6p);
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
}
if (m)
if (m) {
sctp_m_freem(m);
}
return (IPPROTO_DONE);
}