if_gre.c revision 249925
1227825Stheraven/*	$NetBSD: if_gre.c,v 1.49 2003/12/11 00:22:29 itojun Exp $ */
2227825Stheraven/*	 $FreeBSD: head/sys/net/if_gre.c 249925 2013-04-26 12:50:32Z glebius $ */
3227825Stheraven
4227825Stheraven/*-
5227825Stheraven * Copyright (c) 1998 The NetBSD Foundation, Inc.
6227825Stheraven * All rights reserved.
7227825Stheraven *
8227825Stheraven * This code is derived from software contributed to The NetBSD Foundation
9227825Stheraven * by Heiko W.Rupp <hwr@pilhuhn.de>
10227825Stheraven *
11227825Stheraven * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
12227825Stheraven *
13227825Stheraven * Redistribution and use in source and binary forms, with or without
14227825Stheraven * modification, are permitted provided that the following conditions
15227825Stheraven * are met:
16227825Stheraven * 1. Redistributions of source code must retain the above copyright
17227825Stheraven *    notice, this list of conditions and the following disclaimer.
18227825Stheraven * 2. Redistributions in binary form must reproduce the above copyright
19227825Stheraven *    notice, this list of conditions and the following disclaimer in the
20227825Stheraven *    documentation and/or other materials provided with the distribution.
21227825Stheraven *
22227825Stheraven * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23227825Stheraven * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24227825Stheraven * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25227825Stheraven * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26227825Stheraven * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27227825Stheraven * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28227825Stheraven * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29227825Stheraven * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30227825Stheraven * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31227825Stheraven * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32227825Stheraven * POSSIBILITY OF SUCH DAMAGE.
33227825Stheraven */
34227825Stheraven
35227825Stheraven/*
36227825Stheraven * Encapsulate L3 protocols into IP
37227825Stheraven * See RFC 2784 (successor of RFC 1701 and 1702) for more details.
38227825Stheraven * If_gre is compatible with Cisco GRE tunnels, so you can
39227825Stheraven * have a NetBSD box as the other end of a tunnel interface of a Cisco
40227825Stheraven * router. See gre(4) for more details.
41227825Stheraven * Also supported:  IP in IP encaps (proto 55) as of RFC 2004
42227825Stheraven */
43227825Stheraven
44227825Stheraven#include "opt_atalk.h"
45227825Stheraven#include "opt_inet.h"
46227825Stheraven#include "opt_inet6.h"
47227825Stheraven
48227825Stheraven#include <sys/param.h>
49227825Stheraven#include <sys/jail.h>
50227825Stheraven#include <sys/kernel.h>
51227825Stheraven#include <sys/libkern.h>
52227825Stheraven#include <sys/malloc.h>
53227825Stheraven#include <sys/module.h>
54227825Stheraven#include <sys/mbuf.h>
55227825Stheraven#include <sys/priv.h>
56227825Stheraven#include <sys/proc.h>
57227825Stheraven#include <sys/protosw.h>
58227825Stheraven#include <sys/socket.h>
59227825Stheraven#include <sys/sockio.h>
60227825Stheraven#include <sys/sysctl.h>
61227825Stheraven#include <sys/systm.h>
62227825Stheraven
63227825Stheraven#include <net/ethernet.h>
64227825Stheraven#include <net/if.h>
65227825Stheraven#include <net/if_clone.h>
66227825Stheraven#include <net/if_types.h>
67227825Stheraven#include <net/route.h>
68227825Stheraven#include <net/vnet.h>
69227825Stheraven
70227825Stheraven#ifdef INET
71227825Stheraven#include <netinet/in.h>
72227825Stheraven#include <netinet/in_systm.h>
73227825Stheraven#include <netinet/in_var.h>
74227825Stheraven#include <netinet/ip.h>
75227825Stheraven#include <netinet/ip_gre.h>
76227825Stheraven#include <netinet/ip_var.h>
77227825Stheraven#include <netinet/ip_encap.h>
78227825Stheraven#else
79227825Stheraven#error "Huh? if_gre without inet?"
80227825Stheraven#endif
81227825Stheraven
82227825Stheraven#include <net/bpf.h>
83227825Stheraven
84227825Stheraven#include <net/if_gre.h>
85227825Stheraven
86227825Stheraven/*
87227825Stheraven * It is not easy to calculate the right value for a GRE MTU.
88227825Stheraven * We leave this task to the admin and use the same default that
89227825Stheraven * other vendors use.
90227825Stheraven */
91227825Stheraven#define GREMTU	1476
92227825Stheraven
93227825Stheraven#define	MTAG_COOKIE_GRE		1307983903
94227825Stheraven#define	MTAG_GRE_NESTING	1
95227825Stheravenstruct mtag_gre_nesting {
96227825Stheraven	uint16_t	count;
97227825Stheraven	uint16_t	max;
98227825Stheraven	struct ifnet	*ifp[];
99227825Stheraven};
100227825Stheraven
101227825Stheraven/*
102227825Stheraven * gre_mtx protects all global variables in if_gre.c.
103227825Stheraven * XXX: gre_softc data not protected yet.
104227825Stheraven */
105227825Stheravenstruct mtx gre_mtx;
106227825Stheravenstatic const char grename[] = "gre";
107227825Stheravenstatic MALLOC_DEFINE(M_GRE, grename, "Generic Routing Encapsulation");
108227825Stheraven
109227825Stheravenstruct gre_softc_head gre_softc_list;
110227825Stheraven
111227825Stheravenstatic int	gre_clone_create(struct if_clone *, int, caddr_t);
112227825Stheravenstatic void	gre_clone_destroy(struct ifnet *);
113227825Stheravenstatic struct if_clone *gre_cloner;
114227825Stheraven
115227825Stheravenstatic int	gre_ioctl(struct ifnet *, u_long, caddr_t);
116227825Stheravenstatic int	gre_output(struct ifnet *, struct mbuf *,
117227825Stheraven		    const struct sockaddr *, struct route *);
118227825Stheraven
119227825Stheravenstatic int gre_compute_route(struct gre_softc *sc);
120227825Stheraven
121227825Stheravenstatic void	greattach(void);
122227825Stheraven
123227825Stheraven#ifdef INET
124227825Stheravenextern struct domain inetdomain;
125227825Stheravenstatic const struct protosw in_gre_protosw = {
126227825Stheraven	.pr_type =		SOCK_RAW,
127227825Stheraven	.pr_domain =		&inetdomain,
128227825Stheraven	.pr_protocol =		IPPROTO_GRE,
129227825Stheraven	.pr_flags =		PR_ATOMIC|PR_ADDR,
130227825Stheraven	.pr_input =		gre_input,
131227825Stheraven	.pr_output =		(pr_output_t *)rip_output,
132227825Stheraven	.pr_ctlinput =		rip_ctlinput,
133227825Stheraven	.pr_ctloutput =		rip_ctloutput,
134227825Stheraven	.pr_usrreqs =		&rip_usrreqs
135227825Stheraven};
136227825Stheravenstatic const struct protosw in_mobile_protosw = {
137227825Stheraven	.pr_type =		SOCK_RAW,
138227825Stheraven	.pr_domain =		&inetdomain,
139227825Stheraven	.pr_protocol =		IPPROTO_MOBILE,
140227825Stheraven	.pr_flags =		PR_ATOMIC|PR_ADDR,
141227825Stheraven	.pr_input =		gre_mobile_input,
142227825Stheraven	.pr_output =		(pr_output_t *)rip_output,
143227825Stheraven	.pr_ctlinput =		rip_ctlinput,
144227825Stheraven	.pr_ctloutput =		rip_ctloutput,
145227825Stheraven	.pr_usrreqs =		&rip_usrreqs
146227825Stheraven};
147227825Stheraven#endif
148227825Stheraven
149227825StheravenSYSCTL_DECL(_net_link);
150227825Stheravenstatic SYSCTL_NODE(_net_link, IFT_TUNNEL, gre, CTLFLAG_RW, 0,
151227825Stheraven    "Generic Routing Encapsulation");
152227825Stheraven#ifndef MAX_GRE_NEST
153227825Stheraven/*
154227825Stheraven * This macro controls the default upper limitation on nesting of gre tunnels.
155227825Stheraven * Since, setting a large value to this macro with a careless configuration
156227825Stheraven * may introduce system crash, we don't allow any nestings by default.
157227825Stheraven * If you need to configure nested gre tunnels, you can define this macro
158232950Stheraven * in your kernel configuration file.  However, if you do so, please be
159232950Stheraven * careful to configure the tunnels so that it won't make a loop.
160227825Stheraven */
161227825Stheraven#define MAX_GRE_NEST 1
162227825Stheraven#endif
163227825Stheravenstatic int max_gre_nesting = MAX_GRE_NEST;
164227825StheravenSYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
165227825Stheraven    &max_gre_nesting, 0, "Max nested tunnels");
166227825Stheraven
167227825Stheraven/* ARGSUSED */
168227825Stheravenstatic void
169227825Stheravengreattach(void)
170227825Stheraven{
171227825Stheraven
172227825Stheraven	mtx_init(&gre_mtx, "gre_mtx", NULL, MTX_DEF);
173227825Stheraven	LIST_INIT(&gre_softc_list);
174227825Stheraven	gre_cloner = if_clone_simple(grename, gre_clone_create,
175227825Stheraven	    gre_clone_destroy, 0);
176227825Stheraven}
177227825Stheraven
178227825Stheravenstatic int
179227825Stheravengre_clone_create(ifc, unit, params)
180227825Stheraven	struct if_clone *ifc;
181227825Stheraven	int unit;
182227825Stheraven	caddr_t params;
183227825Stheraven{
184227825Stheraven	struct gre_softc *sc;
185227825Stheraven
186227825Stheraven	sc = malloc(sizeof(struct gre_softc), M_GRE, M_WAITOK | M_ZERO);
187227825Stheraven
188227825Stheraven	GRE2IFP(sc) = if_alloc(IFT_TUNNEL);
189227825Stheraven	if (GRE2IFP(sc) == NULL) {
190227825Stheraven		free(sc, M_GRE);
191227825Stheraven		return (ENOSPC);
192227825Stheraven	}
193227825Stheraven
194227825Stheraven	GRE2IFP(sc)->if_softc = sc;
195227825Stheraven	if_initname(GRE2IFP(sc), grename, unit);
196227825Stheraven
197241903Sdim	GRE2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen;
198227825Stheraven	GRE2IFP(sc)->if_addrlen = 0;
199227825Stheraven	GRE2IFP(sc)->if_hdrlen = 24; /* IP + GRE */
200227825Stheraven	GRE2IFP(sc)->if_mtu = GREMTU;
201227825Stheraven	GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
202227825Stheraven	GRE2IFP(sc)->if_output = gre_output;
203227825Stheraven	GRE2IFP(sc)->if_ioctl = gre_ioctl;
204227825Stheraven	sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
205227825Stheraven	sc->g_proto = IPPROTO_GRE;
206227825Stheraven	GRE2IFP(sc)->if_flags |= IFF_LINK0;
207227825Stheraven	sc->encap = NULL;
208227825Stheraven	sc->gre_fibnum = curthread->td_proc->p_fibnum;
209227825Stheraven	sc->wccp_ver = WCCP_V1;
210227825Stheraven	sc->key = 0;
211227825Stheraven	if_attach(GRE2IFP(sc));
212227825Stheraven	bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t));
213227825Stheraven	mtx_lock(&gre_mtx);
214227825Stheraven	LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
215227825Stheraven	mtx_unlock(&gre_mtx);
216227825Stheraven	return (0);
217227825Stheraven}
218227825Stheraven
219227825Stheravenstatic void
220227825Stheravengre_clone_destroy(ifp)
221227825Stheraven	struct ifnet *ifp;
222227825Stheraven{
223227825Stheraven	struct gre_softc *sc = ifp->if_softc;
224227825Stheraven
225227825Stheraven	mtx_lock(&gre_mtx);
226227825Stheraven	LIST_REMOVE(sc, sc_list);
227227825Stheraven	mtx_unlock(&gre_mtx);
228227825Stheraven
229227825Stheraven#ifdef INET
230227825Stheraven	if (sc->encap != NULL)
231227825Stheraven		encap_detach(sc->encap);
232227825Stheraven#endif
233227825Stheraven	bpfdetach(ifp);
234227825Stheraven	if_detach(ifp);
235227825Stheraven	if_free(ifp);
236227825Stheraven	free(sc, M_GRE);
237227825Stheraven}
238227825Stheraven
239227825Stheraven/*
240227825Stheraven * The output routine. Takes a packet and encapsulates it in the protocol
241227825Stheraven * given by sc->g_proto. See also RFC 1701 and RFC 2004
242227825Stheraven */
243227825Stheravenstatic int
244227825Stheravengre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
245227825Stheraven	   struct route *ro)
246227825Stheraven{
247227825Stheraven	int error = 0;
248227825Stheraven	struct gre_softc *sc = ifp->if_softc;
249227825Stheraven	struct greip *gh;
250227825Stheraven	struct ip *ip;
251227825Stheraven	struct m_tag *mtag;
252227825Stheraven	struct mtag_gre_nesting *gt;
253227825Stheraven	size_t len;
254227825Stheraven	u_short gre_ip_id = 0;
255227825Stheraven	uint8_t gre_ip_tos = 0;
256227825Stheraven	u_int16_t etype = 0;
257227825Stheraven	struct mobile_h mob_h;
258227825Stheraven	u_int32_t af;
259232950Stheraven	int extra = 0, max;
260227825Stheraven
261227825Stheraven	/*
262227825Stheraven	 * gre may cause infinite recursion calls when misconfigured.  High
263227825Stheraven	 * nesting level may cause stack exhaustion.  We'll prevent this by
264227825Stheraven	 * detecting loops and by introducing upper limit.
265227825Stheraven	 */
266227825Stheraven	mtag = m_tag_locate(m, MTAG_COOKIE_GRE, MTAG_GRE_NESTING, NULL);
267227825Stheraven	if (mtag != NULL) {
268227825Stheraven		struct ifnet **ifp2;
269227825Stheraven
270227825Stheraven		gt = (struct mtag_gre_nesting *)(mtag + 1);
271227825Stheraven		gt->count++;
272227825Stheraven		if (gt->count > min(gt->max,max_gre_nesting)) {
273227825Stheraven			printf("%s: hit maximum recursion limit %u on %s\n",
274232950Stheraven				__func__, gt->count - 1, ifp->if_xname);
275227825Stheraven			m_freem(m);
276232950Stheraven			error = EIO;	/* is there better errno? */
277232950Stheraven			goto end;
278227825Stheraven		}
279227825Stheraven
280227825Stheraven		ifp2 = gt->ifp;
281227825Stheraven		for (max = gt->count - 1; max > 0; max--) {
282227825Stheraven			if (*ifp2 == ifp)
283227825Stheraven				break;
284227825Stheraven			ifp2++;
285227825Stheraven		}
286227825Stheraven		if (*ifp2 == ifp) {
287227825Stheraven			printf("%s: detected loop with nexting %u on %s\n",
288227825Stheraven				__func__, gt->count-1, ifp->if_xname);
289227825Stheraven			m_freem(m);
290227825Stheraven			error = EIO;	/* is there better errno? */
291227825Stheraven			goto end;
292227825Stheraven		}
293227825Stheraven		*ifp2 = ifp;
294227825Stheraven
295227825Stheraven	} else {
296227825Stheraven		/*
297227825Stheraven		 * Given that people should NOT increase max_gre_nesting beyond
298227825Stheraven		 * their real needs, we allocate once per packet rather than
299227825Stheraven		 * allocating an mtag once per passing through gre.
300227825Stheraven		 *
301227825Stheraven		 * Note: the sysctl does not actually check for saneness, so we
302227825Stheraven		 * limit the maximum numbers of possible recursions here.
303227825Stheraven		 */
304227825Stheraven		max = imin(max_gre_nesting, 256);
305227825Stheraven		/* If someone sets the sysctl <= 0, we want at least 1. */
306227825Stheraven		max = imax(max, 1);
307227825Stheraven		len = sizeof(struct mtag_gre_nesting) +
308227825Stheraven		    max * sizeof(struct ifnet *);
309227825Stheraven		mtag = m_tag_alloc(MTAG_COOKIE_GRE, MTAG_GRE_NESTING, len,
310227825Stheraven		    M_NOWAIT);
311227825Stheraven		if (mtag == NULL) {
312227825Stheraven			m_freem(m);
313227825Stheraven			error = ENOMEM;
314227825Stheraven			goto end;
315227825Stheraven		}
316227825Stheraven		gt = (struct mtag_gre_nesting *)(mtag + 1);
317227825Stheraven		bzero(gt, len);
318227825Stheraven		gt->count = 1;
319227825Stheraven		gt->max = max;
320227825Stheraven		*gt->ifp = ifp;
321227825Stheraven		m_tag_prepend(m, mtag);
322227825Stheraven	}
323227825Stheraven
324227825Stheraven	if (!((ifp->if_flags & IFF_UP) &&
325227825Stheraven	    (ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
326227825Stheraven	    sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
327227825Stheraven		m_freem(m);
328227825Stheraven		error = ENETDOWN;
329227825Stheraven		goto end;
330227825Stheraven	}
331227825Stheraven
332227825Stheraven	gh = NULL;
333227825Stheraven	ip = NULL;
334227825Stheraven
335227825Stheraven	/* BPF writes need to be handled specially. */
336227825Stheraven	if (dst->sa_family == AF_UNSPEC)
337227825Stheraven		bcopy(dst->sa_data, &af, sizeof(af));
338227825Stheraven	else
339227825Stheraven		af = dst->sa_family;
340227825Stheraven
341227825Stheraven	if (bpf_peers_present(ifp->if_bpf))
342227825Stheraven		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
343227825Stheraven
344227825Stheraven	m->m_flags &= ~(M_BCAST|M_MCAST);
345232950Stheraven
346232950Stheraven	if (sc->g_proto == IPPROTO_MOBILE) {
347227825Stheraven		if (af == AF_INET) {
348232950Stheraven			struct mbuf *m0;
349227825Stheraven			int msiz;
350227825Stheraven
351227825Stheraven			ip = mtod(m, struct ip *);
352227825Stheraven
353227825Stheraven			/*
354227825Stheraven			 * RFC2004 specifies that fragmented diagrams shouldn't
355227825Stheraven			 * be encapsulated.
356227825Stheraven			 */
357227825Stheraven			if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
358227825Stheraven				_IF_DROP(&ifp->if_snd);
359227825Stheraven				m_freem(m);
360227825Stheraven				error = EINVAL;    /* is there better errno? */
361227825Stheraven				goto end;
362227825Stheraven			}
363227825Stheraven			memset(&mob_h, 0, MOB_H_SIZ_L);
364227825Stheraven			mob_h.proto = (ip->ip_p) << 8;
365227825Stheraven			mob_h.odst = ip->ip_dst.s_addr;
366227825Stheraven			ip->ip_dst.s_addr = sc->g_dst.s_addr;
367227825Stheraven
368227825Stheraven			/*
369227825Stheraven			 * If the packet comes from our host, we only change
370227825Stheraven			 * the destination address in the IP header.
371227825Stheraven			 * Else we also need to save and change the source
372232950Stheraven			 */
373232950Stheraven			if (in_hosteq(ip->ip_src, sc->g_src)) {
374227825Stheraven				msiz = MOB_H_SIZ_S;
375232950Stheraven			} else {
376227825Stheraven				mob_h.proto |= MOB_H_SBIT;
377227825Stheraven				mob_h.osrc = ip->ip_src.s_addr;
378227825Stheraven				ip->ip_src.s_addr = sc->g_src.s_addr;
379227825Stheraven				msiz = MOB_H_SIZ_L;
380227825Stheraven			}
381227825Stheraven			mob_h.proto = htons(mob_h.proto);
382227825Stheraven			mob_h.hcrc = gre_in_cksum((u_int16_t *)&mob_h, msiz);
383227825Stheraven
384227825Stheraven			if ((m->m_data - msiz) < m->m_pktdat) {
385227825Stheraven				m0 = m_gethdr(M_NOWAIT, MT_DATA);
386227825Stheraven				if (m0 == NULL) {
387227825Stheraven					_IF_DROP(&ifp->if_snd);
388227825Stheraven					m_freem(m);
389227825Stheraven					error = ENOBUFS;
390227825Stheraven					goto end;
391227825Stheraven				}
392227825Stheraven				m0->m_next = m;
393227825Stheraven				m->m_data += sizeof(struct ip);
394227825Stheraven				m->m_len -= sizeof(struct ip);
395227825Stheraven				m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
396227825Stheraven				m0->m_len = msiz + sizeof(struct ip);
397227825Stheraven				m0->m_data += max_linkhdr;
398227825Stheraven				memcpy(mtod(m0, caddr_t), (caddr_t)ip,
399232950Stheraven				       sizeof(struct ip));
400232950Stheraven				m = m0;
401227825Stheraven			} else {  /* we have some space left in the old one */
402232950Stheraven				m->m_data -= msiz;
403227825Stheraven				m->m_len += msiz;
404227825Stheraven				m->m_pkthdr.len += msiz;
405227825Stheraven				bcopy(ip, mtod(m, caddr_t),
406227825Stheraven					sizeof(struct ip));
407227825Stheraven			}
408227825Stheraven			ip = mtod(m, struct ip *);
409227825Stheraven			memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
410227825Stheraven			ip->ip_len = htons(ntohs(ip->ip_len) + msiz);
411227825Stheraven		} else {  /* AF_INET */
412227825Stheraven			_IF_DROP(&ifp->if_snd);
413227825Stheraven			m_freem(m);
414227825Stheraven			error = EINVAL;
415227825Stheraven			goto end;
416227825Stheraven		}
417227825Stheraven	} else if (sc->g_proto == IPPROTO_GRE) {
418227825Stheraven		switch (af) {
419227825Stheraven		case AF_INET:
420227825Stheraven			ip = mtod(m, struct ip *);
421227825Stheraven			gre_ip_tos = ip->ip_tos;
422227825Stheraven			gre_ip_id = ip->ip_id;
423227825Stheraven			if (sc->wccp_ver == WCCP_V2) {
424227825Stheraven				extra = sizeof(uint32_t);
425227825Stheraven				etype =  WCCP_PROTOCOL_TYPE;
426232950Stheraven			} else {
427232950Stheraven				etype = ETHERTYPE_IP;
428227825Stheraven			}
429232950Stheraven			break;
430227825Stheraven#ifdef INET6
431227825Stheraven		case AF_INET6:
432227825Stheraven			gre_ip_id = ip_newid();
433227825Stheraven			etype = ETHERTYPE_IPV6;
434227825Stheraven			break;
435227825Stheraven#endif
436227825Stheraven#ifdef NETATALK
437227825Stheraven		case AF_APPLETALK:
438227825Stheraven			etype = ETHERTYPE_ATALK;
439227825Stheraven			break;
440227825Stheraven#endif
441227825Stheraven		default:
442227825Stheraven			_IF_DROP(&ifp->if_snd);
443227825Stheraven			m_freem(m);
444227825Stheraven			error = EAFNOSUPPORT;
445227825Stheraven			goto end;
446227825Stheraven		}
447227825Stheraven
448227825Stheraven		/* Reserve space for GRE header + optional GRE key */
449227825Stheraven		int hdrlen = sizeof(struct greip) + extra;
450227825Stheraven		if (sc->key)
451227825Stheraven			hdrlen += sizeof(uint32_t);
452227825Stheraven		M_PREPEND(m, hdrlen, M_NOWAIT);
453232950Stheraven	} else {
454232950Stheraven		_IF_DROP(&ifp->if_snd);
455227825Stheraven		m_freem(m);
456232950Stheraven		error = EINVAL;
457227825Stheraven		goto end;
458227825Stheraven	}
459227825Stheraven
460227825Stheraven	if (m == NULL) {	/* mbuf allocation failed */
461227825Stheraven		_IF_DROP(&ifp->if_snd);
462227825Stheraven		error = ENOBUFS;
463227825Stheraven		goto end;
464227825Stheraven	}
465227825Stheraven
466227825Stheraven	M_SETFIB(m, sc->gre_fibnum); /* The envelope may use a different FIB */
467227825Stheraven
468227825Stheraven	gh = mtod(m, struct greip *);
469227825Stheraven	if (sc->g_proto == IPPROTO_GRE) {
470227825Stheraven		uint32_t *options = gh->gi_options;
471227825Stheraven
472227825Stheraven		memset((void *)gh, 0, sizeof(struct greip) + extra);
473227825Stheraven		gh->gi_ptype = htons(etype);
474227825Stheraven		gh->gi_flags = 0;
475227825Stheraven
476227825Stheraven		/* Add key option */
477227825Stheraven		if (sc->key)
478227825Stheraven		{
479227825Stheraven			gh->gi_flags |= htons(GRE_KP);
480232950Stheraven			*(options++) = htonl(sc->key);
481232950Stheraven		}
482227825Stheraven	}
483232950Stheraven
484227825Stheraven	gh->gi_pr = sc->g_proto;
485227825Stheraven	if (sc->g_proto != IPPROTO_MOBILE) {
486227825Stheraven		gh->gi_src = sc->g_src;
487227825Stheraven		gh->gi_dst = sc->g_dst;
488227825Stheraven		((struct ip*)gh)->ip_v = IPPROTO_IPV4;
489227825Stheraven		((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
490227825Stheraven		((struct ip*)gh)->ip_ttl = GRE_TTL;
491227825Stheraven		((struct ip*)gh)->ip_tos = gre_ip_tos;
492227825Stheraven		((struct ip*)gh)->ip_id = gre_ip_id;
493227825Stheraven		gh->gi_len = htons(m->m_pkthdr.len);
494227825Stheraven	}
495227825Stheraven
496227825Stheraven	ifp->if_opackets++;
497227825Stheraven	ifp->if_obytes += m->m_pkthdr.len;
498227825Stheraven	/*
499227825Stheraven	 * Send it off and with IP_FORWARD flag to prevent it from
500227825Stheraven	 * overwriting the ip_id again.  ip_id is already set to the
501227825Stheraven	 * ip_id of the encapsulated packet.
502227825Stheraven	 */
503227825Stheraven	error = ip_output(m, NULL, &sc->route, IP_FORWARDING,
504227825Stheraven	    (struct ip_moptions *)NULL, (struct inpcb *)NULL);
505227825Stheraven  end:
506227825Stheraven	if (error)
507232950Stheraven		ifp->if_oerrors++;
508232950Stheraven	return (error);
509227825Stheraven}
510232950Stheraven
511227825Stheravenstatic int
512227825Stheravengre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
513227825Stheraven{
514227825Stheraven	struct ifreq *ifr = (struct ifreq *)data;
515227825Stheraven	struct if_laddrreq *lifr = (struct if_laddrreq *)data;
516227825Stheraven	struct in_aliasreq *aifr = (struct in_aliasreq *)data;
517227825Stheraven	struct gre_softc *sc = ifp->if_softc;
518227825Stheraven	struct sockaddr_in si;
519227825Stheraven	struct sockaddr *sa = NULL;
520227825Stheraven	int error, adj;
521227825Stheraven	struct sockaddr_in sp, sm, dp, dm;
522227825Stheraven	uint32_t key;
523227825Stheraven
524227825Stheraven	error = 0;
525227825Stheraven	adj = 0;
526227825Stheraven
527227825Stheraven	switch (cmd) {
528227825Stheraven	case SIOCSIFADDR:
529227825Stheraven		ifp->if_flags |= IFF_UP;
530227825Stheraven		break;
531227825Stheraven	case SIOCSIFDSTADDR:
532227825Stheraven		break;
533227825Stheraven	case SIOCSIFFLAGS:
534232950Stheraven		/*
535232950Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
536227825Stheraven		 * layer check?
537232950Stheraven		 */
538227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_SETIFFLAGS)) != 0)
539227825Stheraven			break;
540227825Stheraven		if ((ifr->ifr_flags & IFF_LINK0) != 0)
541227825Stheraven			sc->g_proto = IPPROTO_GRE;
542227825Stheraven		else
543227825Stheraven			sc->g_proto = IPPROTO_MOBILE;
544227825Stheraven		if ((ifr->ifr_flags & IFF_LINK2) != 0)
545227825Stheraven			sc->wccp_ver = WCCP_V2;
546227825Stheraven		else
547227825Stheraven			sc->wccp_ver = WCCP_V1;
548227825Stheraven		goto recompute;
549227825Stheraven	case SIOCSIFMTU:
550227825Stheraven		/*
551227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
552227825Stheraven		 * layer check?
553227825Stheraven		 */
554227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_SETIFMTU)) != 0)
555227825Stheraven			break;
556227825Stheraven		if (ifr->ifr_mtu < 576) {
557227825Stheraven			error = EINVAL;
558227825Stheraven			break;
559227825Stheraven		}
560227825Stheraven		ifp->if_mtu = ifr->ifr_mtu;
561232950Stheraven		break;
562232950Stheraven	case SIOCGIFMTU:
563227825Stheraven		ifr->ifr_mtu = GRE2IFP(sc)->if_mtu;
564232950Stheraven		break;
565227825Stheraven	case SIOCADDMULTI:
566227825Stheraven		/*
567227825Stheraven		 * XXXRW: Isn't this priv_checkr() redundant to the ifnet
568227825Stheraven		 * layer check?
569227825Stheraven		 */
570227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_ADDMULTI)) != 0)
571227825Stheraven			break;
572227825Stheraven		if (ifr == 0) {
573227825Stheraven			error = EAFNOSUPPORT;
574227825Stheraven			break;
575227825Stheraven		}
576227825Stheraven		switch (ifr->ifr_addr.sa_family) {
577227825Stheraven#ifdef INET
578227825Stheraven		case AF_INET:
579227825Stheraven			break;
580227825Stheraven#endif
581227825Stheraven#ifdef INET6
582227825Stheraven		case AF_INET6:
583227825Stheraven			break;
584227825Stheraven#endif
585227825Stheraven		default:
586227825Stheraven			error = EAFNOSUPPORT;
587227825Stheraven			break;
588232950Stheraven		}
589232950Stheraven		break;
590227825Stheraven	case SIOCDELMULTI:
591232950Stheraven		/*
592227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
593227825Stheraven		 * layer check?
594227825Stheraven		 */
595227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_DELIFGROUP)) != 0)
596227825Stheraven			break;
597227825Stheraven		if (ifr == 0) {
598227825Stheraven			error = EAFNOSUPPORT;
599227825Stheraven			break;
600227825Stheraven		}
601227825Stheraven		switch (ifr->ifr_addr.sa_family) {
602227825Stheraven#ifdef INET
603227825Stheraven		case AF_INET:
604227825Stheraven			break;
605227825Stheraven#endif
606227825Stheraven#ifdef INET6
607227825Stheraven		case AF_INET6:
608227825Stheraven			break;
609227825Stheraven#endif
610227825Stheraven		default:
611227825Stheraven			error = EAFNOSUPPORT;
612227825Stheraven			break;
613227825Stheraven		}
614227825Stheraven		break;
615232950Stheraven	case GRESPROTO:
616232950Stheraven		/*
617227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
618232950Stheraven		 * layer check?
619227825Stheraven		 */
620227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
621227825Stheraven			break;
622227825Stheraven		sc->g_proto = ifr->ifr_flags;
623227825Stheraven		switch (sc->g_proto) {
624227825Stheraven		case IPPROTO_GRE:
625227825Stheraven			ifp->if_flags |= IFF_LINK0;
626227825Stheraven			break;
627227825Stheraven		case IPPROTO_MOBILE:
628227825Stheraven			ifp->if_flags &= ~IFF_LINK0;
629227825Stheraven			break;
630227825Stheraven		default:
631227825Stheraven			error = EPROTONOSUPPORT;
632227825Stheraven			break;
633227825Stheraven		}
634227825Stheraven		goto recompute;
635227825Stheraven	case GREGPROTO:
636227825Stheraven		ifr->ifr_flags = sc->g_proto;
637227825Stheraven		break;
638227825Stheraven	case GRESADDRS:
639227825Stheraven	case GRESADDRD:
640227825Stheraven		error = priv_check(curthread, PRIV_NET_GRE);
641227825Stheraven		if (error)
642232950Stheraven			return (error);
643232950Stheraven		/*
644227825Stheraven		 * set tunnel endpoints, compute a less specific route
645227825Stheraven		 * to the remote end and mark if as up
646232950Stheraven		 */
647227825Stheraven		sa = &ifr->ifr_addr;
648227825Stheraven		if (cmd == GRESADDRS)
649227825Stheraven			sc->g_src = (satosin(sa))->sin_addr;
650227825Stheraven		if (cmd == GRESADDRD)
651227825Stheraven			sc->g_dst = (satosin(sa))->sin_addr;
652227825Stheraven	recompute:
653227825Stheraven#ifdef INET
654227825Stheraven		if (sc->encap != NULL) {
655227825Stheraven			encap_detach(sc->encap);
656227825Stheraven			sc->encap = NULL;
657227825Stheraven		}
658227825Stheraven#endif
659227825Stheraven		if ((sc->g_src.s_addr != INADDR_ANY) &&
660227825Stheraven		    (sc->g_dst.s_addr != INADDR_ANY)) {
661227825Stheraven			bzero(&sp, sizeof(sp));
662227825Stheraven			bzero(&sm, sizeof(sm));
663227825Stheraven			bzero(&dp, sizeof(dp));
664227825Stheraven			bzero(&dm, sizeof(dm));
665227825Stheraven			sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
666227825Stheraven			    sizeof(struct sockaddr_in);
667227825Stheraven			sp.sin_family = sm.sin_family = dp.sin_family =
668227825Stheraven			    dm.sin_family = AF_INET;
669227825Stheraven			sp.sin_addr = sc->g_src;
670227825Stheraven			dp.sin_addr = sc->g_dst;
671227825Stheraven			sm.sin_addr.s_addr = dm.sin_addr.s_addr =
672227825Stheraven			    INADDR_BROADCAST;
673227825Stheraven#ifdef INET
674227825Stheraven			sc->encap = encap_attach(AF_INET, sc->g_proto,
675227825Stheraven			    sintosa(&sp), sintosa(&sm), sintosa(&dp),
676227825Stheraven			    sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
677227825Stheraven				&in_gre_protosw : &in_mobile_protosw, sc);
678227825Stheraven			if (sc->encap == NULL)
679227825Stheraven				printf("%s: unable to attach encap\n",
680227825Stheraven				    if_name(GRE2IFP(sc)));
681227825Stheraven#endif
682232950Stheraven			if (sc->route.ro_rt != 0) /* free old route */
683232950Stheraven				RTFREE(sc->route.ro_rt);
684227825Stheraven			if (gre_compute_route(sc) == 0)
685227825Stheraven				ifp->if_drv_flags |= IFF_DRV_RUNNING;
686232950Stheraven			else
687227825Stheraven				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
688227825Stheraven		}
689227825Stheraven		break;
690227825Stheraven	case GREGADDRS:
691227825Stheraven		memset(&si, 0, sizeof(si));
692227825Stheraven		si.sin_family = AF_INET;
693227825Stheraven		si.sin_len = sizeof(struct sockaddr_in);
694227825Stheraven		si.sin_addr.s_addr = sc->g_src.s_addr;
695227825Stheraven		sa = sintosa(&si);
696227825Stheraven		error = prison_if(curthread->td_ucred, sa);
697227825Stheraven		if (error != 0)
698227825Stheraven			break;
699227825Stheraven		ifr->ifr_addr = *sa;
700227825Stheraven		break;
701227825Stheraven	case GREGADDRD:
702227825Stheraven		memset(&si, 0, sizeof(si));
703227825Stheraven		si.sin_family = AF_INET;
704227825Stheraven		si.sin_len = sizeof(struct sockaddr_in);
705227825Stheraven		si.sin_addr.s_addr = sc->g_dst.s_addr;
706227825Stheraven		sa = sintosa(&si);
707227825Stheraven		error = prison_if(curthread->td_ucred, sa);
708227825Stheraven		if (error != 0)
709227825Stheraven			break;
710227825Stheraven		ifr->ifr_addr = *sa;
711227825Stheraven		break;
712227825Stheraven	case SIOCSIFPHYADDR:
713227825Stheraven		/*
714227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
715227825Stheraven		 * layer check?
716227825Stheraven		 */
717227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
718227825Stheraven			break;
719227825Stheraven		if (aifr->ifra_addr.sin_family != AF_INET ||
720227825Stheraven		    aifr->ifra_dstaddr.sin_family != AF_INET) {
721227825Stheraven			error = EAFNOSUPPORT;
722227825Stheraven			break;
723227825Stheraven		}
724227825Stheraven		if (aifr->ifra_addr.sin_len != sizeof(si) ||
725227825Stheraven		    aifr->ifra_dstaddr.sin_len != sizeof(si)) {
726227825Stheraven			error = EINVAL;
727227825Stheraven			break;
728227825Stheraven		}
729227825Stheraven		sc->g_src = aifr->ifra_addr.sin_addr;
730227825Stheraven		sc->g_dst = aifr->ifra_dstaddr.sin_addr;
731227825Stheraven		goto recompute;
732227825Stheraven	case SIOCSLIFPHYADDR:
733227825Stheraven		/*
734227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
735227825Stheraven		 * layer check?
736227825Stheraven		 */
737227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
738227825Stheraven			break;
739227825Stheraven		if (lifr->addr.ss_family != AF_INET ||
740227825Stheraven		    lifr->dstaddr.ss_family != AF_INET) {
741227825Stheraven			error = EAFNOSUPPORT;
742227825Stheraven			break;
743227825Stheraven		}
744227825Stheraven		if (lifr->addr.ss_len != sizeof(si) ||
745227825Stheraven		    lifr->dstaddr.ss_len != sizeof(si)) {
746227825Stheraven			error = EINVAL;
747227825Stheraven			break;
748227825Stheraven		}
749227825Stheraven		sc->g_src = (satosin(&lifr->addr))->sin_addr;
750227825Stheraven		sc->g_dst =
751227825Stheraven		    (satosin(&lifr->dstaddr))->sin_addr;
752227825Stheraven		goto recompute;
753227825Stheraven	case SIOCDIFPHYADDR:
754227825Stheraven		/*
755227825Stheraven		 * XXXRW: Isn't this priv_check() redundant to the ifnet
756227825Stheraven		 * layer check?
757227825Stheraven		 */
758227825Stheraven		if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0)
759227825Stheraven			break;
760227825Stheraven		sc->g_src.s_addr = INADDR_ANY;
761227825Stheraven		sc->g_dst.s_addr = INADDR_ANY;
762227825Stheraven		goto recompute;
763227825Stheraven	case SIOCGLIFPHYADDR:
764227825Stheraven		if (sc->g_src.s_addr == INADDR_ANY ||
765227825Stheraven		    sc->g_dst.s_addr == INADDR_ANY) {
766227825Stheraven			error = EADDRNOTAVAIL;
767227825Stheraven			break;
768227825Stheraven		}
769227825Stheraven		memset(&si, 0, sizeof(si));
770227825Stheraven		si.sin_family = AF_INET;
771227825Stheraven		si.sin_len = sizeof(struct sockaddr_in);
772227825Stheraven		si.sin_addr.s_addr = sc->g_src.s_addr;
773227825Stheraven		error = prison_if(curthread->td_ucred, (struct sockaddr *)&si);
774227825Stheraven		if (error != 0)
775227825Stheraven			break;
776227825Stheraven		memcpy(&lifr->addr, &si, sizeof(si));
777227825Stheraven		si.sin_addr.s_addr = sc->g_dst.s_addr;
778227825Stheraven		error = prison_if(curthread->td_ucred, (struct sockaddr *)&si);
779227825Stheraven		if (error != 0)
780227825Stheraven			break;
781227825Stheraven		memcpy(&lifr->dstaddr, &si, sizeof(si));
782227825Stheraven		break;
783227825Stheraven	case SIOCGIFPSRCADDR:
784227825Stheraven#ifdef INET6
785227825Stheraven	case SIOCGIFPSRCADDR_IN6:
786227825Stheraven#endif
787227825Stheraven		if (sc->g_src.s_addr == INADDR_ANY) {
788227825Stheraven			error = EADDRNOTAVAIL;
789227825Stheraven			break;
790227825Stheraven		}
791227825Stheraven		memset(&si, 0, sizeof(si));
792227825Stheraven		si.sin_family = AF_INET;
793227825Stheraven		si.sin_len = sizeof(struct sockaddr_in);
794227825Stheraven		si.sin_addr.s_addr = sc->g_src.s_addr;
795227825Stheraven		error = prison_if(curthread->td_ucred, (struct sockaddr *)&si);
796227825Stheraven		if (error != 0)
797227825Stheraven			break;
798227825Stheraven		bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
799227825Stheraven		break;
800227825Stheraven	case SIOCGIFPDSTADDR:
801227825Stheraven#ifdef INET6
802227825Stheraven	case SIOCGIFPDSTADDR_IN6:
803227825Stheraven#endif
804227825Stheraven		if (sc->g_dst.s_addr == INADDR_ANY) {
805227825Stheraven			error = EADDRNOTAVAIL;
806227825Stheraven			break;
807227825Stheraven		}
808227825Stheraven		memset(&si, 0, sizeof(si));
809227825Stheraven		si.sin_family = AF_INET;
810227825Stheraven		si.sin_len = sizeof(struct sockaddr_in);
811227825Stheraven		si.sin_addr.s_addr = sc->g_dst.s_addr;
812227825Stheraven		error = prison_if(curthread->td_ucred, (struct sockaddr *)&si);
813227825Stheraven		if (error != 0)
814227825Stheraven			break;
815227825Stheraven		bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
816227825Stheraven		break;
817227825Stheraven	case GRESKEY:
818227825Stheraven		error = priv_check(curthread, PRIV_NET_GRE);
819227825Stheraven		if (error)
820227825Stheraven			break;
821227825Stheraven		error = copyin(ifr->ifr_data, &key, sizeof(key));
822227825Stheraven		if (error)
823227825Stheraven			break;
824227825Stheraven		/* adjust MTU for option header */
825227825Stheraven		if (key == 0 && sc->key != 0)		/* clear */
826227825Stheraven			adj += sizeof(key);
827227825Stheraven		else if (key != 0 && sc->key == 0)	/* set */
828227825Stheraven			adj -= sizeof(key);
829227825Stheraven
830227825Stheraven		if (ifp->if_mtu + adj < 576) {
831227825Stheraven			error = EINVAL;
832227825Stheraven			break;
833227825Stheraven		}
834227825Stheraven		ifp->if_mtu += adj;
835227825Stheraven		sc->key = key;
836227825Stheraven		break;
837227825Stheraven	case GREGKEY:
838227825Stheraven		error = copyout(&sc->key, ifr->ifr_data, sizeof(sc->key));
839227825Stheraven		break;
840227825Stheraven
841227825Stheraven	default:
842227825Stheraven		error = EINVAL;
843227825Stheraven		break;
844227825Stheraven	}
845227825Stheraven
846227825Stheraven	return (error);
847227825Stheraven}
848227825Stheraven
849227825Stheraven/*
850227825Stheraven * computes a route to our destination that is not the one
851227825Stheraven * which would be taken by ip_output(), as this one will loop back to
852227825Stheraven * us. If the interface is p2p as  a--->b, then a routing entry exists
853227825Stheraven * If we now send a packet to b (e.g. ping b), this will come down here
854227825Stheraven * gets src=a, dst=b tacked on and would from ip_output() sent back to
855227825Stheraven * if_gre.
856227825Stheraven * Goal here is to compute a route to b that is less specific than
857227825Stheraven * a-->b. We know that this one exists as in normal operation we have
858227825Stheraven * at least a default route which matches.
859227825Stheraven */
860227825Stheravenstatic int
861227825Stheravengre_compute_route(struct gre_softc *sc)
862227825Stheraven{
863227825Stheraven	struct route *ro;
864227825Stheraven
865227825Stheraven	ro = &sc->route;
866227825Stheraven
867227825Stheraven	memset(ro, 0, sizeof(struct route));
868227825Stheraven	((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
869227825Stheraven	ro->ro_dst.sa_family = AF_INET;
870227825Stheraven	ro->ro_dst.sa_len = sizeof(ro->ro_dst);
871227825Stheraven
872227825Stheraven	/*
873227825Stheraven	 * toggle last bit, so our interface is not found, but a less
874227825Stheraven	 * specific route. I'd rather like to specify a shorter mask,
875227825Stheraven	 * but this is not possible. Should work though. XXX
876227825Stheraven	 * XXX MRT Use a different FIB for the tunnel to solve this problem.
877227825Stheraven	 */
878227825Stheraven	if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0) {
879227825Stheraven		((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr ^=
880227825Stheraven		    htonl(0x01);
881227825Stheraven	}
882227825Stheraven
883227825Stheraven#ifdef DIAGNOSTIC
884227825Stheraven	printf("%s: searching for a route to %s", if_name(GRE2IFP(sc)),
885227825Stheraven	    inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr));
886227825Stheraven#endif
887227825Stheraven
888227825Stheraven	rtalloc_fib(ro, sc->gre_fibnum);
889227825Stheraven
890227825Stheraven	/*
891227825Stheraven	 * check if this returned a route at all and this route is no
892227825Stheraven	 * recursion to ourself
893227825Stheraven	 */
894227825Stheraven	if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
895227825Stheraven#ifdef DIAGNOSTIC
896227825Stheraven		if (ro->ro_rt == NULL)
897227825Stheraven			printf(" - no route found!\n");
898227825Stheraven		else
899227825Stheraven			printf(" - route loops back to ourself!\n");
900227825Stheraven#endif
901227825Stheraven		return EADDRNOTAVAIL;
902227825Stheraven	}
903227825Stheraven
904227825Stheraven	/*
905227825Stheraven	 * now change it back - else ip_output will just drop
906227825Stheraven	 * the route and search one to this interface ...
907227825Stheraven	 */
908227825Stheraven	if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0)
909227825Stheraven		((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
910227825Stheraven
911227825Stheraven#ifdef DIAGNOSTIC
912227825Stheraven	printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
913227825Stheraven	    inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr));
914227825Stheraven	printf("\n");
915227825Stheraven#endif
916227825Stheraven
917227825Stheraven	return 0;
918227825Stheraven}
919227825Stheraven
920227825Stheraven/*
921227825Stheraven * do a checksum of a buffer - much like in_cksum, which operates on
922227825Stheraven * mbufs.
923227825Stheraven */
924227825Stheravenu_int16_t
925227825Stheravengre_in_cksum(u_int16_t *p, u_int len)
926227825Stheraven{
927227825Stheraven	u_int32_t sum = 0;
928227825Stheraven	int nwords = len >> 1;
929227825Stheraven
930227825Stheraven	while (nwords-- != 0)
931227825Stheraven		sum += *p++;
932227825Stheraven
933227825Stheraven	if (len & 1) {
934227825Stheraven		union {
935227825Stheraven			u_short w;
936227825Stheraven			u_char c[2];
937227825Stheraven		} u;
938227825Stheraven		u.c[0] = *(u_char *)p;
939227825Stheraven		u.c[1] = 0;
940227825Stheraven		sum += u.w;
941227825Stheraven	}
942227825Stheraven
943227825Stheraven	/* end-around-carry */
944227825Stheraven	sum = (sum >> 16) + (sum & 0xffff);
945227825Stheraven	sum += (sum >> 16);
946227825Stheraven	return (~sum);
947227825Stheraven}
948227825Stheraven
949227825Stheravenstatic int
950227825Stheravengremodevent(module_t mod, int type, void *data)
951227825Stheraven{
952227825Stheraven
953227825Stheraven	switch (type) {
954227825Stheraven	case MOD_LOAD:
955227825Stheraven		greattach();
956227825Stheraven		break;
957227825Stheraven	case MOD_UNLOAD:
958227825Stheraven		if_clone_detach(gre_cloner);
959227825Stheraven		mtx_destroy(&gre_mtx);
960227825Stheraven		break;
961227825Stheraven	default:
962227825Stheraven		return EOPNOTSUPP;
963227825Stheraven	}
964227825Stheraven	return 0;
965227825Stheraven}
966227825Stheraven
967227825Stheravenstatic moduledata_t gre_mod = {
968227825Stheraven	"if_gre",
969227825Stheraven	gremodevent,
970227825Stheraven	0
971227825Stheraven};
972227825Stheraven
973227825StheravenDECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
974227825StheravenMODULE_VERSION(if_gre, 1);
975227825Stheraven