xref: /openbsd-src/sys/netinet/ip_gre.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*      $OpenBSD: ip_gre.c,v 1.32 2008/06/26 05:42:20 ray Exp $ */
2 /*	$NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
3 
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Heiko W.Rupp <hwr@pilhuhn.de>
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * decapsulate tunneled packets and send them on
35  * output half is in net/if_gre.[ch]
36  * This currently handles IPPROTO_GRE, IPPROTO_MOBILE
37  */
38 
39 
40 #include "gre.h"
41 #if NGRE > 0
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <net/if.h>
49 #include <net/netisr.h>
50 #include <net/route.h>
51 #include <net/bpf.h>
52 
53 #ifdef INET
54 #include <netinet/in.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/ip_gre.h>
60 #include <netinet/if_ether.h>
61 #else
62 #error "ip_gre used without inet"
63 #endif
64 
65 #ifdef NETATALK
66 #include <netatalk/at.h>
67 #include <netatalk/at_var.h>
68 #include <netatalk/at_extern.h>
69 #endif
70 
71 #include "bpfilter.h"
72 
73 /* Needs IP headers. */
74 #include <net/if_gre.h>
75 
76 struct gre_softc *gre_lookup(struct mbuf *, u_int8_t);
77 int gre_input2(struct mbuf *, int, u_char);
78 
79 /*
80  * Decapsulate.
81  * Does the real work and is called from gre_input() (above)
82  * returns 0 if packet is not yet processed
83  * and 1 if it needs no further processing
84  * proto is the protocol number of the "calling" foo_input()
85  * routine.
86  */
87 
88 int
89 gre_input2(m , hlen, proto)
90         struct mbuf *m;
91 	int hlen;
92 	u_char proto;
93 {
94 	struct greip *gip;
95 	int s;
96 	struct ifqueue *ifq;
97 	struct gre_softc *sc;
98 	u_short flags;
99 	u_int af;
100 
101 	if ((sc = gre_lookup(m, proto)) == NULL) {
102 		/* No matching tunnel or tunnel is down. */
103 		return (0);
104 	}
105 
106 	if (m->m_len < sizeof(*gip)) {
107 		m = m_pullup(m, sizeof(*gip));
108 		if (m == NULL)
109 			return (ENOBUFS);
110 	}
111 	gip = mtod(m, struct greip *);
112 
113 	m->m_pkthdr.rcvif = &sc->sc_if;
114 
115 	sc->sc_if.if_ipackets++;
116 	sc->sc_if.if_ibytes += m->m_pkthdr.len;
117 
118 	switch (proto) {
119 	case IPPROTO_GRE:
120 		hlen += sizeof (struct gre_h);
121 
122 		/* process GRE flags as packet can be of variable len */
123 		flags = ntohs(gip->gi_flags);
124 
125 		/* Checksum & Offset are present */
126 		if ((flags & GRE_CP) | (flags & GRE_RP))
127 			hlen += 4;
128 
129 		/* We don't support routing fields (variable length) */
130 		if (flags & GRE_RP)
131 			return (0);
132 
133 		if (flags & GRE_KP)
134 			hlen += 4;
135 
136 		if (flags & GRE_SP)
137 			hlen += 4;
138 
139 		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
140 		case GREPROTO_WCCP:
141 			/* WCCP/GRE:
142 			 *   So far as I can see (and test) it seems that Cisco's WCCP
143 			 *   GRE tunnel is precisely a IP-in-GRE tunnel that differs
144 			 *   only in its protocol number.  At least, it works for me.
145 			 *
146 			 *   The Internet Draft can be found if you look for
147 			 *     draft-forster-wrec-wccp-v1-00.txt
148 			 *
149 			 *   So yes, we're doing a fall-through (unless, of course,
150 			 *   net.inet.gre.wccp is 0).
151 			 */
152 			if (!gre_wccp)
153 				return (0);
154 		case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */
155 			ifq = &ipintrq;          /* we are in ip_input */
156 			af = AF_INET;
157 			break;
158 #ifdef NETATALK
159 		case ETHERTYPE_AT:
160 			ifq = &atintrq1;
161 			schednetisr(NETISR_ATALK);
162 			af = AF_APPLETALK;
163 			break;
164 #endif
165 #ifdef INET6
166 		case ETHERTYPE_IPV6:
167 		        ifq = &ip6intrq;
168 			schednetisr(NETISR_IPV6);
169 			af = AF_INET6;
170 			break;
171 #endif /* INET6 */
172 		default:	   /* others not yet supported */
173 			return (0);
174 		}
175 		break;
176 	default:
177 		/* others not yet supported */
178 		return (0);
179 	}
180 
181 	if (hlen > m->m_pkthdr.len) {
182 		m_freem(m);
183 		return (EINVAL);
184 	}
185 	m_adj(m, hlen);
186 
187 #if NBPFILTER > 0
188         if (sc->sc_if.if_bpf)
189 		bpf_mtap_af(sc->sc_if.if_bpf, af, m, BPF_DIRECTION_IN);
190 #endif
191 
192 	s = splnet();		/* possible */
193 	IF_INPUT_ENQUEUE(ifq, m);
194 	splx(s);
195 
196 	return (1);	/* packet is done, no further processing needed */
197 }
198 
199 /*
200  * Decapsulate a packet and feed it back through ip_input (this
201  * routine is called whenever IP gets a packet with proto type
202  * IPPROTO_GRE and a local destination address).
203  */
204 void
205 gre_input(struct mbuf *m, ...)
206 {
207 	int hlen, ret;
208 	va_list ap;
209 
210 	va_start(ap, m);
211 	hlen = va_arg(ap, int);
212 	va_end(ap);
213 
214 	if (!gre_allow) {
215 	        m_freem(m);
216 		return;
217 	}
218 
219 	ret = gre_input2(m, hlen, IPPROTO_GRE);
220 	/*
221 	 * ret == 0: packet not processed, but input from here
222 	 * means no matching tunnel that is up is found.
223 	 * we inject it to raw ip socket to see if anyone picks it up.
224 	 * possible that we received a WCCPv1-style GRE packet
225 	 * but we're not set to accept them.
226 	 */
227 	if (!ret)
228 		rip_input(m, hlen, IPPROTO_GRE);
229 }
230 
231 /*
232  * Input routine for IPPRPOTO_MOBILE.
233  * This is a little bit diffrent from the other modes, as the
234  * encapsulating header was not prepended, but instead inserted
235  * between IP header and payload.
236  */
237 
238 void
239 gre_mobile_input(struct mbuf *m, ...)
240 {
241 	struct ip *ip;
242 	struct mobip_h *mip;
243 	struct ifqueue *ifq;
244 	struct gre_softc *sc;
245 	int hlen, s;
246 	va_list ap;
247 	u_char osrc = 0;
248 	int msiz;
249 
250 	va_start(ap, m);
251 	hlen = va_arg(ap, int);
252 	va_end(ap);
253 
254 	if (!ip_mobile_allow) {
255 	        m_freem(m);
256 		return;
257 	}
258 
259 	if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
260 		/* No matching tunnel or tunnel is down. */
261 		m_freem(m);
262 		return;
263 	}
264 
265 	if (m->m_len < sizeof(*mip)) {
266 		m = m_pullup(m, sizeof(*mip));
267 		if (m == NULL)
268 			return;
269 	}
270 	ip = mtod(m, struct ip *);
271 	mip = mtod(m, struct mobip_h *);
272 
273 	m->m_pkthdr.rcvif = &sc->sc_if;
274 
275 	sc->sc_if.if_ipackets++;
276 	sc->sc_if.if_ibytes += m->m_pkthdr.len;
277 
278 	if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
279 		osrc = 1;
280 		msiz = MOB_H_SIZ_L;
281 		mip->mi.ip_src.s_addr = mip->mh.osrc;
282 	} else
283 		msiz = MOB_H_SIZ_S;
284 
285 	if (m->m_len < (ip->ip_hl << 2) + msiz) {
286 		m = m_pullup(m, (ip->ip_hl << 2) + msiz);
287 		if (m == NULL)
288 			return;
289 		ip = mtod(m, struct ip *);
290 		mip = mtod(m, struct mobip_h *);
291 	}
292 
293 	mip->mi.ip_dst.s_addr = mip->mh.odst;
294 	mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
295 
296 	if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) {
297 		m_freem(m);
298 		return;
299 	}
300 
301 	bcopy(ip + (ip->ip_hl << 2) + msiz, ip + (ip->ip_hl << 2),
302 	      m->m_len - msiz - (ip->ip_hl << 2));
303 
304 	m->m_len -= msiz;
305 	ip->ip_len = htons(ntohs(ip->ip_len) - msiz);
306 	m->m_pkthdr.len -= msiz;
307 
308 	ip->ip_sum = 0;
309 	ip->ip_sum = in_cksum(m,(ip->ip_hl << 2));
310 
311 	ifq = &ipintrq;
312 
313 #if NBPFILTER > 0
314         if (sc->sc_if.if_bpf)
315 		bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN);
316 #endif
317 
318 	s = splnet();       /* possible */
319 	IF_INPUT_ENQUEUE(ifq, m);
320 	splx(s);
321 }
322 
323 /*
324  * Find the gre interface associated with our src/dst/proto set.
325  */
326 struct gre_softc *
327 gre_lookup(m, proto)
328 	struct mbuf *m;
329 	u_int8_t proto;
330 {
331 	struct ip *ip = mtod(m, struct ip *);
332 	struct gre_softc *sc;
333 
334 	LIST_FOREACH(sc, &gre_softc_list, sc_list) {
335 		if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
336 		    (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
337 		    (sc->g_proto == proto) &&
338 		    ((sc->sc_if.if_flags & IFF_UP) != 0))
339 			return (sc);
340 	}
341 
342 	return (NULL);
343 }
344 
345 int
346 gre_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
347         int *name;
348         u_int namelen;
349         void *oldp;
350         size_t *oldlenp;
351         void *newp;
352         size_t newlen;
353 {
354         /* All sysctl names at this level are terminal. */
355         if (namelen != 1)
356                 return (ENOTDIR);
357 
358         switch (name[0]) {
359         case GRECTL_ALLOW:
360                 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_allow));
361         case GRECTL_WCCP:
362                 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_wccp));
363         default:
364                 return (ENOPROTOOPT);
365         }
366         /* NOTREACHED */
367 }
368 
369 int
370 ipmobile_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
371         int *name;
372         u_int namelen;
373         void *oldp;
374         size_t *oldlenp;
375         void *newp;
376         size_t newlen;
377 {
378         /* All sysctl names at this level are terminal. */
379         if (namelen != 1)
380                 return (ENOTDIR);
381 
382         switch (name[0]) {
383         case MOBILEIPCTL_ALLOW:
384                 return (sysctl_int(oldp, oldlenp, newp, newlen,
385 				   &ip_mobile_allow));
386         default:
387                 return (ENOPROTOOPT);
388         }
389         /* NOTREACHED */
390 }
391 #endif /* if NGRE > 0 */
392