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
2 changed files with 114 additions and 182 deletions
sys

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

@ -68,22 +68,17 @@ int
sctp6_input(struct mbuf **i_pak, int *offp, int proto) sctp6_input(struct mbuf **i_pak, int *offp, int proto)
{ {
struct mbuf *m; struct mbuf *m;
int iphlen;
uint32_t vrf_id = 0;
uint8_t ecn_bits;
struct ip6_hdr *ip6; struct ip6_hdr *ip6;
struct sctphdr *sh; 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; struct sctp_chunkhdr *ch;
int length, offset, iphlen; struct sctp_inpcb *inp = NULL;
uint8_t ecn_bits;
struct sctp_tcb *stcb = 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; uint32_t mflowid;
uint8_t use_mflowid; uint8_t use_mflowid;
@ -91,17 +86,26 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
uint32_t check, calc_check; uint32_t check, calc_check;
#endif #endif
int off = *offp;
uint16_t port = 0; uint16_t port = 0;
/* get the VRF and table id's */ iphlen = *offp;
if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
SCTP_RELEASE_PKT(*i_pak); SCTP_RELEASE_PKT(*i_pak);
return (-1); return (IPPROTO_DONE);
} }
m = SCTP_HEADER_TO_CHAIN(*i_pak); 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 #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); sctp_packet_log(m);
@ -114,42 +118,38 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
mflowid = 0; mflowid = 0;
use_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 *); ip6 = mtod(m, struct ip6_hdr *);
/* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
(int)(sizeof(*sh) + sizeof(*ch))); (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
if (sh == NULL) { if (sh == NULL) {
SCTP_STAT_INCR(sctps_hdrops); SCTP_STAT_INCR(sctps_hdrops);
return (IPPROTO_DONE); return (IPPROTO_DONE);
} }
ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
iphlen = off; offset -= sizeof(struct sctp_chunkhdr);
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
if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) { if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) {
/* XXX send icmp6 host/port unreach? */ /* XXX send icmp6 host/port unreach? */
goto bad; goto bad;
} }
#endif /* NFAITH defined and > 0 */ length = ntohs(ip6->ip6_plen) + iphlen;
SCTP_STAT_INCR(sctps_recvpackets); /* Validate mbuf chain length with IP payload length. */
SCTP_STAT_INCR_COUNTER64(sctps_inpackets); if (SCTP_HEADER_LEN(*i_pak) != length) {
SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n", SCTPDBG(SCTP_DEBUG_INPUT1,
iphlen, pkt_len); "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(*i_pak));
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { SCTP_STAT_INCR(sctps_hdrops);
/* No multi-cast support in SCTP */
goto bad; goto bad;
} }
/* destination port of 0 is illegal, based on RFC2960. */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
if (sh->dest_port == 0)
goto bad; goto bad;
}
SCTPDBG(SCTP_DEBUG_INPUT1,
"sctp6_input() length:%d iphlen:%d\n", length, iphlen);
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 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, m->m_pkthdr.len,
if_name(m->m_pkthdr.rcvif), if_name(m->m_pkthdr.rcvif),
m->m_pkthdr.csum_flags); m->m_pkthdr.csum_flags);
@ -160,15 +160,16 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
SCTP_STAT_INCR(sctps_recvhwcrc); SCTP_STAT_INCR(sctps_recvhwcrc);
goto sctp_skip_csum; goto sctp_skip_csum;
} }
check = sh->checksum; /* save incoming checksum */ check = sh->checksum;
sh->checksum = 0; /* prepare for calc */ sh->checksum = 0;
calc_check = sctp_calculate_cksum(m, iphlen); calc_check = sctp_calculate_cksum(m, iphlen);
sh->checksum = check;
SCTP_STAT_INCR(sctps_recvswcrc); SCTP_STAT_INCR(sctps_recvswcrc);
if (calc_check != check) { if (calc_check != check) {
SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p phlen:%d\n", 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, iphlen); calc_check, check, m, length, iphlen);
stcb = sctp_findassociation_addr(m, offset - sizeof(*ch), stcb = sctp_findassociation_addr(m, offset,
sh, ch, &in6p, &net, vrf_id); sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) { if ((net) && (port)) {
if (net->port == 0) { if (net->port == 0) {
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); 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; net->flowidset = 1;
#endif #endif
} }
/* in6p's ref-count increased && stcb locked */ if ((inp) && (stcb)) {
if ((in6p) && (stcb)) { sctp_send_packet_dropped(stcb, net, m, length, iphlen, 1);
sctp_send_packet_dropped(stcb, net, m, pkt_len, iphlen, 1); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); } else if ((inp != NULL) && (stcb == NULL)) {
} else if ((in6p != NULL) && (stcb == NULL)) {
refcount_up = 1; refcount_up = 1;
} }
SCTP_STAT_INCR(sctps_badsum); SCTP_STAT_INCR(sctps_badsum);
SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
goto bad; goto bad;
} }
sh->checksum = calc_check;
sctp_skip_csum: sctp_skip_csum:
#endif #endif
net = NULL; /* destination port of 0 is illegal, based on RFC2960. */
/* if (sh->dest_port == 0) {
* Locate pcb and tcb for datagram sctp_findassociation_addr() wants SCTP_STAT_INCR(sctps_hdrops);
* IP/SCTP/first chunk header... goto bad;
*/ }
stcb = sctp_findassociation_addr(m, offset - sizeof(*ch), stcb = sctp_findassociation_addr(m, offset,
sh, ch, &in6p, &net, vrf_id); sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) { if ((net) && (port)) {
if (net->port == 0) { if (net->port == 0) {
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr)); sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
@ -215,25 +213,10 @@ sctp_skip_csum:
net->flowidset = 1; net->flowidset = 1;
#endif #endif
} }
/* in6p's ref-count increased */ if (inp == NULL) {
if (in6p == NULL) {
struct sctp_init_chunk *init_chk, chunk_buf;
SCTP_STAT_INCR(sctps_noport); SCTP_STAT_INCR(sctps_noport);
if (ch->chunk_type == SCTP_INITIATION) { if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0)
/* goto bad;
* 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 (ch->chunk_type == SCTP_SHUTDOWN_ACK) { if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(m, sh, sctp_send_shutdown_complete2(m, sh,
use_mflowid, mflowid, use_mflowid, mflowid,
@ -257,55 +240,46 @@ sctp_skip_csum:
refcount_up = 1; refcount_up = 1;
} }
#ifdef IPSEC #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 (inp && ipsec6_in_reject(m, &inp->ip_inp.inp)) {
if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) {
/* XXX */
MODULE_GLOBAL(ipsec6stat).in_polvio++; MODULE_GLOBAL(ipsec6stat).in_polvio++;
SCTP_STAT_INCR(sctps_hdrops);
goto bad; goto bad;
} }
#endif /* IPSEC */ #endif
/*
* CONTROL chunk processing
*/
offset -= sizeof(*ch);
ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 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 */ /* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
in6p, stcb, net, ecn_bits, inp, stcb, net, ecn_bits,
use_mflowid, mflowid, use_mflowid, mflowid,
vrf_id, port); vrf_id, port);
/* inp's ref-count reduced && stcb unlocked */ if (m) {
/* XXX this stuff below gets moved to appropriate parts later... */
if (m)
sctp_m_freem(m); sctp_m_freem(m);
if ((in6p) && refcount_up) { }
if ((inp) && (refcount_up)) {
/* reduce ref-count */ /* reduce ref-count */
SCTP_INP_WLOCK(in6p); SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(in6p); SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(in6p); SCTP_INP_WUNLOCK(inp);
} }
return (IPPROTO_DONE); return (IPPROTO_DONE);
bad: bad:
if (stcb) { if (stcb) {
SCTP_TCB_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb);
} }
if ((in6p) && refcount_up) { if ((inp) && (refcount_up)) {
/* reduce ref-count */ /* reduce ref-count */
SCTP_INP_WLOCK(in6p); SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(in6p); SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(in6p); SCTP_INP_WUNLOCK(inp);
} }
if (m) if (m) {
sctp_m_freem(m); sctp_m_freem(m);
}
return (IPPROTO_DONE); return (IPPROTO_DONE);
} }