1 /* $NetBSD: if_gre.c,v 1.42 2002/08/14 00:23:27 itojun Exp $ */
2 /* $FreeBSD: src/sys/net/if_gre.c,v 1.9.2.3 2003/01/23 21:06:44 sam Exp $ */
3
4 /*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Heiko W.Rupp <hwr@pilhuhn.de>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Encapsulate L3 protocols into IP
42 * See RFC 1701 and 1702 for more details.
43 * If_gre is compatible with Cisco GRE tunnels, so you can
44 * have a NetBSD box as the other end of a tunnel interface of a Cisco
45 * router. See gre(4) for more details.
46 * Also supported: IP in IP encaps (proto 55) as of RFC 2004
47 */
48
49 #include "opt_inet.h"
50
51 #include <sys/param.h>
52 #include <sys/kernel.h>
53 #include <sys/bus.h>
54 #include <sys/malloc.h>
55 #include <sys/mbuf.h>
56 #include <sys/proc.h>
57 #include <sys/caps.h>
58 #include <sys/protosw.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/sysctl.h>
62 #include <sys/systm.h>
63 #include <sys/thread2.h>
64
65 #include <net/ethernet.h>
66 #include <net/if.h>
67 #include <net/if_types.h>
68 #include <net/ifq_var.h>
69 #include <net/route.h>
70 #include <net/if_clone.h>
71 #include <net/netmsg2.h>
72 #include <net/netisr2.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_gre.h>
80 #include <netinet/ip_var.h>
81 #include <netinet/ip_encap.h>
82 #else
83 #error "Huh? if_gre without inet?"
84 #endif
85
86 #include <net/bpf.h>
87
88 #include <net/net_osdep.h>
89 #include "if_gre.h"
90
91 /*
92 * It is not easy to calculate the right value for a GRE MTU.
93 * We leave this task to the admin and use the same default that
94 * other vendors use.
95 */
96 #define GREMTU 1476
97
98 #define GRENAME "gre"
99
100 #define MTAG_GRE 1709049137 /* mtag cookie for nesting check */
101
102 static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation");
103
104 struct gre_softc_head gre_softc_list;
105
106 static int gre_clone_create(struct if_clone *, int, caddr_t, caddr_t);
107 static int gre_clone_destroy(struct ifnet *);
108 static int gre_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
109 static int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
110 struct rtentry *rt);
111
112 static struct if_clone gre_cloner = IF_CLONE_INITIALIZER("gre",
113 gre_clone_create, gre_clone_destroy, 0, IF_MAXUNIT);
114
115 static int gre_compute_route(struct gre_softc *sc, struct route *);
116 static int gre_check_route(struct gre_softc *sc);
117
118 static void greattach(void);
119
120 #ifdef INET
121
122 extern struct domain inetdomain;
123
124 static const struct protosw in_gre_protosw =
125 {
126 .pr_type = SOCK_RAW,
127 .pr_domain = &inetdomain,
128 .pr_protocol = IPPROTO_GRE,
129 .pr_flags = PR_ATOMIC|PR_ADDR,
130
131 .pr_input = gre_input,
132 .pr_output = rip_output,
133 .pr_ctlinput = NULL,
134 .pr_ctloutput = rip_ctloutput,
135
136 .pr_ctlport = NULL,
137 .pr_usrreqs = &rip_usrreqs
138 };
139
140 static const struct protosw in_mobile_protosw =
141 {
142 .pr_type = SOCK_RAW,
143 .pr_domain = &inetdomain,
144 .pr_protocol = IPPROTO_MOBILE,
145 .pr_flags = PR_ATOMIC|PR_ADDR,
146
147 .pr_input = gre_mobile_input,
148 .pr_output = rip_output,
149 .pr_ctlinput = NULL,
150 .pr_ctloutput = rip_ctloutput,
151
152 .pr_ctlport = NULL,
153 .pr_usrreqs = &rip_usrreqs
154 };
155
156 #endif
157
158 SYSCTL_DECL(_net_link);
159 SYSCTL_NODE(_net_link, IFT_OTHER, gre, CTLFLAG_RW, 0,
160 "Generic Routing Encapsulation");
161 #ifndef MAX_GRE_NEST
162 /*
163 * This macro controls the default upper limitation on nesting of gre tunnels.
164 * Since, setting a large value to this macro with a careless configuration
165 * may introduce system crash, we don't allow any nestings by default.
166 * If you need to configure nested gre tunnels, you can define this macro
167 * in your kernel configuration file. However, if you do so, please be
168 * careful to configure the tunnels so that it won't make a loop.
169 */
170 #define MAX_GRE_NEST 1
171 #endif
172 static int max_gre_nesting = MAX_GRE_NEST;
173 SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW,
174 &max_gre_nesting, 0, "Max nested tunnels");
175
176 /* ARGSUSED */
177 static void
greattach(void)178 greattach(void)
179 {
180
181 LIST_INIT(&gre_softc_list);
182 if_clone_attach(&gre_cloner);
183 }
184
185 static int
gre_clone_create(struct if_clone * ifc,int unit,caddr_t params __unused,caddr_t data __unused)186 gre_clone_create(struct if_clone *ifc, int unit,
187 caddr_t params __unused, caddr_t data __unused)
188 {
189 struct gre_softc *sc;
190
191 sc = kmalloc(sizeof(struct gre_softc), M_GRE, M_WAITOK);
192 memset(sc, 0, sizeof(struct gre_softc));
193
194 sc->sc_if.if_softc = sc;
195 if_initname(&(sc->sc_if), GRENAME, unit);
196 ifq_set_maxlen(&sc->sc_if.if_snd, IFQ_MAXLEN);
197 sc->sc_if.if_type = IFT_OTHER;
198 sc->sc_if.if_addrlen = 0;
199 sc->sc_if.if_hdrlen = 24; /* IP + GRE */
200 sc->sc_if.if_mtu = GREMTU;
201 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
202 sc->sc_if.if_output = gre_output;
203 sc->sc_if.if_ioctl = gre_ioctl;
204 sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
205 sc->g_proto = IPPROTO_GRE;
206 sc->sc_if.if_flags |= IFF_LINK0;
207 sc->encap = NULL;
208 sc->route_pcpu = kmalloc(netisr_ncpus * sizeof(struct route), M_GRE,
209 M_WAITOK | M_ZERO);
210 if_attach(&sc->sc_if, NULL);
211 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int32_t));
212 LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
213 return (0);
214 }
215
216 static int
gre_clone_destroy(struct ifnet * ifp)217 gre_clone_destroy(struct ifnet *ifp)
218 {
219 struct gre_softc *sc = ifp->if_softc;
220 int cpu;
221
222 #ifdef INET
223 if (sc->encap != NULL)
224 encap_detach(sc->encap);
225 #endif
226 LIST_REMOVE(sc, sc_list);
227 bpfdetach(ifp);
228 if_detach(ifp);
229
230 for (cpu = 0; cpu < netisr_ncpus; ++cpu) {
231 if (sc->route_pcpu[cpu].ro_rt != NULL) {
232 rtfree_async(sc->route_pcpu[cpu].ro_rt);
233 sc->route_pcpu[cpu].ro_rt = NULL;
234 }
235 }
236 kfree(sc->route_pcpu, M_GRE);
237 kfree(sc, M_GRE);
238
239 return 0;
240 }
241
242 /*
243 * The output routine. Takes a packet and encapsulates it in the protocol
244 * given by sc->g_proto. See also RFC 1701 and RFC 2004
245 */
246 static int
gre_output_serialized(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)247 gre_output_serialized(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
248 struct rtentry *rt)
249 {
250 int error = 0;
251 struct gre_softc *sc = ifp->if_softc;
252 struct greip *gh;
253 struct ip *ip;
254 u_short etype = 0;
255 struct mobile_h mob_h;
256 struct route *ro;
257 struct sockaddr_in *ro_dst;
258
259 ASSERT_NETISR_NCPUS(mycpuid);
260
261 error = if_tunnel_check_nesting(ifp, m, MTAG_GRE, max_gre_nesting);
262 if (error != 0) {
263 m_freem(m);
264 goto end;
265 }
266
267 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 ||
268 sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
269 m_freem(m);
270 error = ENETDOWN;
271 goto end;
272 }
273
274 ro = &sc->route_pcpu[mycpuid];
275 ro_dst = (struct sockaddr_in *)&ro->ro_dst;
276 if (ro->ro_rt != NULL &&
277 ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
278 ro_dst->sin_addr.s_addr != sc->g_dst.s_addr)) {
279 RTFREE(ro->ro_rt);
280 ro->ro_rt = NULL;
281 }
282 if (ro->ro_rt == NULL) {
283 error = gre_compute_route(sc, ro);
284 if (error) {
285 m_freem(m);
286 goto end;
287 }
288 }
289
290 gh = NULL;
291 ip = NULL;
292
293 if (ifp->if_bpf) {
294 bpf_gettoken();
295 if (ifp->if_bpf) {
296 uint32_t af = dst->sa_family;
297
298 bpf_ptap(ifp->if_bpf, m, &af, sizeof(af));
299 }
300 bpf_reltoken();
301 }
302
303 m->m_flags &= ~(M_BCAST|M_MCAST);
304
305 if (sc->g_proto == IPPROTO_MOBILE) {
306 if (dst->sa_family == AF_INET) {
307 struct mbuf *m0;
308 int msiz;
309
310 ip = mtod(m, struct ip *);
311
312 /*
313 * RFC2004 specifies that fragmented datagrams shouldn't
314 * be encapsulated.
315 */
316 if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
317 m_freem(m);
318 error = EINVAL; /* is there better errno? */
319 goto end;
320 }
321 memset(&mob_h, 0, MOB_H_SIZ_L);
322 mob_h.proto = (ip->ip_p) << 8;
323 mob_h.odst = ip->ip_dst.s_addr;
324 ip->ip_dst.s_addr = sc->g_dst.s_addr;
325
326 /*
327 * If the packet comes from our host, we only change
328 * the destination address in the IP header.
329 * Else we also need to save and change the source
330 */
331 if (in_hosteq(ip->ip_src, sc->g_src)) {
332 msiz = MOB_H_SIZ_S;
333 } else {
334 mob_h.proto |= MOB_H_SBIT;
335 mob_h.osrc = ip->ip_src.s_addr;
336 ip->ip_src.s_addr = sc->g_src.s_addr;
337 msiz = MOB_H_SIZ_L;
338 }
339 mob_h.proto = htons(mob_h.proto);
340 mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
341
342 if ((m->m_data - msiz) < m->m_pktdat) {
343 /* need new mbuf */
344 MGETHDR(m0, M_NOWAIT, MT_HEADER);
345 if (m0 == NULL) {
346 m_freem(m);
347 error = ENOBUFS;
348 goto end;
349 }
350 m0->m_next = m;
351 m->m_data += sizeof(struct ip);
352 m->m_len -= sizeof(struct ip);
353 m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
354 m0->m_len = msiz + sizeof(struct ip);
355 m0->m_data += max_linkhdr;
356 memcpy(mtod(m0, caddr_t), (caddr_t)ip,
357 sizeof(struct ip));
358 m = m0;
359 } else { /* we have some space left in the old one */
360 m->m_data -= msiz;
361 m->m_len += msiz;
362 m->m_pkthdr.len += msiz;
363 bcopy(ip, mtod(m, caddr_t),
364 sizeof(struct ip));
365 }
366 ip = mtod(m, struct ip *);
367 memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
368 ip->ip_len = htons(ntohs(ip->ip_len) + msiz);
369 } else { /* AF_INET */
370 m_freem(m);
371 error = EINVAL;
372 goto end;
373 }
374 } else if (sc->g_proto == IPPROTO_GRE) {
375 switch (dst->sa_family) {
376 case AF_INET:
377 ip = mtod(m, struct ip *);
378 etype = ETHERTYPE_IP;
379 break;
380 default:
381 m_freem(m);
382 error = EAFNOSUPPORT;
383 goto end;
384 }
385 M_PREPEND(m, sizeof(struct greip), M_NOWAIT);
386 } else {
387 m_freem(m);
388 error = EINVAL;
389 goto end;
390 }
391
392 if (m == NULL) { /* impossible */
393 error = ENOBUFS;
394 goto end;
395 }
396
397 gh = mtod(m, struct greip *);
398 if (sc->g_proto == IPPROTO_GRE) {
399 /* we don't have any GRE flags for now */
400
401 memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
402 gh->gi_ptype = htons(etype);
403 }
404
405 gh->gi_pr = sc->g_proto;
406 if (sc->g_proto != IPPROTO_MOBILE) {
407 gh->gi_src = sc->g_src;
408 gh->gi_dst = sc->g_dst;
409 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
410 ((struct ip*)gh)->ip_ttl = GRE_TTL;
411 ((struct ip*)gh)->ip_tos = ip->ip_tos;
412 ((struct ip*)gh)->ip_id = ip->ip_id;
413 gh->gi_len = htons(m->m_pkthdr.len);
414 }
415
416 IFNET_STAT_INC(ifp, opackets, 1);
417 IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
418 /* send it off */
419 error = ip_output(m, NULL, ro, IP_DEBUGROUTE, NULL, NULL);
420 end:
421 if (error)
422 IFNET_STAT_INC(ifp, oerrors, 1);
423 return (error);
424 }
425
426 static int
gre_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)427 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
428 struct rtentry *rt)
429 {
430 struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd);
431 int error;
432
433 ifsq_serialize_hw(ifsq);
434 error = gre_output_serialized(ifp, m, dst, rt);
435 ifsq_deserialize_hw(ifsq);
436
437 return error;
438 }
439
440 static int
gre_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)441 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
442 {
443 struct ifreq *ifr = (struct ifreq *)data;
444 struct if_laddrreq *lifr = (struct if_laddrreq *)data;
445 struct in_aliasreq *aifr = (struct in_aliasreq *)data;
446 struct gre_softc *sc = ifp->if_softc;
447 struct sockaddr_in si;
448 struct sockaddr *sa = NULL;
449 int error;
450 struct sockaddr_in sp, sm, dp, dm;
451
452 error = 0;
453
454 crit_enter();
455 switch (cmd) {
456 case SIOCSIFADDR:
457 ifp->if_flags |= IFF_UP;
458 break;
459 case SIOCSIFDSTADDR:
460 break;
461 case SIOCSIFFLAGS:
462 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
463 __SYSCAP_NULLCRED);
464 if (error)
465 break;
466 if ((ifr->ifr_flags & IFF_LINK0) != 0)
467 sc->g_proto = IPPROTO_GRE;
468 else
469 sc->g_proto = IPPROTO_MOBILE;
470 goto recompute;
471 case SIOCSIFMTU:
472 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
473 __SYSCAP_NULLCRED);
474 if (error)
475 break;
476 if (ifr->ifr_mtu < 576) {
477 error = EINVAL;
478 break;
479 }
480 ifp->if_mtu = ifr->ifr_mtu;
481 break;
482 case SIOCGIFMTU:
483 ifr->ifr_mtu = sc->sc_if.if_mtu;
484 break;
485 case SIOCADDMULTI:
486 case SIOCDELMULTI:
487 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
488 __SYSCAP_NULLCRED);
489 if (error)
490 break;
491 if (ifr == NULL) {
492 error = EAFNOSUPPORT;
493 break;
494 }
495 switch (ifr->ifr_addr.sa_family) {
496 #ifdef INET
497 case AF_INET:
498 break;
499 #endif
500 default:
501 error = EAFNOSUPPORT;
502 break;
503 }
504 break;
505 case GRESPROTO:
506 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
507 __SYSCAP_NULLCRED);
508 if (error)
509 break;
510 sc->g_proto = ifr->ifr_flags;
511 switch (sc->g_proto) {
512 case IPPROTO_GRE:
513 ifp->if_flags |= IFF_LINK0;
514 break;
515 case IPPROTO_MOBILE:
516 ifp->if_flags &= ~IFF_LINK0;
517 break;
518 default:
519 error = EPROTONOSUPPORT;
520 break;
521 }
522 goto recompute;
523 case GREGPROTO:
524 ifr->ifr_flags = sc->g_proto;
525 break;
526 case GRESADDRS:
527 case GRESADDRD:
528 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
529 __SYSCAP_NULLCRED);
530 if (error)
531 break;
532 /*
533 * set tunnel endpoints, compute a less specific route
534 * to the remote end and mark if as up
535 */
536 sa = &ifr->ifr_addr;
537 if (cmd == GRESADDRS)
538 sc->g_src = (satosin(sa))->sin_addr;
539 if (cmd == GRESADDRD)
540 sc->g_dst = (satosin(sa))->sin_addr;
541 recompute:
542 #ifdef INET
543 if (sc->encap != NULL) {
544 encap_detach(sc->encap);
545 sc->encap = NULL;
546 }
547 #endif
548 if ((sc->g_src.s_addr != INADDR_ANY) &&
549 (sc->g_dst.s_addr != INADDR_ANY)) {
550 bzero(&sp, sizeof(sp));
551 bzero(&sm, sizeof(sm));
552 bzero(&dp, sizeof(dp));
553 bzero(&dm, sizeof(dm));
554 sp.sin_len = sm.sin_len = dp.sin_len = dm.sin_len =
555 sizeof(struct sockaddr_in);
556 sp.sin_family = sm.sin_family = dp.sin_family =
557 dm.sin_family = AF_INET;
558 sp.sin_addr = sc->g_src;
559 dp.sin_addr = sc->g_dst;
560 sm.sin_addr.s_addr = dm.sin_addr.s_addr =
561 INADDR_BROADCAST;
562 #ifdef INET
563 sc->encap = encap_attach(AF_INET, sc->g_proto,
564 sintosa(&sp), sintosa(&sm), sintosa(&dp),
565 sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ?
566 &in_gre_protosw : &in_mobile_protosw, sc);
567 if (sc->encap == NULL)
568 kprintf("%s: unable to attach encap\n",
569 if_name(&sc->sc_if));
570 #endif
571 ifnet_deserialize_all(ifp);
572 error = gre_check_route(sc);
573 ifnet_serialize_all(ifp);
574 if (!error)
575 ifp->if_flags |= IFF_RUNNING;
576 else
577 ifp->if_flags &= ~IFF_RUNNING;
578 }
579 break;
580 case GREGADDRS:
581 memset(&si, 0, sizeof(si));
582 si.sin_family = AF_INET;
583 si.sin_len = sizeof(struct sockaddr_in);
584 si.sin_addr.s_addr = sc->g_src.s_addr;
585 sa = sintosa(&si);
586 ifr->ifr_addr = *sa;
587 break;
588 case GREGADDRD:
589 memset(&si, 0, sizeof(si));
590 si.sin_family = AF_INET;
591 si.sin_len = sizeof(struct sockaddr_in);
592 si.sin_addr.s_addr = sc->g_dst.s_addr;
593 sa = sintosa(&si);
594 ifr->ifr_addr = *sa;
595 break;
596 case SIOCSIFPHYADDR:
597 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
598 __SYSCAP_NULLCRED);
599 if (error)
600 break;
601 if (aifr->ifra_addr.sin_family != AF_INET ||
602 aifr->ifra_dstaddr.sin_family != AF_INET)
603 {
604 error = EAFNOSUPPORT;
605 break;
606 }
607 if (aifr->ifra_addr.sin_len != sizeof(si) ||
608 aifr->ifra_dstaddr.sin_len != sizeof(si))
609 {
610 error = EINVAL;
611 break;
612 }
613 sc->g_src = aifr->ifra_addr.sin_addr;
614 sc->g_dst = aifr->ifra_dstaddr.sin_addr;
615 goto recompute;
616 case SIOCSLIFPHYADDR:
617 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
618 __SYSCAP_NULLCRED);
619 if (error)
620 break;
621 if (lifr->addr.ss_family != AF_INET ||
622 lifr->dstaddr.ss_family != AF_INET) {
623 error = EAFNOSUPPORT;
624 break;
625 }
626 if (lifr->addr.ss_len != sizeof(si) ||
627 lifr->dstaddr.ss_len != sizeof(si)) {
628 error = EINVAL;
629 break;
630 }
631 sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
632 sc->g_dst =
633 (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
634 goto recompute;
635 case SIOCDIFPHYADDR:
636 error = caps_priv_check(cr, SYSCAP_RESTRICTEDROOT |
637 __SYSCAP_NULLCRED);
638 if (error)
639 break;
640 sc->g_src.s_addr = INADDR_ANY;
641 sc->g_dst.s_addr = INADDR_ANY;
642 goto recompute;
643 case SIOCGLIFPHYADDR:
644 if (sc->g_src.s_addr == INADDR_ANY ||
645 sc->g_dst.s_addr == INADDR_ANY) {
646 error = EADDRNOTAVAIL;
647 break;
648 }
649 memset(&si, 0, sizeof(si));
650 si.sin_family = AF_INET;
651 si.sin_len = sizeof(struct sockaddr_in);
652 si.sin_addr.s_addr = sc->g_src.s_addr;
653 memcpy(&lifr->addr, &si, sizeof(si));
654 si.sin_addr.s_addr = sc->g_dst.s_addr;
655 memcpy(&lifr->dstaddr, &si, sizeof(si));
656 break;
657 case SIOCGIFPSRCADDR:
658 if (sc->g_src.s_addr == INADDR_ANY) {
659 error = EADDRNOTAVAIL;
660 break;
661 }
662 memset(&si, 0, sizeof(si));
663 si.sin_family = AF_INET;
664 si.sin_len = sizeof(struct sockaddr_in);
665 si.sin_addr.s_addr = sc->g_src.s_addr;
666 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
667 break;
668 case SIOCGIFPDSTADDR:
669 if (sc->g_dst.s_addr == INADDR_ANY) {
670 error = EADDRNOTAVAIL;
671 break;
672 }
673 memset(&si, 0, sizeof(si));
674 si.sin_family = AF_INET;
675 si.sin_len = sizeof(struct sockaddr_in);
676 si.sin_addr.s_addr = sc->g_dst.s_addr;
677 bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
678 break;
679 default:
680 error = EINVAL;
681 break;
682 }
683
684 crit_exit();
685 return (error);
686 }
687
688 /*
689 * computes a route to our destination that is not the one
690 * which would be taken by ip_output(), as this one will loop back to
691 * us. If the interface is p2p as a--->b, then a routing entry exists
692 * If we now send a packet to b (e.g. ping b), this will come down here
693 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
694 * if_gre.
695 * Goal here is to compute a route to b that is less specific than
696 * a-->b. We know that this one exists as in normal operation we have
697 * at least a default route which matches.
698 */
699 static int
gre_compute_route(struct gre_softc * sc,struct route * ro)700 gre_compute_route(struct gre_softc *sc, struct route *ro)
701 {
702 #ifdef DIAGNOSTIC
703 char abuf[INET_ADDRSTRLEN];
704 #endif
705 u_int32_t a, b, c;
706
707 ASSERT_NETISR_NCPUS(mycpuid);
708 KASSERT(ro == &sc->route_pcpu[mycpuid], ("route mismatch"));
709 KASSERT(ro->ro_rt == NULL, ("rtentry not freed"));
710
711 memset(ro, 0, sizeof(struct route));
712 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
713 ro->ro_dst.sa_family = AF_INET;
714 ro->ro_dst.sa_len = sizeof(ro->ro_dst);
715
716 /*
717 * toggle last bit, so our interface is not found, but a less
718 * specific route. I'd rather like to specify a shorter mask,
719 * but this is not possible. Should work though. XXX
720 * there is a simpler way ...
721 */
722 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
723 a = ntohl(sc->g_dst.s_addr);
724 b = a & 0x01;
725 c = a & 0xfffffffe;
726 b = b ^ 0x01;
727 a = b | c;
728 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
729 = htonl(a);
730 }
731
732 #ifdef DIAGNOSTIC
733 kprintf("%s: searching a route to %s", if_name(&sc->sc_if),
734 kinet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr, abuf));
735 #endif
736
737 rtalloc(ro);
738
739 /*
740 * check if this returned a route at all and this route is no
741 * recursion to ourself
742 */
743 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp->if_softc == sc) {
744 #ifdef DIAGNOSTIC
745 if (ro->ro_rt == NULL)
746 kprintf(" - no route found!\n");
747 else
748 kprintf(" - route loops back to ourself!\n");
749 #endif
750 return EADDRNOTAVAIL;
751 }
752
753 /*
754 * now change it back - else ip_output will just drop
755 * the route and search one to this interface ...
756 */
757 if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
758 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
759
760 #ifdef DIAGNOSTIC
761 kprintf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp),
762 kinet_ntoa(
763 ((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr, abuf));
764 kprintf("\n");
765 #endif
766
767 return 0;
768 }
769
770 static void
gre_check_route_handler(netmsg_t msg)771 gre_check_route_handler(netmsg_t msg)
772 {
773 struct gre_softc *sc = msg->base.lmsg.u.ms_resultp;
774 struct route *ro;
775 int error;
776
777 ASSERT_NETISR0;
778
779 ro = &sc->route_pcpu[mycpuid];
780 if (ro->ro_rt != NULL) {
781 RTFREE(ro->ro_rt);
782 ro->ro_rt = NULL;
783 }
784 error = gre_compute_route(sc, ro);
785
786 netisr_replymsg(&msg->base, error);
787 }
788
789 static int
gre_check_route(struct gre_softc * sc)790 gre_check_route(struct gre_softc *sc)
791 {
792 struct netmsg_base msg;
793
794 netmsg_init(&msg, NULL, &curthread->td_msgport, MSGF_PRIORITY,
795 gre_check_route_handler);
796 msg.lmsg.u.ms_resultp = sc;
797
798 return (netisr_domsg(&msg, 0));
799 }
800
801 /*
802 * do a checksum of a buffer - much like in_cksum, which operates on
803 * mbufs.
804 */
805 u_short
gre_in_cksum(u_short * p,u_int len)806 gre_in_cksum(u_short *p, u_int len)
807 {
808 u_int sum = 0;
809 int nwords = len >> 1;
810
811 while (nwords-- != 0)
812 sum += *p++;
813
814 if (len & 1) {
815 union {
816 u_short w;
817 u_char c[2];
818 } u;
819 u.c[0] = *(u_char *)p;
820 u.c[1] = 0;
821 sum += u.w;
822 }
823
824 /* end-around-carry */
825 sum = (sum >> 16) + (sum & 0xffff);
826 sum += (sum >> 16);
827 return (~sum);
828 }
829
830 static int
gremodevent(module_t mod,int type,void * data)831 gremodevent(module_t mod, int type, void *data)
832 {
833
834 switch (type) {
835 case MOD_LOAD:
836 greattach();
837 break;
838 case MOD_UNLOAD:
839 if_clone_detach(&gre_cloner);
840
841 while (!LIST_EMPTY(&gre_softc_list))
842 gre_clone_destroy(&LIST_FIRST(&gre_softc_list)->sc_if);
843
844 break;
845 }
846 return 0;
847 }
848
849 static moduledata_t gre_mod = {
850 "if_gre",
851 gremodevent,
852 0
853 };
854
855 DECLARE_MODULE(if_gre, gre_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
856 MODULE_VERSION(if_gre, 1);
857