in_gif.c revision 291993
1116743Ssam/*-
2186904Ssam * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3116743Ssam * All rights reserved.
4116743Ssam *
5116743Ssam * Redistribution and use in source and binary forms, with or without
6116743Ssam * modification, are permitted provided that the following conditions
7116743Ssam * are met:
8116743Ssam * 1. Redistributions of source code must retain the above copyright
9116743Ssam *    notice, this list of conditions and the following disclaimer.
10116743Ssam * 2. Redistributions in binary form must reproduce the above copyright
11116743Ssam *    notice, this list of conditions and the following disclaimer in the
12116743Ssam *    documentation and/or other materials provided with the distribution.
13116743Ssam * 3. Neither the name of the project nor the names of its contributors
14116743Ssam *    may be used to endorse or promote products derived from this software
15116743Ssam *    without specific prior written permission.
16116743Ssam *
17116743Ssam * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18116743Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19116743Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20116743Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21116743Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22116743Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23116743Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24116743Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25116743Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26116743Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27116743Ssam * SUCH DAMAGE.
28116743Ssam *
29116743Ssam *	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $
30116743Ssam */
31116743Ssam
32116743Ssam#include <sys/cdefs.h>
33116743Ssam__FBSDID("$FreeBSD: head/sys/netinet/in_gif.c 291993 2015-12-08 10:50:03Z melifaro $");
34116743Ssam
35116743Ssam#include "opt_inet.h"
36116743Ssam#include "opt_inet6.h"
37116743Ssam
38227327Sadrian#include <sys/param.h>
39227327Sadrian#include <sys/lock.h>
40227327Sadrian#include <sys/rmlock.h>
41227327Sadrian#include <sys/systm.h>
42227327Sadrian#include <sys/socket.h>
43227327Sadrian#include <sys/sockio.h>
44227327Sadrian#include <sys/mbuf.h>
45227327Sadrian#include <sys/errno.h>
46227327Sadrian#include <sys/kernel.h>
47227327Sadrian#include <sys/sysctl.h>
48116743Ssam#include <sys/protosw.h>
49116743Ssam#include <sys/malloc.h>
50116743Ssam
51116743Ssam#include <net/if.h>
52155492Ssam#include <net/if_var.h>
53138570Ssam#include <net/route.h>
54116743Ssam#include <net/vnet.h>
55116743Ssam
56116743Ssam#include <netinet/in.h>
57138570Ssam#include <netinet/in_systm.h>
58116743Ssam#include <netinet/ip.h>
59138570Ssam#include <netinet/ip_var.h>
60116743Ssam#include <netinet/in_var.h>
61116743Ssam#include <netinet/ip_encap.h>
62116743Ssam#include <netinet/ip_ecn.h>
63116743Ssam#include <netinet/in_fib.h>
64116743Ssam
65116743Ssam#ifdef INET6
66116743Ssam#include <netinet/ip6.h>
67116743Ssam#endif
68116743Ssam
69116743Ssam#include <net/if_gif.h>
70116743Ssam
71116743Ssamstatic int in_gif_input(struct mbuf **, int *, int);
72116743Ssam
73116743Ssamextern  struct domain inetdomain;
74116743Ssamstatic struct protosw in_gif_protosw = {
75116743Ssam	.pr_type =		SOCK_RAW,
76116743Ssam	.pr_domain =		&inetdomain,
77116743Ssam	.pr_protocol =		0/* IPPROTO_IPV[46] */,
78116743Ssam	.pr_flags =		PR_ATOMIC|PR_ADDR,
79116743Ssam	.pr_input =		in_gif_input,
80127779Ssam	.pr_output =		rip_output,
81127779Ssam	.pr_ctloutput =		rip_ctloutput,
82170530Ssam	.pr_usrreqs =		&rip_usrreqs
83170530Ssam};
84116743Ssam
85116743Ssam#define GIF_TTL		30
86116743Ssamstatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL;
87116743Ssam#define	V_ip_gif_ttl		VNET(ip_gif_ttl)
88116743SsamSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW,
89116743Ssam	&VNET_NAME(ip_gif_ttl), 0, "");
90138570Ssam
91116743Ssamint
92218689Sadrianin_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
93119147Ssam{
94127779Ssam	GIF_RLOCK_TRACKER;
95138570Ssam	struct gif_softc *sc = ifp->if_softc;
96138570Ssam	struct ip *ip;
97119147Ssam	int len;
98138570Ssam
99138570Ssam	/* prepend new IP header */
100161187Ssam	len = sizeof(struct ip);
101138570Ssam#ifndef __NO_STRICT_ALIGNMENT
102116743Ssam	if (proto == IPPROTO_ETHERIP)
103116743Ssam		len += ETHERIP_ALIGN;
104116743Ssam#endif
105116743Ssam	M_PREPEND(m, len, M_NOWAIT);
106116743Ssam	if (m == NULL)
107116743Ssam		return (ENOBUFS);
108116743Ssam#ifndef __NO_STRICT_ALIGNMENT
109138570Ssam	if (proto == IPPROTO_ETHERIP) {
110138570Ssam		len = mtod(m, vm_offset_t) & 3;
111138570Ssam		KASSERT(len == 0 || len == ETHERIP_ALIGN,
112138570Ssam		    ("in_gif_output: unexpected misalignment"));
113159894Ssam		m->m_data += len;
114159894Ssam		m->m_len -= ETHERIP_ALIGN;
115160992Ssam	}
116170530Ssam#endif
117170530Ssam	ip = mtod(m, struct ip *);
118170530Ssam	GIF_RLOCK(sc);
119170530Ssam	if (sc->gif_family != AF_INET) {
120170530Ssam		m_freem(m);
121170530Ssam		GIF_RUNLOCK(sc);
122186904Ssam		return (ENETDOWN);
123186904Ssam	}
124186904Ssam	bcopy(sc->gif_iphdr, ip, sizeof(struct ip));
125186904Ssam	GIF_RUNLOCK(sc);
126186904Ssam
127186904Ssam	ip->ip_p = proto;
128188195Ssam	/* version will be set in ip_output() */
129188195Ssam	ip->ip_ttl = V_ip_gif_ttl;
130188555Ssam	ip->ip_len = htons(m->m_pkthdr.len);
131211299Sadrian	ip->ip_tos = ecn;
132217684Sadrian
133218378Sadrian	return (ip_output(m, NULL, NULL, 0, NULL, NULL));
134221965Sadrian}
135221965Sadrian
136221965Sadrianstatic int
137221965Sadrianin_gif_input(struct mbuf **mp, int *offp, int proto)
138221965Sadrian{
139218689Sadrian	struct mbuf *m = *mp;
140218924Sadrian	struct gif_softc *sc;
141221965Sadrian	struct ifnet *gifp;
142220772Sadrian	struct ip *ip;
143220782Sadrian	uint8_t ecn;
144221965Sadrian
145221965Sadrian	sc = encap_getarg(m);
146221965Sadrian	if (sc == NULL) {
147226798Sadrian		m_freem(m);
148226798Sadrian		KMOD_IPSTAT_INC(ips_nogif);
149226798Sadrian		return (IPPROTO_DONE);
150226798Sadrian	}
151226798Sadrian	gifp = GIF2IFP(sc);
152226798Sadrian	if ((gifp->if_flags & IFF_UP) != 0) {
153226798Sadrian		ip = mtod(m, struct ip *);
154226798Sadrian		ecn = ip->ip_tos;
155226798Sadrian		m_adj(m, *offp);
156226798Sadrian		gif_input(m, gifp, proto, ecn);
157116743Ssam	} else {
158116743Ssam		m_freem(m);
159116743Ssam		KMOD_IPSTAT_INC(ips_nogif);
160188557Ssam	}
161116743Ssam	return (IPPROTO_DONE);
162123044Ssam}
163138570Ssam
164138570Ssam/*
165138570Ssam * we know that we are in IFF_UP, outer address available, and outer family
166138570Ssam * matched the physical addr family.  see gif_encapcheck().
167138570Ssam */
168138570Ssamint
169138570Ssamin_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
170138570Ssam{
171138570Ssam	const struct ip *ip;
172138570Ssam	struct gif_softc *sc;
173123044Ssam	int ret;
174123044Ssam
175123044Ssam	/* sanity check done in caller */
176224245Sadrian	sc = (struct gif_softc *)arg;
177123044Ssam	GIF_RLOCK_ASSERT(sc);
178119783Ssam
179119783Ssam	/* check for address match */
180119783Ssam	ip = mtod(m, const struct ip *);
181119783Ssam	if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr)
182154140Ssam		return (0);
183119783Ssam	ret = 32;
184119783Ssam	if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) {
185123928Ssam		if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0)
186154140Ssam			return (0);
187154140Ssam	} else
188170530Ssam		ret += 32;
189119783Ssam
190119783Ssam	/* ingress filters on outer source */
191119783Ssam	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) {
192119783Ssam		struct nhop4_basic nh4;
193154140Ssam		struct in_addr dst;
194154140Ssam
195119783Ssam		dst = ip->ip_src;
196170530Ssam
197170530Ssam		if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0)
198170530Ssam			return (0);
199170530Ssam
200170530Ssam		if (nh4.nh_ifp != m->m_pkthdr.rcvif)
201119783Ssam			return (0);
202170530Ssam	}
203170530Ssam	return (ret);
204170530Ssam}
205119783Ssam
206119783Ssamint
207154140Ssamin_gif_attach(struct gif_softc *sc)
208119783Ssam{
209119783Ssam
210123928Ssam	KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL"));
211123928Ssam	sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck,
212170530Ssam	    &in_gif_protosw, sc);
213119783Ssam	if (sc->gif_ecookie == NULL)
214119783Ssam		return (EEXIST);
215119783Ssam	return (0);
216119783Ssam}
217154140Ssam