summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2012-07-02 16:44:09 +0000
committertuexen <tuexen@FreeBSD.org>2012-07-02 16:44:09 +0000
commit26a057bce7069299f5055f592e9331e48318f5df (patch)
tree9862b5b4ce6e437e2ef19dfba1e222b3ba5b992f /sys/netinet/sctp_input.c
parent985a80869fd4002336eded27d9a668fdc2658af4 (diff)
downloadFreeBSD-src-26a057bce7069299f5055f592e9331e48318f5df.zip
FreeBSD-src-26a057bce7069299f5055f592e9331e48318f5df.tar.gz
Move common code parts to sctp_common_input_processing().
MFC after: 3 days
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c331
1 files changed, 168 insertions, 163 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index e321fa8..c3b15b6 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -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);
}
OpenPOWER on IntegriCloud