FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_gre.c
1 /* $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun 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 * deencapsulate tunneled packets and send them on
41 * output half is in net/if_gre.[ch]
42 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE
43 */
44
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $");
47
48 #include "gre.h"
49 #if NGRE > 0
50
51 #include "opt_inet.h"
52 #include "opt_ns.h"
53 #include "opt_atalk.h"
54 #include "bpfilter.h"
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/mbuf.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/protosw.h>
62 #include <sys/errno.h>
63 #include <sys/time.h>
64 #include <sys/kernel.h>
65 #include <sys/ioctl.h>
66 #include <sys/syslog.h>
67 #include <net/bpf.h>
68 #include <net/ethertypes.h>
69 #include <net/if.h>
70 #include <net/netisr.h>
71 #include <net/route.h>
72 #include <net/raw_cb.h>
73
74 #ifdef INET
75 #include <netinet/in.h>
76 #include <netinet/in_var.h>
77 #include <netinet/in_systm.h>
78 #include <netinet/ip.h>
79 #include <netinet/ip_var.h>
80 #include <netinet/ip_gre.h>
81 #else
82 #error ip_gre input without IP?
83 #endif
84
85 #ifdef NS
86 #include <netns/ns.h>
87 #include <netns/ns_if.h>
88 #endif
89
90 #ifdef NETATALK
91 #include <netatalk/at.h>
92 #include <netatalk/at_var.h>
93 #include <netatalk/at_extern.h>
94 #endif
95
96 /* Needs IP headers. */
97 #include <net/if_gre.h>
98
99 #include <machine/stdarg.h>
100
101 #if 1
102 void gre_inet_ntoa(struct in_addr in); /* XXX */
103 #endif
104
105 struct gre_softc *gre_lookup __P((struct mbuf *, u_int8_t));
106
107 int gre_input2 __P((struct mbuf *, int, u_char));
108
109 /*
110 * De-encapsulate a packet and feed it back through ip input (this
111 * routine is called whenever IP gets a packet with proto type
112 * IPPROTO_GRE and a local destination address).
113 * This really is simple
114 */
115 void
116 #if __STDC__
117 gre_input(struct mbuf *m, ...)
118 #else
119 gre_input(m, va_alist)
120 struct mbuf *m;
121 va_dcl
122 #endif
123 {
124 int off, ret, proto;
125 va_list ap;
126
127 va_start(ap, m);
128 off = va_arg(ap, int);
129 proto = va_arg(ap, int);
130 va_end(ap);
131
132 ret = gre_input2(m, off, proto);
133 /*
134 * ret == 0 : packet not processed, meaning that
135 * no matching tunnel that is up is found.
136 * we inject it to raw ip socket to see if anyone picks it up.
137 */
138 if (ret == 0)
139 rip_input(m, off, proto);
140 }
141
142 /*
143 * decapsulate.
144 * Does the real work and is called from gre_input() (above)
145 * returns 0 if packet is not yet processed
146 * and 1 if it needs no further processing
147 * proto is the protocol number of the "calling" foo_input()
148 * routine.
149 */
150 int
151 gre_input2(struct mbuf *m, int hlen, u_char proto)
152 {
153 struct greip *gip;
154 int s;
155 struct ifqueue *ifq;
156 struct gre_softc *sc;
157 u_int16_t flags;
158
159 if ((sc = gre_lookup(m, proto)) == NULL) {
160 /* No matching tunnel or tunnel is down. */
161 return (0);
162 }
163
164 if (m->m_len < sizeof(*gip)) {
165 m = m_pullup(m, sizeof(*gip));
166 if (m == NULL)
167 return (ENOBUFS);
168 }
169 gip = mtod(m, struct greip *);
170
171 sc->sc_if.if_ipackets++;
172 sc->sc_if.if_ibytes += m->m_pkthdr.len;
173
174 switch (proto) {
175 case IPPROTO_GRE:
176 hlen += sizeof(struct gre_h);
177
178 /* process GRE flags as packet can be of variable len */
179 flags = ntohs(gip->gi_flags);
180
181 /* Checksum & Offset are present */
182 if ((flags & GRE_CP) | (flags & GRE_RP))
183 hlen += 4;
184 /* We don't support routing fields (variable length) */
185 if (flags & GRE_RP)
186 return (0);
187 if (flags & GRE_KP)
188 hlen += 4;
189 if (flags & GRE_SP)
190 hlen += 4;
191
192 switch (ntohs(gip->gi_ptype)) { /* ethertypes */
193 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */
194 ifq = &ipintrq; /* we are in ip_input */
195 break;
196 #ifdef NS
197 case ETHERTYPE_NS:
198 ifq = &nsintrq;
199 schednetisr(NETISR_NS);
200 break;
201 #endif
202 #ifdef NETATALK
203 case ETHERTYPE_ATALK:
204 ifq = &atintrq1;
205 schednetisr(NETISR_ATALK);
206 break;
207 #endif
208 case ETHERTYPE_IPV6:
209 /* FALLTHROUGH */
210 default: /* others not yet supported */
211 return (0);
212 }
213 break;
214 default:
215 /* others not yet supported */
216 return (0);
217 }
218
219 if (hlen > m->m_pkthdr.len) {
220 m_freem(m);
221 return (EINVAL);
222 }
223 m_adj(m, hlen);
224
225 #if NBPFILTER > 0
226 if (sc->sc_if.if_bpf) {
227 struct mbuf m0;
228 u_int32_t af = AF_INET;
229
230 m0.m_flags = 0;
231 m0.m_next = m;
232 m0.m_len = 4;
233 m0.m_data = (char *)⁡
234
235 bpf_mtap(sc->sc_if.if_bpf, &m0);
236 }
237 #endif /*NBPFILTER > 0*/
238
239 m->m_pkthdr.rcvif = &sc->sc_if;
240
241 s = splnet(); /* possible */
242 if (IF_QFULL(ifq)) {
243 IF_DROP(ifq);
244 m_freem(m);
245 } else {
246 IF_ENQUEUE(ifq, m);
247 }
248 splx(s);
249
250 return (1); /* packet is done, no further processing needed */
251 }
252
253 /*
254 * input routine for IPPRPOTO_MOBILE
255 * This is a little bit diffrent from the other modes, as the
256 * encapsulating header was not prepended, but instead inserted
257 * between IP header and payload
258 */
259 void
260 #if __STDC__
261 gre_mobile_input(struct mbuf *m, ...)
262 #else
263 gre_mobile_input(m, va_alist)
264 struct mbuf *m;
265 va_dcl
266 #endif
267 {
268 struct ip *ip;
269 struct mobip_h *mip;
270 struct ifqueue *ifq;
271 struct gre_softc *sc;
272 int hlen, s;
273 va_list ap;
274 int msiz;
275
276 va_start(ap, m);
277 hlen = va_arg(ap, int);
278 va_end(ap);
279
280 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
281 /* No matching tunnel or tunnel is down. */
282 m_freem(m);
283 return;
284 }
285
286 if (m->m_len < sizeof(*mip)) {
287 m = m_pullup(m, sizeof(*mip));
288 if (m == NULL)
289 return;
290 }
291 ip = mtod(m, struct ip *);
292 mip = mtod(m, struct mobip_h *);
293
294 sc->sc_if.if_ipackets++;
295 sc->sc_if.if_ibytes += m->m_pkthdr.len;
296
297 if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
298 msiz = MOB_H_SIZ_L;
299 mip->mi.ip_src.s_addr = mip->mh.osrc;
300 } else
301 msiz = MOB_H_SIZ_S;
302
303 if (m->m_len < (ip->ip_hl << 2) + msiz) {
304 m = m_pullup(m, (ip->ip_hl << 2) + msiz);
305 if (m == NULL)
306 return;
307 ip = mtod(m, struct ip *);
308 mip = mtod(m, struct mobip_h *);
309 }
310
311 mip->mi.ip_dst.s_addr = mip->mh.odst;
312 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
313
314 if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) {
315 m_freem(m);
316 return;
317 }
318
319 memmove(ip + (ip->ip_hl << 2), ip + (ip->ip_hl << 2) + msiz,
320 m->m_len - msiz - (ip->ip_hl << 2));
321 m->m_len -= msiz;
322 ip->ip_len = htons(ntohs(ip->ip_len) - msiz);
323 m->m_pkthdr.len -= msiz;
324
325 ip->ip_sum = 0;
326 ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
327
328 #if NBPFILTER > 0
329 if (sc->sc_if.if_bpf) {
330 struct mbuf m0;
331 u_int af = AF_INET;
332
333 m0.m_next = m;
334 m0.m_len = 4;
335 m0.m_data = (char *)⁡
336
337 bpf_mtap(sc->sc_if.if_bpf, &m0);
338 }
339 #endif /*NBPFILTER > 0*/
340
341 ifq = &ipintrq;
342 s = splnet(); /* possible */
343 if (IF_QFULL(ifq)) {
344 IF_DROP(ifq);
345 m_freem(m);
346 } else {
347 IF_ENQUEUE(ifq, m);
348 }
349 splx(s);
350 }
351
352 /*
353 * Find the gre interface associated with our src/dst/proto set.
354 */
355 struct gre_softc *
356 gre_lookup(m, proto)
357 struct mbuf *m;
358 u_int8_t proto;
359 {
360 struct ip *ip = mtod(m, struct ip *);
361 struct gre_softc *sc;
362
363 for (sc = LIST_FIRST(&gre_softc_list); sc != NULL;
364 sc = LIST_NEXT(sc, sc_list)) {
365 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
366 (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
367 (sc->g_proto == proto) &&
368 ((sc->sc_if.if_flags & IFF_UP) != 0))
369 return (sc);
370 }
371
372 return (NULL);
373 }
374
375 #endif /* if NGRE > 0 */
Cache object: 77e316edfcbe860c1fe5ca3bf06a7d7a
|