summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c132
1 files changed, 80 insertions, 52 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 007b138..f31a557 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
#ifdef INET6
+#include <netinet6/sctp6_var.h>
#endif
#include <netinet/sctp_header.h>
#include <netinet/sctp_output.h>
@@ -48,6 +49,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <sys/proc.h>
#ifndef KTR_SCTP
@@ -6769,24 +6773,15 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_
}
#endif
-/* XXX: Remove the #ifdef after tunneling over IPv6 works also on FreeBSD. */
-#ifdef INET
-/* We will need to add support
- * to bind the ports and such here
- * 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>
-#ifdef INET6
-#include <netinet6/sctp6_var.h>
-#endif
-
static void
sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
{
struct ip *iph;
+
+#ifdef INET6
+ struct ip6_hdr *ip6;
+
+#endif
struct mbuf *sp, *last;
struct udphdr *uhdr;
uint16_t port;
@@ -6836,10 +6831,10 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
- /* Not yet supported. */
- goto out;
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr));
+ sctp6_input_with_port(&m, &off, port);
break;
-
#endif
default:
goto out;
@@ -6853,19 +6848,22 @@ out:
void
sctp_over_udp_stop(void)
{
- 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;
+#ifdef INET
+ if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
+ soclose(SCTP_BASE_INFO(udp4_tun_socket));
+ SCTP_BASE_INFO(udp4_tun_socket) = NULL;
}
- sop = SCTP_BASE_INFO(udp_tun_socket);
- soclose(sop);
- SCTP_BASE_INFO(udp_tun_socket) = NULL;
+#endif
+#ifdef INET6
+ if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
+ soclose(SCTP_BASE_INFO(udp6_tun_socket));
+ SCTP_BASE_INFO(udp6_tun_socket) = NULL;
+ }
+#endif
}
int
@@ -6873,53 +6871,83 @@ sctp_over_udp_start(void)
{
uint16_t port;
int ret;
+
+#ifdef INET
struct sockaddr_in sin;
- struct socket *sop = NULL;
- struct thread *th;
- struct ucred *cred;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+
+#endif
/*
* This function assumes sysctl caller holds sctp_sysctl_info_lock()
* for writting!
*/
port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
- if (port == 0) {
+ if (ntohs(port) == 0) {
/* Must have a port set */
return (EINVAL);
}
- if (SCTP_BASE_INFO(udp_tun_socket) != NULL) {
+#ifdef INET
+ if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
+ /* Already running -- must stop first */
+ return (EALREADY);
+ }
+#endif
+#ifdef INET6
+ if (SCTP_BASE_INFO(udp6_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))) {
+#endif
+#ifdef INET
+ if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket),
+ SOCK_DGRAM, IPPROTO_UDP,
+ curthread->td_ucred, curthread))) {
+ sctp_over_udp_stop();
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;
+ /* Call the special UDP hook. */
+ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
+ sctp_recv_udp_tunneled_packet))) {
+ sctp_over_udp_stop();
+ return (ret);
}
- /* Ok we have a socket, bind it to the port */
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
+ /* Ok, we have a socket, bind it to the port. */
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_len = sizeof(struct sockaddr_in);
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:
+ if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket),
+ (struct sockaddr *)&sin, curthread))) {
sctp_over_udp_stop();
return (ret);
}
- /*
- * Ok we should now get UDP packets directly to our input routine
- * sctp_recv_upd_tunneled_packet().
- */
+#endif
+#ifdef INET6
+ if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket),
+ SOCK_DGRAM, IPPROTO_UDP,
+ curthread->td_ucred, curthread))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+ /* Call the special UDP hook. */
+ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
+ sctp_recv_udp_tunneled_packet))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+ /* Ok, we have a socket, bind it to the port. */
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket),
+ (struct sockaddr *)&sin6, curthread))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+#endif
return (0);
}
-
-#endif
OpenPOWER on IntegriCloud