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