summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2012-06-25 19:13:43 +0000
committertuexen <tuexen@FreeBSD.org>2012-06-25 19:13:43 +0000
commit108138a99779b4a03621cfa0cb0f187b1ac0b90d (patch)
tree6ad830e7ccd58d134be97a58bb70b26ac1581436 /sys/netinet6
parent85590af6fa7e8cead37c00e128451fe7558cf305 (diff)
downloadFreeBSD-src-108138a99779b4a03621cfa0cb0f187b1ac0b90d.zip
FreeBSD-src-108138a99779b4a03621cfa0cb0f187b1ac0b90d.tar.gz
Unify sctp_input() and sctp6_input().
MFC after: 3 days
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/sctp6_usrreq.c184
1 files changed, 79 insertions, 105 deletions
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index a765945..82b3faf 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -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 @@ sctp_skip_csum:
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 @@ sctp_skip_csum:
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);
}
OpenPOWER on IntegriCloud