FreeBSD/Linux Kernel Cross Reference
sys/net/if_gif.c
1 /* $FreeBSD: releng/5.0/sys/net/if_gif.c 106939 2002-11-15 00:00:15Z sam $ */
2 /* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include "opt_inet.h"
34 #include "opt_inet6.h"
35 #include "opt_mac.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/mac.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <sys/sysctl.h>
48 #include <sys/syslog.h>
49 #include <sys/protosw.h>
50 #include <sys/conf.h>
51 #include <machine/cpu.h>
52
53 #include <net/if.h>
54 #include <net/if_types.h>
55 #include <net/netisr.h>
56 #include <net/route.h>
57 #include <net/bpf.h>
58
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/ip.h>
62 #ifdef INET
63 #include <netinet/in_var.h>
64 #include <netinet/in_gif.h>
65 #include <netinet/ip_var.h>
66 #endif /* INET */
67
68 #ifdef INET6
69 #ifndef INET
70 #include <netinet/in.h>
71 #endif
72 #include <netinet6/in6_var.h>
73 #include <netinet/ip6.h>
74 #include <netinet6/ip6_var.h>
75 #include <netinet6/in6_gif.h>
76 #include <netinet6/ip6protosw.h>
77 #endif /* INET6 */
78
79 #include <netinet/ip_encap.h>
80 #include <net/if_gif.h>
81
82 #include <net/net_osdep.h>
83
84 #define GIFNAME "gif"
85
86 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
87 static LIST_HEAD(, gif_softc) gif_softc_list;
88
89 void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
90 void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
91 void (*ng_gif_attach_p)(struct ifnet *ifp);
92 void (*ng_gif_detach_p)(struct ifnet *ifp);
93
94 int gif_clone_create(struct if_clone *, int);
95 void gif_clone_destroy(struct ifnet *);
96
97 struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
98 gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
99
100 static int gifmodevent(module_t, int, void *);
101
102 SYSCTL_DECL(_net_link);
103 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
104 "Generic Tunnel Interface");
105 #ifndef MAX_GIF_NEST
106 /*
107 * This macro controls the default upper limitation on nesting of gif tunnels.
108 * Since, setting a large value to this macro with a careless configuration
109 * may introduce system crash, we don't allow any nestings by default.
110 * If you need to configure nested gif tunnels, you can define this macro
111 * in your kernel configuration file. However, if you do so, please be
112 * careful to configure the tunnels so that it won't make a loop.
113 */
114 #define MAX_GIF_NEST 1
115 #endif
116 static int max_gif_nesting = MAX_GIF_NEST;
117 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
118 &max_gif_nesting, 0, "Max nested tunnels");
119
120 /*
121 * By default, we disallow creation of multiple tunnels between the same
122 * pair of addresses. Some applications require this functionality so
123 * we allow control over this check here.
124 */
125 #ifdef XBONEHACK
126 static int parallel_tunnels = 1;
127 #else
128 static int parallel_tunnels = 0;
129 #endif
130 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
131 ¶llel_tunnels, 0, "Allow parallel tunnels?");
132
133 int
134 gif_clone_create(ifc, unit)
135 struct if_clone *ifc;
136 int unit;
137 {
138 struct gif_softc *sc;
139
140 sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
141 bzero(sc, sizeof(struct gif_softc));
142
143 sc->gif_if.if_softc = sc;
144 sc->gif_if.if_name = GIFNAME;
145 sc->gif_if.if_unit = unit;
146
147 gifattach0(sc);
148
149 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
150 return (0);
151 }
152
153 void
154 gifattach0(sc)
155 struct gif_softc *sc;
156 {
157
158 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
159
160 sc->gif_if.if_addrlen = 0;
161 sc->gif_if.if_mtu = GIF_MTU;
162 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
163 #if 0
164 /* turn off ingress filter */
165 sc->gif_if.if_flags |= IFF_LINK2;
166 #endif
167 sc->gif_if.if_ioctl = gif_ioctl;
168 sc->gif_if.if_output = gif_output;
169 sc->gif_if.if_type = IFT_GIF;
170 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
171 if_attach(&sc->gif_if);
172 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
173 if (ng_gif_attach_p != NULL)
174 (*ng_gif_attach_p)(&sc->gif_if);
175 }
176
177 void
178 gif_clone_destroy(ifp)
179 struct ifnet *ifp;
180 {
181 int err;
182 struct gif_softc *sc = ifp->if_softc;
183
184 gif_delete_tunnel(&sc->gif_if);
185 LIST_REMOVE(sc, gif_list);
186 #ifdef INET6
187 if (sc->encap_cookie6 != NULL) {
188 err = encap_detach(sc->encap_cookie6);
189 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
190 }
191 #endif
192 #ifdef INET
193 if (sc->encap_cookie4 != NULL) {
194 err = encap_detach(sc->encap_cookie4);
195 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
196 }
197 #endif
198
199 if (ng_gif_detach_p != NULL)
200 (*ng_gif_detach_p)(ifp);
201 bpfdetach(ifp);
202 if_detach(ifp);
203
204 free(sc, M_GIF);
205 }
206
207 static int
208 gifmodevent(mod, type, data)
209 module_t mod;
210 int type;
211 void *data;
212 {
213
214 switch (type) {
215 case MOD_LOAD:
216 LIST_INIT(&gif_softc_list);
217 if_clone_attach(&gif_cloner);
218
219 #ifdef INET6
220 ip6_gif_hlim = GIF_HLIM;
221 #endif
222
223 break;
224 case MOD_UNLOAD:
225 if_clone_detach(&gif_cloner);
226
227 while (!LIST_EMPTY(&gif_softc_list))
228 gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
229
230 #ifdef INET6
231 ip6_gif_hlim = 0;
232 #endif
233 break;
234 }
235 return 0;
236 }
237
238 static moduledata_t gif_mod = {
239 "if_gif",
240 gifmodevent,
241 0
242 };
243
244 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
245 MODULE_VERSION(if_gif, 1);
246
247 int
248 gif_encapcheck(m, off, proto, arg)
249 const struct mbuf *m;
250 int off;
251 int proto;
252 void *arg;
253 {
254 struct ip ip;
255 struct gif_softc *sc;
256
257 sc = (struct gif_softc *)arg;
258 if (sc == NULL)
259 return 0;
260
261 if ((sc->gif_if.if_flags & IFF_UP) == 0)
262 return 0;
263
264 /* no physical address */
265 if (!sc->gif_psrc || !sc->gif_pdst)
266 return 0;
267
268 switch (proto) {
269 #ifdef INET
270 case IPPROTO_IPV4:
271 break;
272 #endif
273 #ifdef INET6
274 case IPPROTO_IPV6:
275 break;
276 #endif
277 default:
278 return 0;
279 }
280
281 /* Bail on short packets */
282 if (m->m_pkthdr.len < sizeof(ip))
283 return 0;
284
285 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
286
287 switch (ip.ip_v) {
288 #ifdef INET
289 case 4:
290 if (sc->gif_psrc->sa_family != AF_INET ||
291 sc->gif_pdst->sa_family != AF_INET)
292 return 0;
293 return gif_encapcheck4(m, off, proto, arg);
294 #endif
295 #ifdef INET6
296 case 6:
297 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
298 return 0;
299 if (sc->gif_psrc->sa_family != AF_INET6 ||
300 sc->gif_pdst->sa_family != AF_INET6)
301 return 0;
302 return gif_encapcheck6(m, off, proto, arg);
303 #endif
304 default:
305 return 0;
306 }
307 }
308
309 int
310 gif_output(ifp, m, dst, rt)
311 struct ifnet *ifp;
312 struct mbuf *m;
313 struct sockaddr *dst;
314 struct rtentry *rt; /* added in net2 */
315 {
316 struct gif_softc *sc = (struct gif_softc*)ifp;
317 int error = 0;
318 static int called = 0; /* XXX: MUTEX */
319
320 #ifdef MAC
321 error = mac_check_ifnet_transmit(ifp, m);
322 if (error) {
323 m_freem(m);
324 goto end;
325 }
326 #endif
327
328 /*
329 * gif may cause infinite recursion calls when misconfigured.
330 * We'll prevent this by introducing upper limit.
331 * XXX: this mechanism may introduce another problem about
332 * mutual exclusion of the variable CALLED, especially if we
333 * use kernel thread.
334 */
335 if (++called > max_gif_nesting) {
336 log(LOG_NOTICE,
337 "gif_output: recursively called too many times(%d)\n",
338 called);
339 m_freem(m);
340 error = EIO; /* is there better errno? */
341 goto end;
342 }
343
344 m->m_flags &= ~(M_BCAST|M_MCAST);
345 if (!(ifp->if_flags & IFF_UP) ||
346 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
347 m_freem(m);
348 error = ENETDOWN;
349 goto end;
350 }
351
352 if (ifp->if_bpf) {
353 /*
354 * We need to prepend the address family as
355 * a four byte field. Cons up a dummy header
356 * to pacify bpf. This is safe because bpf
357 * will only read from the mbuf (i.e., it won't
358 * try to free it or keep a pointer a to it).
359 */
360 struct mbuf m0;
361 u_int32_t af = dst->sa_family;
362
363 m0.m_next = m;
364 m0.m_len = 4;
365 m0.m_data = (char *)⁡
366
367 BPF_MTAP(ifp, &m0);
368 }
369 ifp->if_opackets++;
370 ifp->if_obytes += m->m_pkthdr.len;
371
372 /* inner AF-specific encapsulation */
373
374 /* XXX should we check if our outer source is legal? */
375
376 /* dispatch to output logic based on outer AF */
377 switch (sc->gif_psrc->sa_family) {
378 #ifdef INET
379 case AF_INET:
380 error = in_gif_output(ifp, dst->sa_family, m);
381 break;
382 #endif
383 #ifdef INET6
384 case AF_INET6:
385 error = in6_gif_output(ifp, dst->sa_family, m);
386 break;
387 #endif
388 default:
389 m_freem(m);
390 error = ENETDOWN;
391 goto end;
392 }
393
394 end:
395 called = 0; /* reset recursion counter */
396 if (error)
397 ifp->if_oerrors++;
398 return error;
399 }
400
401 void
402 gif_input(m, af, ifp)
403 struct mbuf *m;
404 int af;
405 struct ifnet *ifp;
406 {
407 int isr;
408 struct ifqueue *ifq = NULL;
409
410 if (ifp == NULL) {
411 /* just in case */
412 m_freem(m);
413 return;
414 }
415
416 m->m_pkthdr.rcvif = ifp;
417
418 #ifdef MAC
419 mac_create_mbuf_from_ifnet(ifp, m);
420 #endif
421
422 if (ifp->if_bpf) {
423 /*
424 * We need to prepend the address family as
425 * a four byte field. Cons up a dummy header
426 * to pacify bpf. This is safe because bpf
427 * will only read from the mbuf (i.e., it won't
428 * try to free it or keep a pointer a to it).
429 */
430 struct mbuf m0;
431 u_int32_t af1 = af;
432
433 m0.m_next = m;
434 m0.m_len = 4;
435 m0.m_data = (char *)&af1;
436
437 BPF_MTAP(ifp, &m0);
438 }
439
440 if (ng_gif_input_p != NULL) {
441 (*ng_gif_input_p)(ifp, &m, af);
442 if (m == NULL)
443 return;
444 }
445
446 /*
447 * Put the packet to the network layer input queue according to the
448 * specified address family.
449 * Note: older versions of gif_input directly called network layer
450 * input functions, e.g. ip6_input, here. We changed the policy to
451 * prevent too many recursive calls of such input functions, which
452 * might cause kernel panic. But the change may introduce another
453 * problem; if the input queue is full, packets are discarded.
454 * The kernel stack overflow really happened, and we believed
455 * queue-full rarely occurs, so we changed the policy.
456 */
457 switch (af) {
458 #ifdef INET
459 case AF_INET:
460 ifq = &ipintrq;
461 isr = NETISR_IP;
462 break;
463 #endif
464 #ifdef INET6
465 case AF_INET6:
466 ifq = &ip6intrq;
467 isr = NETISR_IPV6;
468 break;
469 #endif
470 default:
471 if (ng_gif_input_orphan_p != NULL)
472 (*ng_gif_input_orphan_p)(ifp, m, af);
473 else
474 m_freem(m);
475 return;
476 }
477
478 ifp->if_ipackets++;
479 ifp->if_ibytes += m->m_pkthdr.len;
480 (void) IF_HANDOFF(ifq, m, NULL);
481 /* we need schednetisr since the address family may change */
482 schednetisr(isr);
483
484 return;
485 }
486
487 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
488 int
489 gif_ioctl(ifp, cmd, data)
490 struct ifnet *ifp;
491 u_long cmd;
492 caddr_t data;
493 {
494 struct gif_softc *sc = (struct gif_softc*)ifp;
495 struct ifreq *ifr = (struct ifreq*)data;
496 int error = 0, size;
497 struct sockaddr *dst, *src;
498 #ifdef SIOCSIFMTU /* xxx */
499 u_long mtu;
500 #endif
501
502 switch (cmd) {
503 case SIOCSIFADDR:
504 ifp->if_flags |= IFF_UP;
505 break;
506
507 case SIOCSIFDSTADDR:
508 break;
509
510 case SIOCADDMULTI:
511 case SIOCDELMULTI:
512 break;
513
514 #ifdef SIOCSIFMTU /* xxx */
515 case SIOCGIFMTU:
516 break;
517
518 case SIOCSIFMTU:
519 mtu = ifr->ifr_mtu;
520 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
521 return (EINVAL);
522 ifp->if_mtu = mtu;
523 break;
524 #endif /* SIOCSIFMTU */
525
526 #ifdef INET
527 case SIOCSIFPHYADDR:
528 #endif
529 #ifdef INET6
530 case SIOCSIFPHYADDR_IN6:
531 #endif /* INET6 */
532 case SIOCSLIFPHYADDR:
533 switch (cmd) {
534 #ifdef INET
535 case SIOCSIFPHYADDR:
536 src = (struct sockaddr *)
537 &(((struct in_aliasreq *)data)->ifra_addr);
538 dst = (struct sockaddr *)
539 &(((struct in_aliasreq *)data)->ifra_dstaddr);
540 break;
541 #endif
542 #ifdef INET6
543 case SIOCSIFPHYADDR_IN6:
544 src = (struct sockaddr *)
545 &(((struct in6_aliasreq *)data)->ifra_addr);
546 dst = (struct sockaddr *)
547 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
548 break;
549 #endif
550 case SIOCSLIFPHYADDR:
551 src = (struct sockaddr *)
552 &(((struct if_laddrreq *)data)->addr);
553 dst = (struct sockaddr *)
554 &(((struct if_laddrreq *)data)->dstaddr);
555 break;
556 default:
557 return EINVAL;
558 }
559
560 /* sa_family must be equal */
561 if (src->sa_family != dst->sa_family)
562 return EINVAL;
563
564 /* validate sa_len */
565 switch (src->sa_family) {
566 #ifdef INET
567 case AF_INET:
568 if (src->sa_len != sizeof(struct sockaddr_in))
569 return EINVAL;
570 break;
571 #endif
572 #ifdef INET6
573 case AF_INET6:
574 if (src->sa_len != sizeof(struct sockaddr_in6))
575 return EINVAL;
576 break;
577 #endif
578 default:
579 return EAFNOSUPPORT;
580 }
581 switch (dst->sa_family) {
582 #ifdef INET
583 case AF_INET:
584 if (dst->sa_len != sizeof(struct sockaddr_in))
585 return EINVAL;
586 break;
587 #endif
588 #ifdef INET6
589 case AF_INET6:
590 if (dst->sa_len != sizeof(struct sockaddr_in6))
591 return EINVAL;
592 break;
593 #endif
594 default:
595 return EAFNOSUPPORT;
596 }
597
598 /* check sa_family looks sane for the cmd */
599 switch (cmd) {
600 case SIOCSIFPHYADDR:
601 if (src->sa_family == AF_INET)
602 break;
603 return EAFNOSUPPORT;
604 #ifdef INET6
605 case SIOCSIFPHYADDR_IN6:
606 if (src->sa_family == AF_INET6)
607 break;
608 return EAFNOSUPPORT;
609 #endif /* INET6 */
610 case SIOCSLIFPHYADDR:
611 /* checks done in the above */
612 break;
613 }
614
615 error = gif_set_tunnel(&sc->gif_if, src, dst);
616 break;
617
618 #ifdef SIOCDIFPHYADDR
619 case SIOCDIFPHYADDR:
620 gif_delete_tunnel(&sc->gif_if);
621 break;
622 #endif
623
624 case SIOCGIFPSRCADDR:
625 #ifdef INET6
626 case SIOCGIFPSRCADDR_IN6:
627 #endif /* INET6 */
628 if (sc->gif_psrc == NULL) {
629 error = EADDRNOTAVAIL;
630 goto bad;
631 }
632 src = sc->gif_psrc;
633 switch (cmd) {
634 #ifdef INET
635 case SIOCGIFPSRCADDR:
636 dst = &ifr->ifr_addr;
637 size = sizeof(ifr->ifr_addr);
638 break;
639 #endif /* INET */
640 #ifdef INET6
641 case SIOCGIFPSRCADDR_IN6:
642 dst = (struct sockaddr *)
643 &(((struct in6_ifreq *)data)->ifr_addr);
644 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
645 break;
646 #endif /* INET6 */
647 default:
648 error = EADDRNOTAVAIL;
649 goto bad;
650 }
651 if (src->sa_len > size)
652 return EINVAL;
653 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
654 break;
655
656 case SIOCGIFPDSTADDR:
657 #ifdef INET6
658 case SIOCGIFPDSTADDR_IN6:
659 #endif /* INET6 */
660 if (sc->gif_pdst == NULL) {
661 error = EADDRNOTAVAIL;
662 goto bad;
663 }
664 src = sc->gif_pdst;
665 switch (cmd) {
666 #ifdef INET
667 case SIOCGIFPDSTADDR:
668 dst = &ifr->ifr_addr;
669 size = sizeof(ifr->ifr_addr);
670 break;
671 #endif /* INET */
672 #ifdef INET6
673 case SIOCGIFPDSTADDR_IN6:
674 dst = (struct sockaddr *)
675 &(((struct in6_ifreq *)data)->ifr_addr);
676 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
677 break;
678 #endif /* INET6 */
679 default:
680 error = EADDRNOTAVAIL;
681 goto bad;
682 }
683 if (src->sa_len > size)
684 return EINVAL;
685 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
686 break;
687
688 case SIOCGLIFPHYADDR:
689 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
690 error = EADDRNOTAVAIL;
691 goto bad;
692 }
693
694 /* copy src */
695 src = sc->gif_psrc;
696 dst = (struct sockaddr *)
697 &(((struct if_laddrreq *)data)->addr);
698 size = sizeof(((struct if_laddrreq *)data)->addr);
699 if (src->sa_len > size)
700 return EINVAL;
701 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
702
703 /* copy dst */
704 src = sc->gif_pdst;
705 dst = (struct sockaddr *)
706 &(((struct if_laddrreq *)data)->dstaddr);
707 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
708 if (src->sa_len > size)
709 return EINVAL;
710 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
711 break;
712
713 case SIOCSIFFLAGS:
714 /* if_ioctl() takes care of it */
715 break;
716
717 default:
718 error = EINVAL;
719 break;
720 }
721 bad:
722 return error;
723 }
724
725 int
726 gif_set_tunnel(ifp, src, dst)
727 struct ifnet *ifp;
728 struct sockaddr *src;
729 struct sockaddr *dst;
730 {
731 struct gif_softc *sc = (struct gif_softc *)ifp;
732 struct gif_softc *sc2;
733 struct sockaddr *osrc, *odst, *sa;
734 int s;
735 int error = 0;
736
737 s = splnet();
738
739 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
740 if (sc2 == sc)
741 continue;
742 if (!sc2->gif_pdst || !sc2->gif_psrc)
743 continue;
744 if (sc2->gif_pdst->sa_family != dst->sa_family ||
745 sc2->gif_pdst->sa_len != dst->sa_len ||
746 sc2->gif_psrc->sa_family != src->sa_family ||
747 sc2->gif_psrc->sa_len != src->sa_len)
748 continue;
749
750 /*
751 * Disallow parallel tunnels unless instructed
752 * otherwise.
753 */
754 if (!parallel_tunnels &&
755 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
756 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
757 error = EADDRNOTAVAIL;
758 goto bad;
759 }
760
761 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
762 }
763
764 /* XXX we can detach from both, but be polite just in case */
765 if (sc->gif_psrc)
766 switch (sc->gif_psrc->sa_family) {
767 #ifdef INET
768 case AF_INET:
769 (void)in_gif_detach(sc);
770 break;
771 #endif
772 #ifdef INET6
773 case AF_INET6:
774 (void)in6_gif_detach(sc);
775 break;
776 #endif
777 }
778
779 osrc = sc->gif_psrc;
780 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
781 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
782 sc->gif_psrc = sa;
783
784 odst = sc->gif_pdst;
785 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
786 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
787 sc->gif_pdst = sa;
788
789 switch (sc->gif_psrc->sa_family) {
790 #ifdef INET
791 case AF_INET:
792 error = in_gif_attach(sc);
793 break;
794 #endif
795 #ifdef INET6
796 case AF_INET6:
797 error = in6_gif_attach(sc);
798 break;
799 #endif
800 }
801 if (error) {
802 /* rollback */
803 free((caddr_t)sc->gif_psrc, M_IFADDR);
804 free((caddr_t)sc->gif_pdst, M_IFADDR);
805 sc->gif_psrc = osrc;
806 sc->gif_pdst = odst;
807 goto bad;
808 }
809
810 if (osrc)
811 free((caddr_t)osrc, M_IFADDR);
812 if (odst)
813 free((caddr_t)odst, M_IFADDR);
814
815 if (sc->gif_psrc && sc->gif_pdst)
816 ifp->if_flags |= IFF_RUNNING;
817 else
818 ifp->if_flags &= ~IFF_RUNNING;
819 splx(s);
820
821 return 0;
822
823 bad:
824 if (sc->gif_psrc && sc->gif_pdst)
825 ifp->if_flags |= IFF_RUNNING;
826 else
827 ifp->if_flags &= ~IFF_RUNNING;
828 splx(s);
829
830 return error;
831 }
832
833 void
834 gif_delete_tunnel(ifp)
835 struct ifnet *ifp;
836 {
837 struct gif_softc *sc = (struct gif_softc *)ifp;
838 int s;
839
840 s = splnet();
841
842 if (sc->gif_psrc) {
843 free((caddr_t)sc->gif_psrc, M_IFADDR);
844 sc->gif_psrc = NULL;
845 }
846 if (sc->gif_pdst) {
847 free((caddr_t)sc->gif_pdst, M_IFADDR);
848 sc->gif_pdst = NULL;
849 }
850 /* it is safe to detach from both */
851 #ifdef INET
852 (void)in_gif_detach(sc);
853 #endif
854 #ifdef INET6
855 (void)in6_gif_detach(sc);
856 #endif
857
858 if (sc->gif_psrc && sc->gif_pdst)
859 ifp->if_flags |= IFF_RUNNING;
860 else
861 ifp->if_flags &= ~IFF_RUNNING;
862 splx(s);
863 }
Cache object: 40762d8d848ae14dad4049f52433c378
|