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