xref: /netbsd-src/sys/net/if_gre.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
2 
3 /*
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Heiko W.Rupp <hwr@pilhuhn.de>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Encapsulate L3 protocols into IP
41  * See RFC 1701 and 1702 for more details.
42  * If_gre is compatible with Cisco GRE tunnels, so you can
43  * have a NetBSD box as the other end of a tunnel interface of a Cisco
44  * router. See gre(4) for more details.
45  * Also supported:  IP in IP encaps (proto 55) as of RFC 2004
46  */
47 
48 #include "gre.h"
49 #if NGRE > 0
50 
51 #include "opt_inet.h"
52 #include "opt_ns.h"
53 #include "bpfilter.h"
54 
55 #include <sys/param.h>
56 #include <sys/proc.h>
57 #include <sys/malloc.h>
58 #include <sys/mbuf.h>
59 #include <sys/buf.h>
60 #include <sys/dkstat.h>
61 #include <sys/protosw.h>
62 #include <sys/socket.h>
63 #include <sys/ioctl.h>
64 #include <sys/sockio.h>
65 #include <sys/file.h>
66 #include <sys/tty.h>
67 #include <sys/kernel.h>
68 #include <sys/conf.h>
69 #if __NetBSD__
70 #include <sys/systm.h>
71 #endif
72 
73 #include <machine/cpu.h>
74 
75 #include <net/ethertypes.h>
76 #include <net/if.h>
77 #include <net/if_types.h>
78 #include <net/netisr.h>
79 #include <net/route.h>
80 
81 #ifdef INET
82 #include <netinet/in.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/in_var.h>
85 #include <netinet/ip.h>
86 #include <netinet/ip_var.h>
87 #else
88 #error "Huh? if_gre without inet?"
89 #endif
90 
91 #ifdef NS
92 #include <netns/ns.h>
93 #include <netns/ns_if.h>
94 #endif
95 
96 #ifdef NETATALK
97 #include <netatalk/at.h>
98 #include <netatalk/at_var.h>
99 #include <netatalk/at_extern.h>
100 #endif
101 
102 #if NBPFILTER > 0
103 #include <sys/time.h>
104 #include <net/bpf.h>
105 #endif
106 
107 #include <net/if_gre.h>
108 
109 #define GREMTU 1450	/* XXX this is below the standard MTU of
110                          1500 Bytes, allowing for headers,
111                          but we should possibly do path mtu discovery
112                          before changing if state to up to find the
113                          correct value */
114 #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2)
115 
116 struct gre_softc gre_softc[NGRE];
117 
118 
119 void gre_compute_route(struct gre_softc *sc);
120 #ifdef DIAGNOSTIC
121 void gre_inet_ntoa(struct in_addr in);
122 #endif
123 
124 void
125 greattach(void)
126 {
127 	struct gre_softc *sc;
128 	int i;
129 
130 	i = 0 ;
131 	for (sc = gre_softc ; i < NGRE ; sc++ ) {
132 		sprintf(sc->sc_if.if_xname, "gre%d", i++);
133 		sc->sc_if.if_softc = sc;
134 		sc->sc_if.if_type =  IFT_OTHER;
135 		sc->sc_if.if_addrlen = 4;
136 		sc->sc_if.if_hdrlen = 24; /* IP + GRE */
137 		sc->sc_if.if_mtu = GREMTU;
138 		sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
139 		sc->sc_if.if_output = gre_output;
140 		sc->sc_if.if_ioctl = gre_ioctl;
141 		sc->sc_if.if_collisions = 0;
142 		sc->sc_if.if_ierrors = 0;
143 		sc->sc_if.if_oerrors = 0;
144 		sc->sc_if.if_ipackets = 0;
145 		sc->sc_if.if_opackets = 0;
146 		sc->g_dst.s_addr = sc->g_src.s_addr=INADDR_ANY;
147 		sc->g_proto = IPPROTO_GRE;
148 		if_attach(&sc->sc_if);
149 #if 0
150 #if NBPFILTER > 0
151 		bpfattach(&sc->gre_bpf, &sc->sc_if, DLT_RAW, sizeof(u_int32_t) );
152 #endif
153 #endif
154 
155 	}
156 }
157 
158 
159 /*
160  * The output routine. Takes a packet and encapsulates it in the protocol
161  * given by sc->g_proto. See also RFC 1701 and RFC 2004
162  */
163 
164 #if 0
165 struct ip ip_h;
166 #endif
167 struct mobile_h mob_h;
168 
169 int
170 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
171 	   struct rtentry *rt)
172 {
173 	int error = 0;
174 	struct gre_softc *sc = (struct gre_softc *)(ifp->if_softc);
175 	struct greip *gh;
176 	struct ip *inp;
177 	u_char ttl, osrc;
178 	u_short etype = 0;
179 
180 
181 	gh = NULL;
182 	inp = NULL;
183 	osrc = 0;
184 
185 #if 0
186 #if NBPFILTER >0
187 
188 	if (sc->gre_bpf) {
189 		/* see comment of other if_foo.c files */
190 		struct mbuf m0;
191 		u_int af = dst->sa_family;
192 
193 		m0.m_next = m;
194 		m0.m_len = 4;
195 		m0.m_data = (char *)&af;
196 
197 		bpf_mtap(ifp->if_bpf, &m0);
198 	}
199 #endif
200 #endif
201 
202 	ttl = 255;
203 
204 	if (sc->g_proto == IPPROTO_MOBILE) {
205 		if (dst->sa_family == AF_INET) {
206 			struct mbuf *m0;
207 			int msiz;
208 
209 			inp = mtod(m, struct ip *);
210 
211 			memset(&mob_h, 0, MOB_H_SIZ_L);
212 			mob_h.proto = (inp->ip_p) << 8;
213 			mob_h.odst = inp->ip_dst.s_addr;
214 			inp->ip_dst.s_addr = sc->g_dst.s_addr;
215 
216 			/*
217 			 * If the packet comes from our host, we only change
218 			 * the destination address in the IP header.
219 			 * Else we also need to save and change the source
220 			 */
221 			if (in_hosteq(inp->ip_src, sc->g_src)) {
222 				msiz = MOB_H_SIZ_S;
223 			} else {
224 				mob_h.proto |= MOB_H_SBIT;
225 				mob_h.osrc = inp->ip_src.s_addr;
226 				inp->ip_src.s_addr = sc->g_src.s_addr;
227 				msiz = MOB_H_SIZ_L;
228 			}
229 			HTONS(mob_h.proto);
230 			mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
231 
232 			if ((m->m_data - msiz) < m->m_pktdat) {
233 				/* need new mbuf */
234 				MGETHDR(m0, M_DONTWAIT, MT_HEADER);
235 				if (m0 == NULL) {
236 					IF_DROP(&ifp->if_snd);
237 					m_freem(m);
238 					return (ENOBUFS);
239 				}
240 				m0->m_next = m;
241 				m->m_data += sizeof(struct ip);
242 				m->m_len -= sizeof(struct ip);
243 				m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
244 				m0->m_len = msiz + sizeof(struct ip);
245 				m0->m_data += max_linkhdr;
246 				memcpy(mtod(m0, caddr_t), (caddr_t)inp,
247 				       sizeof(struct ip));
248 				m = m0;
249 			} else {  /* we have some spave left in the old one */
250 				m->m_data -= msiz;
251 				m->m_len += msiz;
252 				m->m_pkthdr.len += msiz;
253 				memmove(mtod(m, caddr_t), inp,
254 					sizeof(struct ip));
255 			}
256 			inp=mtod(m, struct ip *);
257 			memcpy((caddr_t)(inp + 1), &mob_h, (unsigned)msiz);
258 			NTOHS(inp->ip_len);
259 			inp->ip_len += msiz;
260 		} else {  /* AF_INET */
261 			IF_DROP(&ifp->if_snd);
262 			m_freem(m);
263 			return (EINVAL);
264 		}
265 	} else if (sc->g_proto == IPPROTO_GRE) {
266 		switch(dst->sa_family) {
267 		case AF_INET:
268 			inp = mtod(m, struct ip *);
269 			ttl = inp->ip_ttl;
270 			etype = ETHERTYPE_IP;
271 			break;
272 #ifdef NETATALK
273 		case AF_APPLETALK:
274 			etype = ETHERTYPE_ATALK;
275 			break;
276 #endif
277 #ifdef NS
278 		case AF_NS:
279 			etype = ETHERTYPE_NS;
280 			break;
281 #endif
282 		default:
283 			IF_DROP(&ifp->if_snd);
284 			m_freem(m);
285 			return (EAFNOSUPPORT);
286 		}
287 		M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
288 	} else {
289 		error = EINVAL;
290 		IF_DROP(&ifp->if_snd);
291 		m_freem(m);
292 		return (error);
293 	}
294 
295 
296 	if (m == NULL) {
297 		IF_DROP(&ifp->if_snd);
298 		return (ENOBUFS);
299 	}
300 
301 	gh = mtod(m, struct greip *);
302 	if (sc->g_proto == IPPROTO_GRE) {
303 		/* we don't have any GRE flags for now */
304 
305 		memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
306 		gh->gi_ptype = htons(etype);
307 	}
308 
309 	gh->gi_pr = sc->g_proto;
310 	if (sc->g_proto != IPPROTO_MOBILE) {
311 		gh->gi_src = sc->g_src;
312 		gh->gi_dst = sc->g_dst;
313 		((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
314 		((struct ip*)gh)->ip_ttl = ttl;
315 		((struct ip*)gh)->ip_tos = inp->ip_tos;
316 	    gh->gi_len = m->m_pkthdr.len;
317 	}
318 
319 	ifp->if_opackets++;
320 	ifp->if_obytes += m->m_pkthdr.len;
321 	/* send it off */
322 	error = ip_output(m, NULL, &sc->route, 0, NULL);
323 	if (error)
324 		ifp->if_oerrors++;
325 	return (error);
326 
327 }
328 
329 int
330 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
331 {
332 
333 	struct ifaddr *ifa = (struct ifaddr *)data;
334 	struct ifreq *ifr = (struct ifreq *)data;
335 	struct in_ifaddr *ia = (struct in_ifaddr *)data;
336 	struct gre_softc *sc = ifp->if_softc;
337 	int s;
338 	struct sockaddr_in si;
339 	struct sockaddr *sa = NULL;
340 	int error;
341 
342 	error = 0;
343 
344 	s = splimp();
345 	switch(cmd) {
346 	case SIOCSIFADDR:
347 	case SIOCSIFDSTADDR:
348 		/*
349                  * set tunnel endpoints in case that we "only"
350                  * have ip over ip encapsulation. This allows to
351                  * set tunnel endpoints with ifconfig.
352                  */
353 		if (ifa->ifa_addr->sa_family == AF_INET) {
354 			sa = ifa->ifa_addr;
355 			sc->g_src = (satosin(sa))->sin_addr;
356 			sc->g_dst = ia->ia_dstaddr.sin_addr;
357 			if ((sc->g_src.s_addr != INADDR_ANY) &&
358 			    (sc->g_dst.s_addr != INADDR_ANY)) {
359 				if (sc->route.ro_rt != 0) /* free old route */
360 					RTFREE(sc->route.ro_rt);
361 				gre_compute_route(sc);
362 				ifp->if_flags |= IFF_UP;
363 			}
364 		}
365 		break;
366 	case SIOCSIFFLAGS:
367 		if ((sc->g_dst.s_addr == INADDR_ANY) ||
368 		    (sc->g_src.s_addr == INADDR_ANY))
369 			ifp->if_flags &= ~IFF_UP;
370 
371 		switch(ifr->ifr_flags & LINK_MASK) {
372 			case IFF_LINK0:
373 				sc->g_proto = IPPROTO_GRE;
374 				ifp->if_flags |= IFF_LINK0;
375 				ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
376 				break;
377 			case IFF_LINK2:
378 				sc->g_proto = IPPROTO_MOBILE;
379 				ifp->if_flags |= IFF_LINK2;
380 				ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
381 				break;
382 		}
383 		break;
384 	case SIOCSIFMTU:
385 		if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
386 			error = EINVAL;
387 			break;
388 		}
389 		ifp->if_mtu = ifr->ifr_mtu;
390 		break;
391 	case SIOCGIFMTU:
392 		ifr->ifr_mtu = sc->sc_if.if_mtu;
393 		break;
394 	case SIOCADDMULTI:
395 	case SIOCDELMULTI:
396 		if (ifr == 0) {
397 			error = EAFNOSUPPORT;
398 			break;
399 		}
400 		switch (ifr->ifr_addr.sa_family) {
401 #ifdef INET
402 		case AF_INET:
403 			break;
404 #endif
405 		default:
406 			error = EAFNOSUPPORT;
407 			break;
408 		}
409 		break;
410 	case GRESPROTO:
411 		sc->g_proto = ifr->ifr_flags;
412 		switch (sc->g_proto) {
413 		case IPPROTO_GRE :
414 			ifp->if_flags |= IFF_LINK0;
415 			ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
416 			break;
417 		case IPPROTO_MOBILE :
418 			ifp->if_flags |= IFF_LINK2;
419 			ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
420 			break;
421 		default:
422 			ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
423 		}
424 		break;
425 	case GREGPROTO:
426 		ifr->ifr_flags = sc->g_proto;
427 		break;
428 	case GRESADDRS:
429 	case GRESADDRD:
430 		/*
431 	         * set tunnel endpoints, compute a less specific route
432 	         * to the remote end and mark if as up
433                  */
434 		sa = &ifr->ifr_addr;
435 		if (cmd == GRESADDRS )
436 			sc->g_src = (satosin(sa))->sin_addr;
437 		if (cmd == GRESADDRD )
438 			sc->g_dst = (satosin(sa))->sin_addr;
439 		if ((sc->g_src.s_addr != INADDR_ANY) &&
440 		    (sc->g_dst.s_addr != INADDR_ANY)) {
441 			if (sc->route.ro_rt != 0) /* free old route */
442 				RTFREE(sc->route.ro_rt);
443 			gre_compute_route(sc);
444 			ifp->if_flags |= IFF_UP;
445 		}
446 		break;
447 	case GREGADDRS:
448 		si.sin_addr.s_addr = sc->g_src.s_addr;
449 		sa = sintosa(&si);
450 		ifr->ifr_addr = *sa;
451 		break;
452 	case GREGADDRD:
453 		si.sin_addr.s_addr = sc->g_dst.s_addr;
454 		sa = sintosa(&si);
455 		ifr->ifr_addr = *sa;
456 		break;
457 	default:
458 		error = EINVAL;
459 	}
460 
461 	splx(s);
462 	return (error);
463 }
464 
465 /*
466  * computes a route to our destination that is not the one
467  * which would be taken by ip_output(), as this one will loop back to
468  * us. If the interface is p2p as  a--->b, then a routing entry exists
469  * If we now send a packet to b (e.g. ping b), this will come down here
470  * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
471  * if_gre.
472  * Goal here is to compute a route to b that is less specific than
473  * a-->b. We know that this one exists as in normal operation we have
474  * at least a default route which matches.
475  */
476 
477 void
478 gre_compute_route(struct gre_softc *sc)
479 {
480 	struct route *ro;
481 	u_int32_t a, b, c;
482 
483 	ro = &sc->route;
484 
485 	memset(ro, 0, sizeof(struct route));
486 	((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
487 	ro->ro_dst.sa_family = AF_INET;
488 	ro->ro_dst.sa_len = sizeof(ro->ro_dst);
489 
490 	/*
491 	 * toggle last bit, so our interface is not found, but a less
492          * specific route. I'd rather like to specify a shorter mask,
493  	 * but this is not possible. Should work though. XXX
494 	 * there is a simpler way ...
495          */
496 	if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
497 		a = ntohl(sc->g_dst.s_addr);
498 		b = a & 0x01;
499 		c = a & 0xfffffffe;
500 		b = b ^ 0x01;
501 		a = b | c;
502 		((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
503 			= htonl(a);
504 	}
505 
506 #ifdef DIAGNOSTIC
507 	printf("%s: searching a route to ", sc->sc_if.if_xname);
508 	gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
509 #endif
510 
511 	rtalloc(ro);
512 
513 	/*
514 	 * now change it back - else ip_output will just drop
515          * the route and search one to this interface ...
516          */
517 	if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
518 		((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
519 
520 #ifdef DIAGNOSTIC
521 	printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
522 	gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
523 	printf("\n");
524 #endif
525 }
526 
527 /*
528  * do a checksum of a buffer - much like in_cksum, which operates on
529  * mbufs.
530  */
531 
532 u_short
533 gre_in_cksum(u_short *p, u_int len)
534 {
535 	u_int sum = 0;
536 	int nwords = len >> 1;
537 
538 	while (nwords-- != 0)
539 		sum += *p++;
540 
541 		if (len & 1) {
542 			union {
543 				u_short w;
544 				u_char c[2];
545 			} u;
546 			u.c[0] = *(u_char *)p;
547 			u.c[1] = 0;
548 			sum += u.w;
549 		}
550 
551 		/* end-around-carry */
552 		sum = (sum >> 16) + (sum & 0xffff);
553 		sum += (sum >> 16);
554 		return (~sum);
555 }
556 
557 
558 /* while testing ... */
559 #ifdef DIAGNOSTIC
560 void
561 gre_inet_ntoa(struct in_addr in)
562 {
563 	char *p;
564 
565 	p = (char *)&in;
566 #define UC(b)   (((int)b)&0xff)
567 	printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
568 }
569 
570 #endif
571 #endif
572 
573