Move common code parts to sctp_common_input_processing().
MFC after: 3 days
This commit is contained in:
parent
985a80869f
commit
26a057bce7
@ -5590,26 +5590,141 @@ void
|
||||
sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int length,
|
||||
struct sockaddr *src, struct sockaddr *dst,
|
||||
struct sctphdr *sh, struct sctp_chunkhdr *ch,
|
||||
struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net, uint8_t ecn_bits,
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
uint8_t compute_crc,
|
||||
#endif
|
||||
uint8_t ecn_bits,
|
||||
uint8_t use_mflowid, uint32_t mflowid,
|
||||
uint32_t vrf_id, uint16_t port)
|
||||
{
|
||||
/*
|
||||
* Control chunk processing
|
||||
*/
|
||||
uint32_t high_tsn;
|
||||
int fwd_tsn_seen = 0, data_processed = 0;
|
||||
struct mbuf *m = *mm;
|
||||
int un_sent;
|
||||
int cnt_ctrl_ready = 0;
|
||||
struct sctp_inpcb *inp, *inp_decr = NULL;
|
||||
struct sctp_tcb *stcb = NULL;
|
||||
struct sctp_nets *net;
|
||||
|
||||
SCTP_STAT_INCR(sctps_recvdatagrams);
|
||||
#ifdef SCTP_AUDITING_ENABLED
|
||||
sctp_audit_log(0xE0, 1);
|
||||
sctp_auditing(0, inp, stcb, net);
|
||||
#endif
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
if (compute_crc != 0) {
|
||||
uint32_t check, calc_check;
|
||||
|
||||
check = sh->checksum;
|
||||
sh->checksum = 0;
|
||||
calc_check = sctp_calculate_cksum(m, iphlen);
|
||||
sh->checksum = 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",
|
||||
calc_check, check, m, length, iphlen);
|
||||
stcb = sctp_findassociation_addr(m, offset, src, dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net != NULL) && (port != 0)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
if ((inp != NULL) && (stcb != NULL)) {
|
||||
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)) {
|
||||
inp_decr = inp;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_badsum);
|
||||
SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Destination port of 0 is illegal, based on RFC4960. */
|
||||
if (sh->dest_port == 0) {
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto out;
|
||||
}
|
||||
stcb = sctp_findassociation_addr(m, offset, src, dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net != NULL) && (port != 0)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
if (inp == NULL) {
|
||||
SCTP_STAT_INCR(sctps_noport);
|
||||
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) {
|
||||
goto out;
|
||||
}
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
|
||||
sctp_send_shutdown_complete2(src, dst, sh,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
goto out;
|
||||
}
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
|
||||
goto out;
|
||||
}
|
||||
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) {
|
||||
if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
|
||||
((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
|
||||
(ch->chunk_type != SCTP_INIT))) {
|
||||
sctp_send_abort(m, iphlen, src, dst,
|
||||
sh, 0, NULL,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
} else if (stcb == NULL) {
|
||||
inp_decr = inp;
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
if (inp != NULL) {
|
||||
switch (dst->sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (ipsec4_in_reject(m, &inp->ip_inp.inp)) {
|
||||
MODULE_GLOBAL(ipsec4stat).in_polvio++;
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (ipsec6_in_reject(m, &inp->ip_inp.inp)) {
|
||||
MODULE_GLOBAL(ipsec6stat).in_polvio++;
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "Ok, Common input processing called, m:%p iphlen:%d offset:%d length:%d stcb:%p\n",
|
||||
m, iphlen, offset, length, stcb);
|
||||
if (stcb) {
|
||||
@ -5628,10 +5743,11 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
* NOT respond to any packet.. its OOTB.
|
||||
*/
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
stcb = NULL;
|
||||
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
goto out_now;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (IS_SCTP_CONTROL(ch)) {
|
||||
@ -5671,21 +5787,19 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks)) {
|
||||
/* "silently" ignore */
|
||||
SCTP_STAT_INCR(sctps_recvauthmissing);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
goto out_now;
|
||||
goto out;
|
||||
}
|
||||
if (stcb == NULL) {
|
||||
/* out of the blue DATA chunk */
|
||||
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
goto out_now;
|
||||
goto out;
|
||||
}
|
||||
if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) {
|
||||
/* v_tag mismatch! */
|
||||
SCTP_STAT_INCR(sctps_badvtag);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
goto out_now;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5695,7 +5809,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
* packet while processing control, or we're done with this
|
||||
* packet (done or skip rest of data), so we drop it...
|
||||
*/
|
||||
goto out_now;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* DATA chunk processing
|
||||
@ -5749,8 +5863,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
sctp_handle_ootb(m, iphlen, offset, src, dst, sh, inp,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
goto out_now;
|
||||
goto out;
|
||||
/* sa_ignore NOTREACHED */
|
||||
break;
|
||||
case SCTP_STATE_EMPTY: /* should not happen */
|
||||
@ -5758,8 +5871,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
case SCTP_STATE_SHUTDOWN_RECEIVED: /* This is a peer error */
|
||||
case SCTP_STATE_SHUTDOWN_ACK_SENT:
|
||||
default:
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
goto out_now;
|
||||
goto out;
|
||||
/* sa_ignore NOTREACHED */
|
||||
break;
|
||||
case SCTP_STATE_OPEN:
|
||||
@ -5777,7 +5889,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt
|
||||
* The association aborted, NO UNLOCK needed since
|
||||
* the association is destroyed.
|
||||
*/
|
||||
goto out_now;
|
||||
stcb = NULL;
|
||||
goto out;
|
||||
}
|
||||
data_processed = 1;
|
||||
/*
|
||||
@ -5834,10 +5947,20 @@ trigger_send:
|
||||
sctp_audit_log(0xE0, 3);
|
||||
sctp_auditing(2, inp, stcb, net);
|
||||
#endif
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
out_now:
|
||||
out:
|
||||
if (stcb != NULL) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
if (inp_decr != NULL) {
|
||||
/* reduce ref-count */
|
||||
SCTP_INP_WLOCK(inp_decr);
|
||||
SCTP_INP_DECR_REF(inp_decr);
|
||||
SCTP_INP_WUNLOCK(inp_decr);
|
||||
}
|
||||
#ifdef INVARIANTS
|
||||
sctp_validate_no_locks(inp);
|
||||
if (inp != NULL) {
|
||||
sctp_validate_no_locks(inp);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -5867,18 +5990,14 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
|
||||
struct ip *ip;
|
||||
struct sctphdr *sh;
|
||||
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, offset;
|
||||
uint32_t mflowid;
|
||||
uint8_t use_mflowid;
|
||||
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
uint32_t check, calc_check;
|
||||
uint8_t compute_crc;
|
||||
|
||||
#endif
|
||||
uint32_t mflowid;
|
||||
uint8_t use_mflowid;
|
||||
|
||||
iphlen = off;
|
||||
if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) {
|
||||
@ -5903,6 +6022,11 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
|
||||
sctp_packet_log(m);
|
||||
}
|
||||
#endif
|
||||
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_flags & M_FLOWID) {
|
||||
mflowid = m->m_pkthdr.flowid;
|
||||
use_mflowid = 1;
|
||||
@ -5936,161 +6060,42 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port)
|
||||
dst.sin_addr = ip->ip_dst;
|
||||
length = ip->ip_len + iphlen;
|
||||
/* Validate mbuf chain length with IP payload length. */
|
||||
if (SCTP_HEADER_LEN(i_pak) != length) {
|
||||
if (SCTP_HEADER_LEN(m) != length) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1,
|
||||
"sctp_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(i_pak));
|
||||
"sctp_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
/* SCTP does not allow broadcasts or multicasts */
|
||||
if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
if (SCTP_IS_IT_BROADCAST(dst.sin_addr, m)) {
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
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,
|
||||
if_name(m->m_pkthdr.rcvif),
|
||||
m->m_pkthdr.csum_flags);
|
||||
ecn_bits = ip->ip_tos;
|
||||
#if defined(SCTP_WITH_NO_CSUM)
|
||||
SCTP_STAT_INCR(sctps_recvnocrc);
|
||||
#else
|
||||
if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
|
||||
SCTP_STAT_INCR(sctps_recvhwcrc);
|
||||
goto sctp_skip_csum;
|
||||
}
|
||||
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, length, iphlen);
|
||||
stcb = sctp_findassociation_addr(m, offset,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net) && (port)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
stcb = sctp_findassociation_addr(m, offset,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net) && (port)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
if (inp == NULL) {
|
||||
SCTP_STAT_INCR(sctps_noport);
|
||||
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0)
|
||||
goto bad;
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
|
||||
sctp_send_shutdown_complete2((struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
goto bad;
|
||||
}
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
|
||||
goto bad;
|
||||
}
|
||||
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) {
|
||||
if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
|
||||
((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
|
||||
(ch->chunk_type != SCTP_INIT))) {
|
||||
sctp_send_abort(m, iphlen,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, 0, NULL,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
}
|
||||
}
|
||||
goto bad;
|
||||
} else if (stcb == NULL) {
|
||||
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.
|
||||
*/
|
||||
if (inp && ipsec4_in_reject(m, &inp->ip_inp.inp)) {
|
||||
MODULE_GLOBAL(ipsec4stat).in_polvio++;
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto bad;
|
||||
compute_crc = 0;
|
||||
} else {
|
||||
SCTP_STAT_INCR(sctps_recvswcrc);
|
||||
compute_crc = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ecn_bits = ip->ip_tos;
|
||||
/* sa_ignore NO_NULL_CHK */
|
||||
sctp_common_input_processing(&m, iphlen, offset, length,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, inp, stcb, net, ecn_bits,
|
||||
sh, ch,
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
compute_crc,
|
||||
#endif
|
||||
ecn_bits,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
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:
|
||||
if (stcb) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
if ((inp) && (refcount_up)) {
|
||||
/* reduce ref-count */
|
||||
SCTP_INP_WLOCK(inp);
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
out:
|
||||
if (m) {
|
||||
sctp_m_freem(m);
|
||||
}
|
||||
|
@ -41,8 +41,10 @@ void
|
||||
sctp_common_input_processing(struct mbuf **, int, int, int,
|
||||
struct sockaddr *, struct sockaddr *,
|
||||
struct sctphdr *, struct sctp_chunkhdr *,
|
||||
struct sctp_inpcb *, struct sctp_tcb *,
|
||||
struct sctp_nets *, uint8_t,
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
uint8_t,
|
||||
#endif
|
||||
uint8_t,
|
||||
uint8_t, uint32_t,
|
||||
uint32_t, uint16_t);
|
||||
|
||||
|
@ -69,24 +69,20 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
|
||||
{
|
||||
struct mbuf *m;
|
||||
int iphlen;
|
||||
uint32_t vrf_id = 0;
|
||||
uint32_t vrf_id;
|
||||
uint8_t ecn_bits;
|
||||
struct sockaddr_in6 src, dst;
|
||||
struct ip6_hdr *ip6;
|
||||
struct sctphdr *sh;
|
||||
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, offset;
|
||||
uint32_t mflowid;
|
||||
uint8_t use_mflowid;
|
||||
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
uint32_t check, calc_check;
|
||||
uint8_t compute_crc;
|
||||
|
||||
#endif
|
||||
uint32_t mflowid;
|
||||
uint8_t use_mflowid;
|
||||
uint16_t port = 0;
|
||||
|
||||
iphlen = *offp;
|
||||
@ -112,6 +108,11 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
|
||||
sctp_packet_log(m);
|
||||
}
|
||||
#endif
|
||||
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
|
||||
"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);
|
||||
if (m->m_flags & M_FLOWID) {
|
||||
mflowid = m->m_pkthdr.flowid;
|
||||
use_mflowid = 1;
|
||||
@ -122,8 +123,8 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
|
||||
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 *);
|
||||
offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
|
||||
(int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
|
||||
if (sh == NULL) {
|
||||
@ -138,7 +139,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
|
||||
src.sin6_port = sh->src_port;
|
||||
src.sin6_addr = ip6->ip6_src;
|
||||
if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
memset(&dst, 0, sizeof(struct sockaddr_in6));
|
||||
dst.sin6_family = AF_INET6;
|
||||
@ -146,165 +147,46 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
|
||||
dst.sin6_port = sh->dest_port;
|
||||
dst.sin6_addr = ip6->ip6_dst;
|
||||
if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
if (faithprefix_p != NULL && (*faithprefix_p) (&dst.sin6_addr)) {
|
||||
/* XXX send icmp6 host/port unreach? */
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
length = ntohs(ip6->ip6_plen) + iphlen;
|
||||
/* Validate mbuf chain length with IP payload length. */
|
||||
if (SCTP_HEADER_LEN(*i_pak) != length) {
|
||||
if (SCTP_HEADER_LEN(m) != length) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1,
|
||||
"sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(*i_pak));
|
||||
"sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1,
|
||||
"sctp6_input() length:%d iphlen:%d\n", length, iphlen);
|
||||
SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
|
||||
"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);
|
||||
ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
|
||||
#if defined(SCTP_WITH_NO_CSUM)
|
||||
SCTP_STAT_INCR(sctps_recvnocrc);
|
||||
#else
|
||||
if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
|
||||
SCTP_STAT_INCR(sctps_recvhwcrc);
|
||||
goto sctp_skip_csum;
|
||||
}
|
||||
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, length, iphlen);
|
||||
stcb = sctp_findassociation_addr(m, offset,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net) && (port)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
stcb = sctp_findassociation_addr(m, offset,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, &inp, &net, vrf_id);
|
||||
if ((net) && (port)) {
|
||||
if (net->port == 0) {
|
||||
sctp_pathmtu_adjustment(stcb, net->mtu - sizeof(struct udphdr));
|
||||
}
|
||||
net->port = port;
|
||||
}
|
||||
if ((net != NULL) && (use_mflowid != 0)) {
|
||||
net->flowid = mflowid;
|
||||
#ifdef INVARIANTS
|
||||
net->flowidset = 1;
|
||||
#endif
|
||||
}
|
||||
if (inp == NULL) {
|
||||
SCTP_STAT_INCR(sctps_noport);
|
||||
if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0)
|
||||
goto bad;
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
|
||||
sctp_send_shutdown_complete2((struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
goto bad;
|
||||
}
|
||||
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
|
||||
goto bad;
|
||||
}
|
||||
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) {
|
||||
if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
|
||||
((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
|
||||
(ch->chunk_type != SCTP_INIT))) {
|
||||
sctp_send_abort(m, iphlen,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, 0, NULL,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
}
|
||||
}
|
||||
goto bad;
|
||||
} else if (stcb == NULL) {
|
||||
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.
|
||||
*/
|
||||
if (inp && ipsec6_in_reject(m, &inp->ip_inp.inp)) {
|
||||
MODULE_GLOBAL(ipsec6stat).in_polvio++;
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
goto bad;
|
||||
compute_crc = 0;
|
||||
} else {
|
||||
SCTP_STAT_INCR(sctps_recvswcrc);
|
||||
compute_crc = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
|
||||
/* sa_ignore NO_NULL_CHK */
|
||||
sctp_common_input_processing(&m, iphlen, offset, length,
|
||||
(struct sockaddr *)&src,
|
||||
(struct sockaddr *)&dst,
|
||||
sh, ch, inp, stcb, net, ecn_bits,
|
||||
sh, ch,
|
||||
#if !defined(SCTP_WITH_NO_CSUM)
|
||||
compute_crc,
|
||||
#endif
|
||||
ecn_bits,
|
||||
use_mflowid, mflowid,
|
||||
vrf_id, port);
|
||||
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 (IPPROTO_DONE);
|
||||
bad:
|
||||
if (stcb) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
if ((inp) && (refcount_up)) {
|
||||
/* reduce ref-count */
|
||||
SCTP_INP_WLOCK(inp);
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
out:
|
||||
if (m) {
|
||||
sctp_m_freem(m);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user