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