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