if_gre.c revision 1.8.2.1 1 /* $NetBSD: if_gre.c,v 1.8.2.1 2000/11/20 18:10:02 bouyer 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 (at) 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/malloc.h>
57 #include <sys/mbuf.h>
58 #include <sys/protosw.h>
59 #include <sys/socket.h>
60 #include <sys/ioctl.h>
61 #include <sys/queue.h>
62 #if __NetBSD__
63 #include <sys/systm.h>
64 #endif
65
66 #include <machine/cpu.h>
67
68 #include <net/ethertypes.h>
69 #include <net/if.h>
70 #include <net/if_types.h>
71 #include <net/netisr.h>
72 #include <net/route.h>
73
74 #ifdef INET
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/in_var.h>
78 #include <netinet/ip.h>
79 #include <netinet/ip_var.h>
80 #else
81 #error "Huh? if_gre without inet?"
82 #endif
83
84 #ifdef NS
85 #include <netns/ns.h>
86 #include <netns/ns_if.h>
87 #endif
88
89 #ifdef NETATALK
90 #include <netatalk/at.h>
91 #include <netatalk/at_var.h>
92 #include <netatalk/at_extern.h>
93 #endif
94
95 #if NBPFILTER > 0
96 #include <sys/time.h>
97 #include <net/bpf.h>
98 #endif
99
100 #include <net/if_gre.h>
101
102 #define GREMTU 1450 /* XXX this is below the standard MTU of
103 1500 Bytes, allowing for headers,
104 but we should possibly do path mtu discovery
105 before changing if state to up to find the
106 correct value */
107 #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2)
108
109 struct gre_softc_head gre_softc_list;
110
111 int gre_clone_create __P((struct if_clone *, int));
112 void gre_clone_destroy __P((struct ifnet *));
113
114 struct if_clone gre_cloner =
115 IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy);
116
117 void gre_compute_route(struct gre_softc *sc);
118 #ifdef DIAGNOSTIC
119 void gre_inet_ntoa(struct in_addr in);
120 #endif
121
122 void greattach __P((int));
123
124 /* ARGSUSED */
125 void
126 greattach(count)
127 int count;
128 {
129
130 LIST_INIT(&gre_softc_list);
131 if_clone_attach(&gre_cloner);
132 }
133
134 int
135 gre_clone_create(ifc, unit)
136 struct if_clone *ifc;
137 int unit;
138 {
139 struct gre_softc *sc;
140
141 sc = malloc(sizeof(struct gre_softc), M_DEVBUF, M_WAITOK);
142 memset(sc, 0, sizeof(struct gre_softc));
143
144 sprintf(sc->sc_if.if_xname, "%s%d", ifc->ifc_name, unit);
145 sc->sc_if.if_softc = sc;
146 sc->sc_if.if_type = IFT_OTHER;
147 sc->sc_if.if_addrlen = 4;
148 sc->sc_if.if_hdrlen = 24; /* IP + GRE */
149 sc->sc_if.if_mtu = GREMTU;
150 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
151 sc->sc_if.if_output = gre_output;
152 sc->sc_if.if_ioctl = gre_ioctl;
153 sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
154 sc->g_proto = IPPROTO_GRE;
155 if_attach(&sc->sc_if);
156 #if NBPFILTER > 0
157 bpfattach(&sc->gre_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int32_t));
158 #endif
159 LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
160 return (0);
161 }
162
163 void
164 gre_clone_destroy(ifp)
165 struct ifnet *ifp;
166 {
167 struct gre_softc *sc = ifp->if_softc;
168
169 LIST_REMOVE(sc, sc_list);
170 #if NBPFILTER > 0
171 bpfdetach(ifp);
172 #endif
173 if_detach(ifp);
174 free(sc, M_DEVBUF);
175 }
176
177 /*
178 * The output routine. Takes a packet and encapsulates it in the protocol
179 * given by sc->g_proto. See also RFC 1701 and RFC 2004
180 */
181
182 #if 0
183 struct ip ip_h;
184 #endif
185 struct mobile_h mob_h;
186
187 int
188 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
189 struct rtentry *rt)
190 {
191 int error = 0;
192 struct gre_softc *sc = ifp->if_softc;
193 struct greip *gh;
194 struct ip *inp;
195 u_char ttl, osrc;
196 u_short etype = 0;
197
198
199 gh = NULL;
200 inp = NULL;
201 osrc = 0;
202
203 #if NBPFILTER >0
204 if (sc->gre_bpf) {
205 /* see comment of other if_foo.c files */
206 struct mbuf m0;
207 u_int af = dst->sa_family;
208
209 m0.m_next = m;
210 m0.m_len = 4;
211 m0.m_data = (char *)⁡
212
213 bpf_mtap(sc->gre_bpf, &m0);
214 }
215 #endif
216
217 ttl = 255;
218
219 if (sc->g_proto == IPPROTO_MOBILE) {
220 if (dst->sa_family == AF_INET) {
221 struct mbuf *m0;
222 int msiz;
223
224 inp = mtod(m, struct ip *);
225
226 memset(&mob_h, 0, MOB_H_SIZ_L);
227 mob_h.proto = (inp->ip_p) << 8;
228 mob_h.odst = inp->ip_dst.s_addr;
229 inp->ip_dst.s_addr = sc->g_dst.s_addr;
230
231 /*
232 * If the packet comes from our host, we only change
233 * the destination address in the IP header.
234 * Else we also need to save and change the source
235 */
236 if (in_hosteq(inp->ip_src, sc->g_src)) {
237 msiz = MOB_H_SIZ_S;
238 } else {
239 mob_h.proto |= MOB_H_SBIT;
240 mob_h.osrc = inp->ip_src.s_addr;
241 inp->ip_src.s_addr = sc->g_src.s_addr;
242 msiz = MOB_H_SIZ_L;
243 }
244 HTONS(mob_h.proto);
245 mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
246
247 if ((m->m_data - msiz) < m->m_pktdat) {
248 /* need new mbuf */
249 MGETHDR(m0, M_DONTWAIT, MT_HEADER);
250 if (m0 == NULL) {
251 IF_DROP(&ifp->if_snd);
252 m_freem(m);
253 return (ENOBUFS);
254 }
255 m0->m_next = m;
256 m->m_data += sizeof(struct ip);
257 m->m_len -= sizeof(struct ip);
258 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
259 m0->m_len = msiz + sizeof(struct ip);
260 m0->m_data += max_linkhdr;
261 memcpy(mtod(m0, caddr_t), (caddr_t)inp,
262 sizeof(struct ip));
263 m = m0;
264 } else { /* we have some spave left in the old one */
265 m->m_data -= msiz;
266 m->m_len += msiz;
267 m->m_pkthdr.len += msiz;
268 memmove(mtod(m, caddr_t), inp,
269 sizeof(struct ip));
270 }
271 inp=mtod(m, struct ip *);
272 memcpy((caddr_t)(inp + 1), &mob_h, (unsigned)msiz);
273 NTOHS(inp->ip_len);
274 inp->ip_len += msiz;
275 } else { /* AF_INET */
276 IF_DROP(&ifp->if_snd);
277 m_freem(m);
278 return (EINVAL);
279 }
280 } else if (sc->g_proto == IPPROTO_GRE) {
281 switch(dst->sa_family) {
282 case AF_INET:
283 inp = mtod(m, struct ip *);
284 ttl = inp->ip_ttl;
285 etype = ETHERTYPE_IP;
286 break;
287 #ifdef NETATALK
288 case AF_APPLETALK:
289 etype = ETHERTYPE_ATALK;
290 break;
291 #endif
292 #ifdef NS
293 case AF_NS:
294 etype = ETHERTYPE_NS;
295 break;
296 #endif
297 default:
298 IF_DROP(&ifp->if_snd);
299 m_freem(m);
300 return (EAFNOSUPPORT);
301 }
302 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
303 } else {
304 error = EINVAL;
305 IF_DROP(&ifp->if_snd);
306 m_freem(m);
307 return (error);
308 }
309
310
311 if (m == NULL) {
312 IF_DROP(&ifp->if_snd);
313 return (ENOBUFS);
314 }
315
316 gh = mtod(m, struct greip *);
317 if (sc->g_proto == IPPROTO_GRE) {
318 /* we don't have any GRE flags for now */
319
320 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
321 gh->gi_ptype = htons(etype);
322 }
323
324 gh->gi_pr = sc->g_proto;
325 if (sc->g_proto != IPPROTO_MOBILE) {
326 gh->gi_src = sc->g_src;
327 gh->gi_dst = sc->g_dst;
328 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
329 ((struct ip*)gh)->ip_ttl = ttl;
330 ((struct ip*)gh)->ip_tos = inp->ip_tos;
331 gh->gi_len = m->m_pkthdr.len;
332 }
333
334 ifp->if_opackets++;
335 ifp->if_obytes += m->m_pkthdr.len;
336 /* send it off */
337 error = ip_output(m, NULL, &sc->route, 0, NULL);
338 if (error)
339 ifp->if_oerrors++;
340 return (error);
341
342 }
343
344 int
345 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
346 {
347
348 struct ifaddr *ifa = (struct ifaddr *)data;
349 struct ifreq *ifr = (struct ifreq *)data;
350 struct in_ifaddr *ia = (struct in_ifaddr *)data;
351 struct gre_softc *sc = ifp->if_softc;
352 int s;
353 struct sockaddr_in si;
354 struct sockaddr *sa = NULL;
355 int error;
356
357 error = 0;
358
359 s = splimp();
360 switch(cmd) {
361 case SIOCSIFADDR:
362 case SIOCSIFDSTADDR:
363 /*
364 * set tunnel endpoints in case that we "only"
365 * have ip over ip encapsulation. This allows to
366 * set tunnel endpoints with ifconfig.
367 */
368 if (ifa->ifa_addr->sa_family == AF_INET) {
369 sa = ifa->ifa_addr;
370 sc->g_src = (satosin(sa))->sin_addr;
371 sc->g_dst = ia->ia_dstaddr.sin_addr;
372 if ((sc->g_src.s_addr != INADDR_ANY) &&
373 (sc->g_dst.s_addr != INADDR_ANY)) {
374 if (sc->route.ro_rt != 0) /* free old route */
375 RTFREE(sc->route.ro_rt);
376 gre_compute_route(sc);
377 ifp->if_flags |= IFF_UP;
378 }
379 }
380 break;
381 case SIOCSIFFLAGS:
382 if ((sc->g_dst.s_addr == INADDR_ANY) ||
383 (sc->g_src.s_addr == INADDR_ANY))
384 ifp->if_flags &= ~IFF_UP;
385
386 switch(ifr->ifr_flags & LINK_MASK) {
387 case IFF_LINK0:
388 sc->g_proto = IPPROTO_GRE;
389 ifp->if_flags |= IFF_LINK0;
390 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
391 break;
392 case IFF_LINK2:
393 sc->g_proto = IPPROTO_MOBILE;
394 ifp->if_flags |= IFF_LINK2;
395 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
396 break;
397 }
398 break;
399 case SIOCSIFMTU:
400 if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) {
401 error = EINVAL;
402 break;
403 }
404 ifp->if_mtu = ifr->ifr_mtu;
405 break;
406 case SIOCGIFMTU:
407 ifr->ifr_mtu = sc->sc_if.if_mtu;
408 break;
409 case SIOCADDMULTI:
410 case SIOCDELMULTI:
411 if (ifr == 0) {
412 error = EAFNOSUPPORT;
413 break;
414 }
415 switch (ifr->ifr_addr.sa_family) {
416 #ifdef INET
417 case AF_INET:
418 break;
419 #endif
420 default:
421 error = EAFNOSUPPORT;
422 break;
423 }
424 break;
425 case GRESPROTO:
426 sc->g_proto = ifr->ifr_flags;
427 switch (sc->g_proto) {
428 case IPPROTO_GRE :
429 ifp->if_flags |= IFF_LINK0;
430 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
431 break;
432 case IPPROTO_MOBILE :
433 ifp->if_flags |= IFF_LINK2;
434 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
435 break;
436 default:
437 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
438 }
439 break;
440 case GREGPROTO:
441 ifr->ifr_flags = sc->g_proto;
442 break;
443 case GRESADDRS:
444 case GRESADDRD:
445 /*
446 * set tunnel endpoints, compute a less specific route
447 * to the remote end and mark if as up
448 */
449 sa = &ifr->ifr_addr;
450 if (cmd == GRESADDRS )
451 sc->g_src = (satosin(sa))->sin_addr;
452 if (cmd == GRESADDRD )
453 sc->g_dst = (satosin(sa))->sin_addr;
454 if ((sc->g_src.s_addr != INADDR_ANY) &&
455 (sc->g_dst.s_addr != INADDR_ANY)) {
456 if (sc->route.ro_rt != 0) /* free old route */
457 RTFREE(sc->route.ro_rt);
458 gre_compute_route(sc);
459 ifp->if_flags |= IFF_UP;
460 }
461 break;
462 case GREGADDRS:
463 si.sin_addr.s_addr = sc->g_src.s_addr;
464 sa = sintosa(&si);
465 ifr->ifr_addr = *sa;
466 break;
467 case GREGADDRD:
468 si.sin_addr.s_addr = sc->g_dst.s_addr;
469 sa = sintosa(&si);
470 ifr->ifr_addr = *sa;
471 break;
472 default:
473 error = EINVAL;
474 }
475
476 splx(s);
477 return (error);
478 }
479
480 /*
481 * computes a route to our destination that is not the one
482 * which would be taken by ip_output(), as this one will loop back to
483 * us. If the interface is p2p as a--->b, then a routing entry exists
484 * If we now send a packet to b (e.g. ping b), this will come down here
485 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
486 * if_gre.
487 * Goal here is to compute a route to b that is less specific than
488 * a-->b. We know that this one exists as in normal operation we have
489 * at least a default route which matches.
490 */
491
492 void
493 gre_compute_route(struct gre_softc *sc)
494 {
495 struct route *ro;
496 u_int32_t a, b, c;
497
498 ro = &sc->route;
499
500 memset(ro, 0, sizeof(struct route));
501 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
502 ro->ro_dst.sa_family = AF_INET;
503 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
504
505 /*
506 * toggle last bit, so our interface is not found, but a less
507 * specific route. I'd rather like to specify a shorter mask,
508 * but this is not possible. Should work though. XXX
509 * there is a simpler way ...
510 */
511 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
512 a = ntohl(sc->g_dst.s_addr);
513 b = a & 0x01;
514 c = a & 0xfffffffe;
515 b = b ^ 0x01;
516 a = b | c;
517 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
518 = htonl(a);
519 }
520
521 #ifdef DIAGNOSTIC
522 printf("%s: searching a route to ", sc->sc_if.if_xname);
523 gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
524 #endif
525
526 rtalloc(ro);
527
528 /*
529 * now change it back - else ip_output will just drop
530 * the route and search one to this interface ...
531 */
532 if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
533 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
534
535 #ifdef DIAGNOSTIC
536 printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
537 gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
538 printf("\n");
539 #endif
540 }
541
542 /*
543 * do a checksum of a buffer - much like in_cksum, which operates on
544 * mbufs.
545 */
546
547 u_short
548 gre_in_cksum(u_short *p, u_int len)
549 {
550 u_int sum = 0;
551 int nwords = len >> 1;
552
553 while (nwords-- != 0)
554 sum += *p++;
555
556 if (len & 1) {
557 union {
558 u_short w;
559 u_char c[2];
560 } u;
561 u.c[0] = *(u_char *)p;
562 u.c[1] = 0;
563 sum += u.w;
564 }
565
566 /* end-around-carry */
567 sum = (sum >> 16) + (sum & 0xffff);
568 sum += (sum >> 16);
569 return (~sum);
570 }
571
572
573 /* while testing ... */
574 #ifdef DIAGNOSTIC
575 void
576 gre_inet_ntoa(struct in_addr in)
577 {
578 char *p;
579
580 p = (char *)∈
581 #define UC(b) (((int)b)&0xff)
582 printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
583 }
584
585 #endif
586 #endif
587
588