1139823Simp/*-
2103026Ssobomax * Copyright (c) 1998 The NetBSD Foundation, Inc.
3284066Sae * Copyright (c) 2014 Andrey V. Elsukov <ae@FreeBSD.org>
4103026Ssobomax * All rights reserved.
5103026Ssobomax *
6103026Ssobomax * This code is derived from software contributed to The NetBSD Foundation
7103026Ssobomax * by Heiko W.Rupp <hwr@pilhuhn.de>
8103026Ssobomax *
9148613Sbz * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
10148613Sbz *
11103026Ssobomax * Redistribution and use in source and binary forms, with or without
12103026Ssobomax * modification, are permitted provided that the following conditions
13103026Ssobomax * are met:
14103026Ssobomax * 1. Redistributions of source code must retain the above copyright
15103026Ssobomax *    notice, this list of conditions and the following disclaimer.
16103026Ssobomax * 2. Redistributions in binary form must reproduce the above copyright
17103026Ssobomax *    notice, this list of conditions and the following disclaimer in the
18103026Ssobomax *    documentation and/or other materials provided with the distribution.
19103026Ssobomax *
20103026Ssobomax * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21103026Ssobomax * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22103026Ssobomax * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23103026Ssobomax * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24103026Ssobomax * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25103026Ssobomax * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26103026Ssobomax * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27103026Ssobomax * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28103026Ssobomax * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29103026Ssobomax * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30103026Ssobomax * POSSIBILITY OF SUCH DAMAGE.
31284066Sae *
32284066Sae * $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $
33103026Ssobomax */
34103026Ssobomax
35172467Ssilby#include <sys/cdefs.h>
36172467Ssilby__FBSDID("$FreeBSD$");
37172467Ssilby
38103026Ssobomax#include "opt_inet.h"
39148613Sbz#include "opt_inet6.h"
40103026Ssobomax
41103026Ssobomax#include <sys/param.h>
42103026Ssobomax#include <sys/systm.h>
43103026Ssobomax#include <sys/mbuf.h>
44103026Ssobomax#include <sys/socket.h>
45103026Ssobomax#include <sys/socketvar.h>
46103026Ssobomax#include <sys/protosw.h>
47103026Ssobomax#include <sys/errno.h>
48103026Ssobomax#include <sys/time.h>
49103026Ssobomax#include <sys/kernel.h>
50284066Sae#include <sys/lock.h>
51284066Sae#include <sys/rmlock.h>
52284066Sae#include <sys/sysctl.h>
53103026Ssobomax#include <net/ethernet.h>
54103026Ssobomax#include <net/if.h>
55284066Sae#include <net/if_var.h>
56284066Sae#include <net/vnet.h>
57103026Ssobomax#include <net/raw_cb.h>
58103026Ssobomax
59103026Ssobomax#include <netinet/in.h>
60103026Ssobomax#include <netinet/in_var.h>
61103026Ssobomax#include <netinet/in_systm.h>
62103026Ssobomax#include <netinet/ip.h>
63284066Sae#include <netinet/ip_encap.h>
64103026Ssobomax#include <netinet/ip_var.h>
65103026Ssobomax#include <machine/in_cksum.h>
66103026Ssobomax
67284066Sae#ifdef INET6
68284066Sae#include <netinet/ip6.h>
69103026Ssobomax#endif
70103026Ssobomax
71103026Ssobomax/* Needs IP headers. */
72103026Ssobomax#include <net/if_gre.h>
73103026Ssobomax#include <machine/stdarg.h>
74103026Ssobomax
75284066Saeextern struct domain inetdomain;
76284066Saestatic void gre_input10(struct mbuf *, int);
77284066Saestatic const struct protosw in_gre_protosw = {
78284066Sae	.pr_type =		SOCK_RAW,
79284066Sae	.pr_domain =		&inetdomain,
80284066Sae	.pr_protocol =		IPPROTO_GRE,
81284066Sae	.pr_flags =		PR_ATOMIC|PR_ADDR,
82284066Sae	.pr_input =		gre_input10,
83284066Sae	.pr_output =		(pr_output_t *)rip_output,
84284066Sae	.pr_ctlinput =		rip_ctlinput,
85284066Sae	.pr_ctloutput =		rip_ctloutput,
86284066Sae	.pr_usrreqs =		&rip_usrreqs
87284066Sae};
88103026Ssobomax
89284066Sae#define	GRE_TTL			30
90284066SaeVNET_DEFINE(int, ip_gre_ttl) = GRE_TTL;
91284066Sae#define	V_ip_gre_ttl		VNET(ip_gre_ttl)
92284066SaeSYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_RW,
93284066Sae	&VNET_NAME(ip_gre_ttl), 0, "");
94284066Sae
95284066Saestatic void
96284066Saegre_input10(struct mbuf *m, int off)
97103026Ssobomax{
98158645Sglebius	int proto;
99103026Ssobomax
100103026Ssobomax	proto = (mtod(m, struct ip *))->ip_p;
101284066Sae	gre_input(&m, &off, proto);
102103026Ssobomax}
103103026Ssobomax
104284066Saestatic int
105284066Saein_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
106103026Ssobomax{
107284066Sae	GRE_RLOCK_TRACKER;
108103026Ssobomax	struct gre_softc *sc;
109284066Sae	struct ip *ip;
110103026Ssobomax
111284066Sae	sc = (struct gre_softc *)arg;
112284066Sae	if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
113284066Sae		return (0);
114103026Ssobomax
115284066Sae	M_ASSERTPKTHDR(m);
116284066Sae	/*
117284066Sae	 * We expect that payload contains at least IPv4
118284066Sae	 * or IPv6 packet.
119284066Sae	 */
120284066Sae	if (m->m_pkthdr.len < sizeof(struct greip) + sizeof(struct ip))
121284066Sae		return (0);
122123992Ssobomax
123284066Sae	GRE_RLOCK(sc);
124284066Sae	if (sc->gre_family == 0)
125284066Sae		goto bad;
126103026Ssobomax
127284066Sae	KASSERT(sc->gre_family == AF_INET,
128284066Sae	    ("wrong gre_family: %d", sc->gre_family));
129103026Ssobomax
130284066Sae	ip = mtod(m, struct ip *);
131284066Sae	if (sc->gre_oip.ip_src.s_addr != ip->ip_dst.s_addr ||
132284066Sae	    sc->gre_oip.ip_dst.s_addr != ip->ip_src.s_addr)
133284066Sae		goto bad;
134103026Ssobomax
135284066Sae	GRE_RUNLOCK(sc);
136284066Sae	return (32 * 2);
137284066Saebad:
138284066Sae	GRE_RUNLOCK(sc);
139284066Sae	return (0);
140103026Ssobomax}
141103026Ssobomax
142284066Saeint
143284066Saein_gre_output(struct mbuf *m, int af, int hlen)
144103026Ssobomax{
145284066Sae	struct greip *gi;
146103026Ssobomax
147284066Sae	gi = mtod(m, struct greip *);
148284066Sae	switch (af) {
149284066Sae	case AF_INET:
150284066Sae		/*
151284066Sae		 * gre_transmit() has used M_PREPEND() that doesn't guarantee
152284066Sae		 * m_data is contiguous more than hlen bytes. Use m_copydata()
153284066Sae		 * here to avoid m_pullup().
154284066Sae		 */
155284066Sae		m_copydata(m, hlen + offsetof(struct ip, ip_tos),
156284066Sae		    sizeof(u_char), &gi->gi_ip.ip_tos);
157284066Sae		m_copydata(m, hlen + offsetof(struct ip, ip_id),
158284066Sae		    sizeof(u_short), (caddr_t)&gi->gi_ip.ip_id);
159284066Sae		break;
160284066Sae#ifdef INET6
161284066Sae	case AF_INET6:
162284066Sae		gi->gi_ip.ip_tos = 0; /* XXX */
163284066Sae		gi->gi_ip.ip_id = ip_newid();
164284066Sae		break;
165284066Sae#endif
166103026Ssobomax	}
167284066Sae	gi->gi_ip.ip_ttl = V_ip_gre_ttl;
168284066Sae	gi->gi_ip.ip_len = htons(m->m_pkthdr.len);
169284066Sae	return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL));
170103026Ssobomax}
171103026Ssobomax
172284066Saeint
173284066Saein_gre_attach(struct gre_softc *sc)
174103026Ssobomax{
175103026Ssobomax
176284066Sae	KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL"));
177284066Sae	sc->gre_ecookie = encap_attach_func(AF_INET, IPPROTO_GRE,
178284066Sae	    in_gre_encapcheck, &in_gre_protosw, sc);
179284066Sae	if (sc->gre_ecookie == NULL)
180284066Sae		return (EEXIST);
181284066Sae	return (0);
182103026Ssobomax}
183