diff options
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 332 |
1 files changed, 160 insertions, 172 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index ce06853..ac13717 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_output.h> #include <netinet/sctp_uio.h> #include <netinet/sctp_timer.h> -#include <netinet/sctp_crc32.h> #include <netinet/sctp_indata.h>/* for sctp_deliver_data() */ #include <netinet/sctp_auth.h> #include <netinet/sctp_asconf.h> @@ -53,9 +52,15 @@ __FBSDID("$FreeBSD$"); #define NUMBER_OF_MTU_SIZES 18 +#if defined(__Windows__) && !defined(SCTP_LOCAL_TRACE_BUF) +#include "eventrace_netinet.h" +#include "sctputil.tmh" /* this is the file that will be auto + * generated */ +#else #ifndef KTR_SCTP #define KTR_SCTP KTR_SUBSYS #endif +#endif void sctp_sblog(struct sockbuf *sb, @@ -2458,48 +2463,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } -#ifdef SCTP_USE_ADLER32 -static uint32_t -update_adler32(uint32_t adler, uint8_t * buf, int32_t len) -{ - uint32_t s1 = adler & 0xffff; - uint32_t s2 = (adler >> 16) & 0xffff; - int n; - - for (n = 0; n < len; n++, buf++) { - /* s1 = (s1 + buf[n]) % BASE */ - /* first we add */ - s1 = (s1 + *buf); - /* - * now if we need to, we do a mod by subtracting. It seems a - * bit faster since I really will only ever do one subtract - * at the MOST, since buf[n] is a max of 255. - */ - if (s1 >= SCTP_ADLER32_BASE) { - s1 -= SCTP_ADLER32_BASE; - } - /* s2 = (s2 + s1) % BASE */ - /* first we add */ - s2 = (s2 + s1); - /* - * again, it is more efficent (it seems) to subtract since - * the most s2 will ever be is (BASE-1 + BASE-1) in the - * worse case. This would then be (2 * BASE) - 2, which will - * still only do one subtract. On Intel this is much better - * to do this way and avoid the divide. Have not -pg'd on - * sparc. - */ - if (s2 >= SCTP_ADLER32_BASE) { - s2 -= SCTP_ADLER32_BASE; - } - } - /* Return the adler32 of the bytes buf[0..len-1] */ - return ((s2 << 16) + s1); -} - -#endif - - uint32_t sctp_calculate_len(struct mbuf *m) { @@ -2514,132 +2477,6 @@ sctp_calculate_len(struct mbuf *m) return (tlen); } -#if defined(SCTP_WITH_NO_CSUM) - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - if (pktlen == NULL) - return (0); - *pktlen = sctp_calculate_len(m); - return (0); -} - -#elif defined(SCTP_USE_INCHKSUM) - -#include <machine/in_cksum.h> - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - struct mbuf *at; - uint32_t the_sum, retsum; - - at = m; - while (at) { - tlen += SCTP_BUF_LEN(at); - at = SCTP_BUF_NEXT(at); - } - the_sum = (uint32_t) (in_cksum_skip(m, tlen, offset)); - if (pktlen != NULL) - *pktlen = (tlen - offset); - retsum = htons(the_sum); - return (the_sum); -} - -#else - -uint32_t -sctp_calculate_sum(struct mbuf *m, int32_t * pktlen, uint32_t offset) -{ - /* - * given a mbuf chain with a packetheader offset by 'offset' - * pointing at a sctphdr (with csum set to 0) go through the chain - * of SCTP_BUF_NEXT()'s and calculate the SCTP checksum. This also - * has a side bonus as it will calculate the total length of the - * mbuf chain. Note: if offset is greater than the total mbuf - * length, checksum=1, pktlen=0 is returned (ie. no real error code) - */ - int32_t tlen = 0; - -#ifdef SCTP_USE_ADLER32 - uint32_t base = 1L; - -#else - uint32_t base = 0xffffffff; - -#endif - struct mbuf *at; - - at = m; - /* find the correct mbuf and offset into mbuf */ - while ((at != NULL) && (offset > (uint32_t) SCTP_BUF_LEN(at))) { - offset -= SCTP_BUF_LEN(at); /* update remaining offset - * left */ - at = SCTP_BUF_NEXT(at); - } - while (at != NULL) { - if ((SCTP_BUF_LEN(at) - offset) > 0) { -#ifdef SCTP_USE_ADLER32 - base = update_adler32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); -#else - if ((SCTP_BUF_LEN(at) - offset) < 4) { - /* Use old method if less than 4 bytes */ - base = old_update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } else { - base = update_crc32(base, - (unsigned char *)(SCTP_BUF_AT(at, offset)), - (unsigned int)(SCTP_BUF_LEN(at) - offset)); - } -#endif - tlen += SCTP_BUF_LEN(at) - offset; - /* we only offset once into the first mbuf */ - } - if (offset) { - if (offset < (uint32_t) SCTP_BUF_LEN(at)) - offset = 0; - else - offset -= SCTP_BUF_LEN(at); - } - at = SCTP_BUF_NEXT(at); - } - if (pktlen != NULL) { - *pktlen = tlen; - } -#ifdef SCTP_USE_ADLER32 - /* Adler32 */ - base = htonl(base); -#else - /* CRC-32c */ - base = sctp_csum_finalize(base); -#endif - return (base); -} - - -#endif - void sctp_mtu_size_reset(struct sctp_inpcb *inp, struct sctp_association *asoc, uint32_t mtu) @@ -3428,7 +3265,6 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb) } #endif socantsendmore(stcb->sctp_socket); - socantrcvmore(stcb->sctp_socket); #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -3596,6 +3432,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, /* If the socket is gone we are out of here */ return; } + if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { + return; + } if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || @@ -6708,14 +6547,163 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_ * so we can do UDP tunneling. In * the mean-time, we return error */ +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <sys/proc.h> +#include <netinet6/sctp6_var.h> + +static void +sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored) +{ + struct ip *iph; + struct mbuf *sp, *last; + struct udphdr *uhdr; + uint16_t port = 0, len; + int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr); + + /* + * Split out the mbuf chain. Leave the IP header in m, place the + * rest in the sp. + */ + if ((m->m_flags & M_PKTHDR) == 0) { + /* Can't handle one that is not a pkt hdr */ + goto out; + } + /* pull the src port */ + iph = mtod(m, struct ip *); + uhdr = (struct udphdr *)((caddr_t)iph + off); + + port = uhdr->uh_sport; + sp = m_split(m, off, M_DONTWAIT); + if (sp == NULL) { + /* Gak, drop packet, we can't do a split */ + goto out; + } + if (sp->m_pkthdr.len < header_size) { + /* Gak, packet can't have an SCTP header in it - to small */ + m_freem(sp); + goto out; + } + /* ok now pull up the UDP header and SCTP header together */ + sp = m_pullup(sp, header_size); + if (sp == NULL) { + /* Gak pullup failed */ + goto out; + } + /* trim out the UDP header */ + m_adj(sp, sizeof(struct udphdr)); + + /* Now reconstruct the mbuf chain */ + /* 1) find last one */ + last = m; + while (last->m_next != NULL) { + last = last->m_next; + } + last->m_next = sp; + m->m_pkthdr.len += sp->m_pkthdr.len; + last = m; + while (last != NULL) { + last = last->m_next; + } + /* Now its ready for sctp_input or sctp6_input */ + iph = mtod(m, struct ip *); + switch (iph->ip_v) { + case IPVERSION: + { + /* its IPv4 */ + len = SCTP_GET_IPV4_LENGTH(iph); + len -= sizeof(struct udphdr); + SCTP_GET_IPV4_LENGTH(iph) = len; + sctp_input_with_port(m, off, port); + break; + } +#ifdef INET6 + case IPV6_VERSION >> 4: + { + /* its IPv6 - NOT supported */ + goto out; + break; + + } +#endif + default: + { + m_freem(m); + break; + } + } + return; +out: + m_freem(m); +} void sctp_over_udp_stop(void) { - return; + struct socket *sop; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + if (SCTP_BASE_INFO(udp_tun_socket) == NULL) { + /* Nothing to do */ + return; + } + sop = SCTP_BASE_INFO(udp_tun_socket); + soclose(sop); + SCTP_BASE_INFO(udp_tun_socket) = NULL; } int sctp_over_udp_start(void) { - return (-1); + uint16_t port; + int ret; + struct sockaddr_in sin; + struct socket *sop = NULL; + struct thread *th; + struct ucred *cred; + + /* + * This function assumes sysctl caller holds sctp_sysctl_info_lock() + * for writting! + */ + port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); + if (port == 0) { + /* Must have a port set */ + return (EINVAL); + } + if (SCTP_BASE_INFO(udp_tun_socket) != NULL) { + /* Already running -- must stop first */ + return (EALREADY); + } + th = curthread; + cred = th->td_ucred; + if ((ret = socreate(PF_INET, &sop, + SOCK_DGRAM, IPPROTO_UDP, cred, th))) { + return (ret); + } + SCTP_BASE_INFO(udp_tun_socket) = sop; + /* call the special UDP hook */ + ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet); + if (ret) { + goto exit_stage_left; + } + /* Ok we have a socket, bind it to the port */ + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + ret = sobind(sop, (struct sockaddr *)&sin, th); + if (ret) { + /* Close up we cant get the port */ +exit_stage_left: + sctp_over_udp_stop(); + return (ret); + } + /* + * Ok we should now get UDP packets directly to our input routine + * sctp_recv_upd_tunneled_packet(). + */ + return (0); } |