xref: /freebsd/sys/netinet/ip_gre.c (revision f325335cafc940e54a1ea56560de6f25340c81b7)
1c398230bSWarner Losh /*-
28e96e13eSMaxim Sobolev  * Copyright (c) 1998 The NetBSD Foundation, Inc.
3*f325335cSAndrey V. Elsukov  * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org>
48e96e13eSMaxim Sobolev  * All rights reserved.
58e96e13eSMaxim Sobolev  *
68e96e13eSMaxim Sobolev  * This code is derived from software contributed to The NetBSD Foundation
78e96e13eSMaxim Sobolev  * by Heiko W.Rupp <hwr@pilhuhn.de>
88e96e13eSMaxim Sobolev  *
99e669156SBjoern A. Zeeb  * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
109e669156SBjoern A. Zeeb  *
118e96e13eSMaxim Sobolev  * Redistribution and use in source and binary forms, with or without
128e96e13eSMaxim Sobolev  * modification, are permitted provided that the following conditions
138e96e13eSMaxim Sobolev  * are met:
148e96e13eSMaxim Sobolev  * 1. Redistributions of source code must retain the above copyright
158e96e13eSMaxim Sobolev  *    notice, this list of conditions and the following disclaimer.
168e96e13eSMaxim Sobolev  * 2. Redistributions in binary form must reproduce the above copyright
178e96e13eSMaxim Sobolev  *    notice, this list of conditions and the following disclaimer in the
188e96e13eSMaxim Sobolev  *    documentation and/or other materials provided with the distribution.
198e96e13eSMaxim Sobolev  *
208e96e13eSMaxim Sobolev  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
218e96e13eSMaxim Sobolev  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
228e96e13eSMaxim Sobolev  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
238e96e13eSMaxim Sobolev  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
248e96e13eSMaxim Sobolev  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258e96e13eSMaxim Sobolev  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268e96e13eSMaxim Sobolev  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278e96e13eSMaxim Sobolev  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288e96e13eSMaxim Sobolev  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298e96e13eSMaxim Sobolev  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308e96e13eSMaxim Sobolev  * POSSIBILITY OF SUCH DAMAGE.
31*f325335cSAndrey V. Elsukov  *
32*f325335cSAndrey V. Elsukov  * $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $
338e96e13eSMaxim Sobolev  */
348e96e13eSMaxim Sobolev 
354b421e2dSMike Silbersack #include <sys/cdefs.h>
364b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
374b421e2dSMike Silbersack 
388e96e13eSMaxim Sobolev #include "opt_inet.h"
399e669156SBjoern A. Zeeb #include "opt_inet6.h"
408e96e13eSMaxim Sobolev 
418e96e13eSMaxim Sobolev #include <sys/param.h>
428e96e13eSMaxim Sobolev #include <sys/systm.h>
438e96e13eSMaxim Sobolev #include <sys/mbuf.h>
448e96e13eSMaxim Sobolev #include <sys/socket.h>
458e96e13eSMaxim Sobolev #include <sys/socketvar.h>
468e96e13eSMaxim Sobolev #include <sys/protosw.h>
478e96e13eSMaxim Sobolev #include <sys/errno.h>
488e96e13eSMaxim Sobolev #include <sys/time.h>
498e96e13eSMaxim Sobolev #include <sys/kernel.h>
50*f325335cSAndrey V. Elsukov #include <sys/lock.h>
51*f325335cSAndrey V. Elsukov #include <sys/rmlock.h>
52*f325335cSAndrey V. Elsukov #include <sys/sysctl.h>
538e96e13eSMaxim Sobolev #include <net/ethernet.h>
548e96e13eSMaxim Sobolev #include <net/if.h>
5576039bc8SGleb Smirnoff #include <net/if_var.h>
56*f325335cSAndrey V. Elsukov #include <net/vnet.h>
578e96e13eSMaxim Sobolev 
588e96e13eSMaxim Sobolev #include <netinet/in.h>
598e96e13eSMaxim Sobolev #include <netinet/in_var.h>
608e96e13eSMaxim Sobolev #include <netinet/ip.h>
61*f325335cSAndrey V. Elsukov #include <netinet/ip_encap.h>
628e96e13eSMaxim Sobolev #include <netinet/ip_var.h>
63*f325335cSAndrey V. Elsukov 
64*f325335cSAndrey V. Elsukov #ifdef INET6
65*f325335cSAndrey V. Elsukov #include <netinet/ip6.h>
668e96e13eSMaxim Sobolev #endif
678e96e13eSMaxim Sobolev 
688e96e13eSMaxim Sobolev #include <net/if_gre.h>
698e96e13eSMaxim Sobolev 
70*f325335cSAndrey V. Elsukov extern struct domain inetdomain;
71*f325335cSAndrey V. Elsukov extern int gre_input(struct mbuf **, int *, int);
728e96e13eSMaxim Sobolev 
73*f325335cSAndrey V. Elsukov int in_gre_attach(struct gre_softc *);
74*f325335cSAndrey V. Elsukov int in_gre_output(struct mbuf *, int, int);
758e96e13eSMaxim Sobolev 
76*f325335cSAndrey V. Elsukov static const struct protosw in_gre_protosw = {
77*f325335cSAndrey V. Elsukov 	.pr_type =		SOCK_RAW,
78*f325335cSAndrey V. Elsukov 	.pr_domain =		&inetdomain,
79*f325335cSAndrey V. Elsukov 	.pr_protocol =		IPPROTO_GRE,
80*f325335cSAndrey V. Elsukov 	.pr_flags =		PR_ATOMIC|PR_ADDR,
81*f325335cSAndrey V. Elsukov 	.pr_input =		gre_input,
82*f325335cSAndrey V. Elsukov 	.pr_output =		rip_output,
83*f325335cSAndrey V. Elsukov 	.pr_ctlinput =		rip_ctlinput,
84*f325335cSAndrey V. Elsukov 	.pr_ctloutput =		rip_ctloutput,
85*f325335cSAndrey V. Elsukov 	.pr_usrreqs =		&rip_usrreqs
86*f325335cSAndrey V. Elsukov };
878e96e13eSMaxim Sobolev 
88*f325335cSAndrey V. Elsukov #define	GRE_TTL			30
89*f325335cSAndrey V. Elsukov VNET_DEFINE(int, ip_gre_ttl) = GRE_TTL;
90*f325335cSAndrey V. Elsukov #define	V_ip_gre_ttl		VNET(ip_gre_ttl)
91*f325335cSAndrey V. Elsukov SYSCTL_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_VNET | CTLFLAG_RW,
92*f325335cSAndrey V. Elsukov 	&VNET_NAME(ip_gre_ttl), 0, "");
938e96e13eSMaxim Sobolev 
94*f325335cSAndrey V. Elsukov static int
95*f325335cSAndrey V. Elsukov in_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
968e96e13eSMaxim Sobolev {
97*f325335cSAndrey V. Elsukov 	GRE_RLOCK_TRACKER;
988e96e13eSMaxim Sobolev 	struct gre_softc *sc;
99*f325335cSAndrey V. Elsukov 	struct ip *ip;
1008e96e13eSMaxim Sobolev 
101*f325335cSAndrey V. Elsukov 	sc = (struct gre_softc *)arg;
102*f325335cSAndrey V. Elsukov 	if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
103*f325335cSAndrey V. Elsukov 		return (0);
104*f325335cSAndrey V. Elsukov 
105*f325335cSAndrey V. Elsukov 	M_ASSERTPKTHDR(m);
106*f325335cSAndrey V. Elsukov 	/*
107*f325335cSAndrey V. Elsukov 	 * We expect that payload contains at least IPv4
108*f325335cSAndrey V. Elsukov 	 * or IPv6 packet.
109*f325335cSAndrey V. Elsukov 	 */
110*f325335cSAndrey V. Elsukov 	if (m->m_pkthdr.len < sizeof(struct greip) + sizeof(struct ip))
111*f325335cSAndrey V. Elsukov 		return (0);
112*f325335cSAndrey V. Elsukov 
113*f325335cSAndrey V. Elsukov 	GRE_RLOCK(sc);
114*f325335cSAndrey V. Elsukov 	if (sc->gre_family == 0)
115*f325335cSAndrey V. Elsukov 		goto bad;
116*f325335cSAndrey V. Elsukov 
117*f325335cSAndrey V. Elsukov 	KASSERT(sc->gre_family == AF_INET,
118*f325335cSAndrey V. Elsukov 	    ("wrong gre_family: %d", sc->gre_family));
119*f325335cSAndrey V. Elsukov 
120*f325335cSAndrey V. Elsukov 	ip = mtod(m, struct ip *);
121*f325335cSAndrey V. Elsukov 	if (sc->gre_oip.ip_src.s_addr != ip->ip_dst.s_addr ||
122*f325335cSAndrey V. Elsukov 	    sc->gre_oip.ip_dst.s_addr != ip->ip_src.s_addr)
123*f325335cSAndrey V. Elsukov 		goto bad;
124*f325335cSAndrey V. Elsukov 
125*f325335cSAndrey V. Elsukov 	GRE_RUNLOCK(sc);
126*f325335cSAndrey V. Elsukov 	return (32 * 2);
127*f325335cSAndrey V. Elsukov bad:
128*f325335cSAndrey V. Elsukov 	GRE_RUNLOCK(sc);
129*f325335cSAndrey V. Elsukov 	return (0);
1308e96e13eSMaxim Sobolev }
1318e96e13eSMaxim Sobolev 
132*f325335cSAndrey V. Elsukov int
133*f325335cSAndrey V. Elsukov in_gre_output(struct mbuf *m, int af, int hlen)
134*f325335cSAndrey V. Elsukov {
135*f325335cSAndrey V. Elsukov 	struct greip *gi;
13673d7ddbcSMaxim Sobolev 
137*f325335cSAndrey V. Elsukov 	gi = mtod(m, struct greip *);
138*f325335cSAndrey V. Elsukov 	switch (af) {
139*f325335cSAndrey V. Elsukov 	case AF_INET:
140*f325335cSAndrey V. Elsukov 		/*
141*f325335cSAndrey V. Elsukov 		 * gre_transmit() has used M_PREPEND() that doesn't guarantee
142*f325335cSAndrey V. Elsukov 		 * m_data is contiguous more than hlen bytes. Use m_copydata()
143*f325335cSAndrey V. Elsukov 		 * here to avoid m_pullup().
144*f325335cSAndrey V. Elsukov 		 */
145*f325335cSAndrey V. Elsukov 		m_copydata(m, hlen + offsetof(struct ip, ip_tos),
146*f325335cSAndrey V. Elsukov 		    sizeof(u_char), &gi->gi_ip.ip_tos);
147*f325335cSAndrey V. Elsukov 		m_copydata(m, hlen + offsetof(struct ip, ip_id),
148*f325335cSAndrey V. Elsukov 		    sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id);
1498e96e13eSMaxim Sobolev 		break;
1509e669156SBjoern A. Zeeb #ifdef INET6
151*f325335cSAndrey V. Elsukov 	case AF_INET6:
152*f325335cSAndrey V. Elsukov 		gi->gi_ip.ip_tos = 0; /* XXX */
153*f325335cSAndrey V. Elsukov 		gi->gi_ip.ip_id = ip_newid();
1549e669156SBjoern A. Zeeb 		break;
1559e669156SBjoern A. Zeeb #endif
1568e96e13eSMaxim Sobolev 	}
157*f325335cSAndrey V. Elsukov 	gi->gi_ip.ip_ttl = V_ip_gre_ttl;
158*f325335cSAndrey V. Elsukov 	gi->gi_ip.ip_len = htons(m->m_pkthdr.len);
159*f325335cSAndrey V. Elsukov 	return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL));
1608e96e13eSMaxim Sobolev }
1618e96e13eSMaxim Sobolev 
1628f5a8818SKevin Lo int
163*f325335cSAndrey V. Elsukov in_gre_attach(struct gre_softc *sc)
1648e96e13eSMaxim Sobolev {
1658e96e13eSMaxim Sobolev 
166*f325335cSAndrey V. Elsukov 	KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL"));
167*f325335cSAndrey V. Elsukov 	sc->gre_ecookie = encap_attach_func(AF_INET, IPPROTO_GRE,
168*f325335cSAndrey V. Elsukov 	    in_gre_encapcheck, &in_gre_protosw, sc);
169*f325335cSAndrey V. Elsukov 	if (sc->gre_ecookie == NULL)
170*f325335cSAndrey V. Elsukov 		return (EEXIST);
171*f325335cSAndrey V. Elsukov 	return (0);
1728e96e13eSMaxim Sobolev }
173