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