Annotation of sys/netinet/ip_gre.c, Revision 1.1.1.1
1.1 nbrk 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 */
CVSweb