if_gif.c revision 1.111 1 /* $NetBSD: if_gif.c,v 1.111 2016/06/24 04:38:12 knakahara Exp $ */
2 /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc 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 <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.111 2016/06/24 04:38:12 knakahara Exp $");
35
36 #ifdef _KERNEL_OPT
37 #include "opt_inet.h"
38 #endif
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <sys/errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/time.h>
49 #include <sys/socketvar.h>
50 #include <sys/syslog.h>
51 #include <sys/proc.h>
52 #include <sys/cpu.h>
53 #include <sys/intr.h>
54 #include <sys/kmem.h>
55 #include <sys/sysctl.h>
56
57 #include <net/if.h>
58 #include <net/if_types.h>
59 #include <net/netisr.h>
60 #include <net/route.h>
61 #include <net/bpf.h>
62
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/ip.h>
66 #ifdef INET
67 #include <netinet/in_var.h>
68 #endif /* INET */
69 #include <netinet/in_gif.h>
70
71 #ifdef INET6
72 #ifndef INET
73 #include <netinet/in.h>
74 #endif
75 #include <netinet6/in6_var.h>
76 #include <netinet/ip6.h>
77 #include <netinet6/ip6_var.h>
78 #include <netinet6/in6_gif.h>
79 #endif /* INET6 */
80
81 #include <netinet/ip_encap.h>
82 #include <net/if_gif.h>
83
84 #include <net/net_osdep.h>
85
86 #include "ioconf.h"
87
88 /*
89 * gif global variable definitions
90 */
91 static LIST_HEAD(, gif_softc) gif_softc_list;
92
93 static void gifattach0(struct gif_softc *);
94 static int gif_output(struct ifnet *, struct mbuf *,
95 const struct sockaddr *, const struct rtentry *);
96 static void gif_start(struct ifnet *);
97 static int gif_ioctl(struct ifnet *, u_long, void *);
98 static int gif_set_tunnel(struct ifnet *, struct sockaddr *,
99 struct sockaddr *);
100 static void gif_delete_tunnel(struct ifnet *);
101
102 static void gif_sysctl_setup(struct sysctllog **);
103
104 static int gif_clone_create(struct if_clone *, int);
105 static int gif_clone_destroy(struct ifnet *);
106 static int gif_check_nesting(struct ifnet *, struct mbuf *);
107
108 static int gif_encap_attach(struct gif_softc *);
109 static int gif_encap_detach(struct gif_softc *);
110
111 static struct if_clone gif_cloner =
112 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
113
114 #ifndef MAX_GIF_NEST
115 /*
116 * This macro controls the upper limitation on nesting of gif tunnels.
117 * Since, setting a large value to this macro with a careless configuration
118 * may introduce system crash, we don't allow any nestings by default.
119 * If you need to configure nested gif tunnels, you can define this macro
120 * in your kernel configuration file. However, if you do so, please be
121 * careful to configure the tunnels so that it won't make a loop.
122 */
123 #define MAX_GIF_NEST 1
124 #endif
125 static int max_gif_nesting = MAX_GIF_NEST;
126
127 static void
128 gif_sysctl_setup(struct sysctllog **clog)
129 {
130
131 #ifdef INET
132 sysctl_createv(clog, 0, NULL, NULL,
133 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
134 CTLTYPE_INT, "gifttl",
135 SYSCTL_DESCR("Default TTL for a gif tunnel datagram"),
136 NULL, 0, &ip_gif_ttl, 0,
137 CTL_NET, PF_INET, IPPROTO_IP,
138 IPCTL_GIF_TTL, CTL_EOL);
139 #endif
140 #ifdef INET6
141 sysctl_createv(clog, 0, NULL, NULL,
142 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
143 CTLTYPE_INT, "gifhlim",
144 SYSCTL_DESCR("Default hop limit for a gif tunnel datagram"),
145 NULL, 0, &ip6_gif_hlim, 0,
146 CTL_NET, PF_INET6, IPPROTO_IPV6,
147 IPV6CTL_GIF_HLIM, CTL_EOL);
148 #endif
149 }
150
151 /* ARGSUSED */
152 void
153 gifattach(int count)
154 {
155
156 LIST_INIT(&gif_softc_list);
157 if_clone_attach(&gif_cloner);
158
159 gif_sysctl_setup(NULL);
160 }
161
162 static int
163 gif_clone_create(struct if_clone *ifc, int unit)
164 {
165 struct gif_softc *sc;
166
167 sc = kmem_zalloc(sizeof(struct gif_softc), KM_SLEEP);
168 if (sc == NULL)
169 return ENOMEM;
170
171 if_initname(&sc->gif_if, ifc->ifc_name, unit);
172
173 gifattach0(sc);
174
175 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
176 return (0);
177 }
178
179 static void
180 gifattach0(struct gif_softc *sc)
181 {
182
183 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
184
185 sc->gif_if.if_addrlen = 0;
186 sc->gif_if.if_mtu = GIF_MTU;
187 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
188 sc->gif_if.if_ioctl = gif_ioctl;
189 sc->gif_if.if_output = gif_output;
190 sc->gif_if.if_type = IFT_GIF;
191 sc->gif_if.if_dlt = DLT_NULL;
192 sc->gif_if.if_softc = sc;
193 IFQ_SET_READY(&sc->gif_if.if_snd);
194 if_attach(&sc->gif_if);
195 if_alloc_sadl(&sc->gif_if);
196 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
197 }
198
199 static int
200 gif_clone_destroy(struct ifnet *ifp)
201 {
202 struct gif_softc *sc = (void *) ifp;
203
204 LIST_REMOVE(sc, gif_list);
205
206 gif_delete_tunnel(&sc->gif_if);
207 bpf_detach(ifp);
208 if_detach(ifp);
209 rtcache_free(&sc->gif_ro);
210
211 kmem_free(sc, sizeof(struct gif_softc));
212
213 return (0);
214 }
215
216 #ifdef GIF_ENCAPCHECK
217 int
218 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
219 {
220 struct ip ip;
221 struct gif_softc *sc;
222
223 sc = arg;
224 if (sc == NULL)
225 return 0;
226
227 if ((sc->gif_if.if_flags & IFF_UP) == 0)
228 return 0;
229
230 /* no physical address */
231 if (!sc->gif_psrc || !sc->gif_pdst)
232 return 0;
233
234 switch (proto) {
235 #ifdef INET
236 case IPPROTO_IPV4:
237 break;
238 #endif
239 #ifdef INET6
240 case IPPROTO_IPV6:
241 break;
242 #endif
243 default:
244 return 0;
245 }
246
247 /* Bail on short packets */
248 KASSERT(m->m_flags & M_PKTHDR);
249 if (m->m_pkthdr.len < sizeof(ip))
250 return 0;
251
252 m_copydata(m, 0, sizeof(ip), &ip);
253
254 switch (ip.ip_v) {
255 #ifdef INET
256 case 4:
257 if (sc->gif_psrc->sa_family != AF_INET ||
258 sc->gif_pdst->sa_family != AF_INET)
259 return 0;
260 return gif_encapcheck4(m, off, proto, arg);
261 #endif
262 #ifdef INET6
263 case 6:
264 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
265 return 0;
266 if (sc->gif_psrc->sa_family != AF_INET6 ||
267 sc->gif_pdst->sa_family != AF_INET6)
268 return 0;
269 return gif_encapcheck6(m, off, proto, arg);
270 #endif
271 default:
272 return 0;
273 }
274 }
275 #endif
276
277 /*
278 * gif may cause infinite recursion calls when misconfigured.
279 * We'll prevent this by introducing upper limit.
280 */
281 static int
282 gif_check_nesting(struct ifnet *ifp, struct mbuf *m)
283 {
284 struct m_tag *mtag;
285 int *count;
286
287 mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL);
288 if (mtag != NULL) {
289 count = (int *)(mtag + 1);
290 if (++(*count) > max_gif_nesting) {
291 log(LOG_NOTICE,
292 "%s: recursively called too many times(%d)\n",
293 if_name(ifp),
294 *count);
295 return EIO;
296 }
297 } else {
298 mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count),
299 M_NOWAIT);
300 if (mtag != NULL) {
301 m_tag_prepend(m, mtag);
302 count = (int *)(mtag + 1);
303 *count = 0;
304 } else {
305 log(LOG_DEBUG,
306 "%s: m_tag_get() failed, recursion calls are not prevented.\n",
307 if_name(ifp));
308 }
309 }
310
311 return 0;
312 }
313
314 static int
315 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
316 const struct rtentry *rt)
317 {
318 struct gif_softc *sc = ifp->if_softc;
319 int error = 0;
320 int s;
321
322 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
323
324 if ((error = gif_check_nesting(ifp, m)) != 0) {
325 m_free(m);
326 goto end;
327 }
328
329 m->m_flags &= ~(M_BCAST|M_MCAST);
330 if (!(ifp->if_flags & IFF_UP) ||
331 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
332 m_freem(m);
333 error = ENETDOWN;
334 goto end;
335 }
336
337 /* XXX should we check if our outer source is legal? */
338
339 /* use DLT_NULL encapsulation here to pass inner af type */
340 M_PREPEND(m, sizeof(int), M_DONTWAIT);
341 if (!m) {
342 error = ENOBUFS;
343 goto end;
344 }
345 *mtod(m, int *) = dst->sa_family;
346
347 /* Clear checksum-offload flags. */
348 m->m_pkthdr.csum_flags = 0;
349 m->m_pkthdr.csum_data = 0;
350
351 s = splnet();
352 IFQ_ENQUEUE(&ifp->if_snd, m, error);
353 if (error) {
354 splx(s);
355 goto end;
356 }
357 splx(s);
358
359 gif_start(ifp);
360
361 error = 0;
362
363 end:
364 if (error)
365 ifp->if_oerrors++;
366 return error;
367 }
368
369 static void
370 gif_start(struct ifnet *ifp)
371 {
372 struct gif_softc *sc;
373 struct mbuf *m;
374 int family;
375 int len;
376 int s;
377 int error;
378
379 sc = ifp->if_softc;
380
381 /* output processing */
382 while (1) {
383 s = splnet();
384 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
385 splx(s);
386 if (m == NULL)
387 break;
388
389 /* grab and chop off inner af type */
390 if (sizeof(int) > m->m_len) {
391 m = m_pullup(m, sizeof(int));
392 if (!m) {
393 ifp->if_oerrors++;
394 continue;
395 }
396 }
397 family = *mtod(m, int *);
398 bpf_mtap(ifp, m);
399 m_adj(m, sizeof(int));
400
401 len = m->m_pkthdr.len;
402
403 /* dispatch to output logic based on outer AF */
404 switch (sc->gif_psrc->sa_family) {
405 #ifdef INET
406 case AF_INET:
407 /* XXX
408 * To add mutex_enter(softnet_lock) or
409 * KASSERT(mutex_owned(softnet_lock)) here, we shold
410 * coordinate softnet_lock between in6_if_up() and
411 * in6_purgeif().
412 */
413 error = in_gif_output(ifp, family, m);
414 break;
415 #endif
416 #ifdef INET6
417 case AF_INET6:
418 /* XXX
419 * the same as in_gif_output()
420 */
421 error = in6_gif_output(ifp, family, m);
422 break;
423 #endif
424 default:
425 m_freem(m);
426 error = ENETDOWN;
427 break;
428 }
429
430 if (error)
431 ifp->if_oerrors++;
432 else {
433 ifp->if_opackets++;
434 ifp->if_obytes += len;
435 }
436 }
437 }
438
439 void
440 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
441 {
442 pktqueue_t *pktq;
443 size_t pktlen;
444 int s;
445
446 if (ifp == NULL) {
447 /* just in case */
448 m_freem(m);
449 return;
450 }
451
452 m_set_rcvif(m, ifp);
453 pktlen = m->m_pkthdr.len;
454
455 bpf_mtap_af(ifp, af, m);
456
457 /*
458 * Put the packet to the network layer input queue according to the
459 * specified address family. Note: we avoid direct call to the
460 * input function of the network layer in order to avoid recursion.
461 * This may be revisited in the future.
462 */
463 switch (af) {
464 #ifdef INET
465 case AF_INET:
466 pktq = ip_pktq;
467 break;
468 #endif
469 #ifdef INET6
470 case AF_INET6:
471 pktq = ip6_pktq;
472 break;
473 #endif
474 default:
475 m_freem(m);
476 return;
477 }
478
479 s = splnet();
480 if (__predict_true(pktq_enqueue(pktq, m, 0))) {
481 ifp->if_ibytes += pktlen;
482 ifp->if_ipackets++;
483 } else {
484 m_freem(m);
485 }
486 splx(s);
487 }
488
489 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
490 static int
491 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
492 {
493 struct gif_softc *sc = ifp->if_softc;
494 struct ifreq *ifr = (struct ifreq*)data;
495 struct ifaddr *ifa = (struct ifaddr*)data;
496 int error = 0, size;
497 struct sockaddr *dst, *src;
498
499 switch (cmd) {
500 case SIOCINITIFADDR:
501 ifp->if_flags |= IFF_UP;
502 ifa->ifa_rtrequest = p2p_rtrequest;
503 break;
504
505 case SIOCADDMULTI:
506 case SIOCDELMULTI:
507 switch (ifr->ifr_addr.sa_family) {
508 #ifdef INET
509 case AF_INET: /* IP supports Multicast */
510 break;
511 #endif /* INET */
512 #ifdef INET6
513 case AF_INET6: /* IP6 supports Multicast */
514 break;
515 #endif /* INET6 */
516 default: /* Other protocols doesn't support Multicast */
517 error = EAFNOSUPPORT;
518 break;
519 }
520 break;
521
522 case SIOCSIFMTU:
523 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
524 return EINVAL;
525 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
526 error = 0;
527 break;
528
529 #ifdef INET
530 case SIOCSIFPHYADDR:
531 #endif
532 #ifdef INET6
533 case SIOCSIFPHYADDR_IN6:
534 #endif /* INET6 */
535 case SIOCSLIFPHYADDR:
536 switch (cmd) {
537 #ifdef INET
538 case SIOCSIFPHYADDR:
539 src = (struct sockaddr *)
540 &(((struct in_aliasreq *)data)->ifra_addr);
541 dst = (struct sockaddr *)
542 &(((struct in_aliasreq *)data)->ifra_dstaddr);
543 break;
544 #endif
545 #ifdef INET6
546 case SIOCSIFPHYADDR_IN6:
547 src = (struct sockaddr *)
548 &(((struct in6_aliasreq *)data)->ifra_addr);
549 dst = (struct sockaddr *)
550 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
551 break;
552 #endif
553 case SIOCSLIFPHYADDR:
554 src = (struct sockaddr *)
555 &(((struct if_laddrreq *)data)->addr);
556 dst = (struct sockaddr *)
557 &(((struct if_laddrreq *)data)->dstaddr);
558 break;
559 default:
560 return EINVAL;
561 }
562
563 /* sa_family must be equal */
564 if (src->sa_family != dst->sa_family)
565 return EINVAL;
566
567 /* validate sa_len */
568 switch (src->sa_family) {
569 #ifdef INET
570 case AF_INET:
571 if (src->sa_len != sizeof(struct sockaddr_in))
572 return EINVAL;
573 break;
574 #endif
575 #ifdef INET6
576 case AF_INET6:
577 if (src->sa_len != sizeof(struct sockaddr_in6))
578 return EINVAL;
579 break;
580 #endif
581 default:
582 return EAFNOSUPPORT;
583 }
584 switch (dst->sa_family) {
585 #ifdef INET
586 case AF_INET:
587 if (dst->sa_len != sizeof(struct sockaddr_in))
588 return EINVAL;
589 break;
590 #endif
591 #ifdef INET6
592 case AF_INET6:
593 if (dst->sa_len != sizeof(struct sockaddr_in6))
594 return EINVAL;
595 break;
596 #endif
597 default:
598 return EAFNOSUPPORT;
599 }
600
601 /* check sa_family looks sane for the cmd */
602 switch (cmd) {
603 case SIOCSIFPHYADDR:
604 if (src->sa_family == AF_INET)
605 break;
606 return EAFNOSUPPORT;
607 #ifdef INET6
608 case SIOCSIFPHYADDR_IN6:
609 if (src->sa_family == AF_INET6)
610 break;
611 return EAFNOSUPPORT;
612 #endif /* INET6 */
613 case SIOCSLIFPHYADDR:
614 /* checks done in the above */
615 break;
616 }
617
618 error = gif_set_tunnel(&sc->gif_if, src, dst);
619 break;
620
621 #ifdef SIOCDIFPHYADDR
622 case SIOCDIFPHYADDR:
623 gif_delete_tunnel(&sc->gif_if);
624 break;
625 #endif
626
627 case SIOCGIFPSRCADDR:
628 #ifdef INET6
629 case SIOCGIFPSRCADDR_IN6:
630 #endif /* INET6 */
631 if (sc->gif_psrc == NULL) {
632 error = EADDRNOTAVAIL;
633 goto bad;
634 }
635 src = sc->gif_psrc;
636 switch (cmd) {
637 #ifdef INET
638 case SIOCGIFPSRCADDR:
639 dst = &ifr->ifr_addr;
640 size = sizeof(ifr->ifr_addr);
641 break;
642 #endif /* INET */
643 #ifdef INET6
644 case SIOCGIFPSRCADDR_IN6:
645 dst = (struct sockaddr *)
646 &(((struct in6_ifreq *)data)->ifr_addr);
647 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
648 break;
649 #endif /* INET6 */
650 default:
651 error = EADDRNOTAVAIL;
652 goto bad;
653 }
654 if (src->sa_len > size)
655 return EINVAL;
656 memcpy(dst, src, src->sa_len);
657 break;
658
659 case SIOCGIFPDSTADDR:
660 #ifdef INET6
661 case SIOCGIFPDSTADDR_IN6:
662 #endif /* INET6 */
663 if (sc->gif_pdst == NULL) {
664 error = EADDRNOTAVAIL;
665 goto bad;
666 }
667 src = sc->gif_pdst;
668 switch (cmd) {
669 #ifdef INET
670 case SIOCGIFPDSTADDR:
671 dst = &ifr->ifr_addr;
672 size = sizeof(ifr->ifr_addr);
673 break;
674 #endif /* INET */
675 #ifdef INET6
676 case SIOCGIFPDSTADDR_IN6:
677 dst = (struct sockaddr *)
678 &(((struct in6_ifreq *)data)->ifr_addr);
679 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
680 break;
681 #endif /* INET6 */
682 default:
683 error = EADDRNOTAVAIL;
684 goto bad;
685 }
686 if (src->sa_len > size)
687 return EINVAL;
688 memcpy(dst, src, src->sa_len);
689 break;
690
691 case SIOCGLIFPHYADDR:
692 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
693 error = EADDRNOTAVAIL;
694 goto bad;
695 }
696
697 /* copy src */
698 src = sc->gif_psrc;
699 dst = (struct sockaddr *)
700 &(((struct if_laddrreq *)data)->addr);
701 size = sizeof(((struct if_laddrreq *)data)->addr);
702 if (src->sa_len > size)
703 return EINVAL;
704 memcpy(dst, src, src->sa_len);
705
706 /* copy dst */
707 src = sc->gif_pdst;
708 dst = (struct sockaddr *)
709 &(((struct if_laddrreq *)data)->dstaddr);
710 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
711 if (src->sa_len > size)
712 return EINVAL;
713 memcpy(dst, src, src->sa_len);
714 break;
715
716 default:
717 return ifioctl_common(ifp, cmd, data);
718 }
719 bad:
720 return error;
721 }
722
723 static int
724 gif_encap_attach(struct gif_softc *sc)
725 {
726 int error;
727
728 if (sc == NULL || sc->gif_psrc == NULL)
729 return EINVAL;
730
731 switch (sc->gif_psrc->sa_family) {
732 #ifdef INET
733 case AF_INET:
734 error = in_gif_attach(sc);
735 break;
736 #endif
737 #ifdef INET6
738 case AF_INET6:
739 error = in6_gif_attach(sc);
740 break;
741 #endif
742 default:
743 error = EINVAL;
744 break;
745 }
746
747 return error;
748 }
749
750 static int
751 gif_encap_detach(struct gif_softc *sc)
752 {
753 int error;
754
755 if (sc == NULL || sc->gif_psrc == NULL)
756 return EINVAL;
757
758 switch (sc->gif_psrc->sa_family) {
759 #ifdef INET
760 case AF_INET:
761 error = in_gif_detach(sc);
762 break;
763 #endif
764 #ifdef INET6
765 case AF_INET6:
766 error = in6_gif_detach(sc);
767 break;
768 #endif
769 default:
770 error = EINVAL;
771 break;
772 }
773
774 return error;
775 }
776
777 static int
778 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
779 {
780 struct gif_softc *sc = ifp->if_softc;
781 struct gif_softc *sc2;
782 struct sockaddr *osrc, *odst;
783 struct sockaddr *nsrc, *ndst;
784 int s;
785 int error;
786
787 s = splsoftnet();
788
789 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
790 if (sc2 == sc)
791 continue;
792 if (!sc2->gif_pdst || !sc2->gif_psrc)
793 continue;
794 /* can't configure same pair of address onto two gifs */
795 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
796 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
797 /* continue to use the old configureation. */
798 splx(s);
799 return EADDRNOTAVAIL;
800 }
801
802 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
803 }
804
805 if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
806 splx(s);
807 return ENOMEM;
808 }
809 if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
810 sockaddr_free(nsrc);
811 splx(s);
812 return ENOMEM;
813 }
814
815 /* Firstly, clear old configurations. */
816 /* XXX we can detach from both, but be polite just in case */
817 if (sc->gif_psrc)
818 (void)gif_encap_detach(sc);
819
820 /*
821 * Secondly, try to set new configurations.
822 * If the setup failed, rollback to old configurations.
823 */
824 do {
825 osrc = sc->gif_psrc;
826 odst = sc->gif_pdst;
827 sc->gif_psrc = nsrc;
828 sc->gif_pdst = ndst;
829
830 error = gif_encap_attach(sc);
831 if (error) {
832 /* rollback to the last configuration. */
833 nsrc = osrc;
834 ndst = odst;
835 osrc = sc->gif_psrc;
836 odst = sc->gif_pdst;
837
838 continue;
839 }
840 } while (error != 0 && (nsrc != NULL && ndst != NULL));
841 /* Thirdly, even rollback failed, clear configurations. */
842 if (error) {
843 osrc = sc->gif_psrc;
844 odst = sc->gif_pdst;
845 sc->gif_psrc = NULL;
846 sc->gif_pdst = NULL;
847 }
848
849 if (osrc)
850 sockaddr_free(osrc);
851 if (odst)
852 sockaddr_free(odst);
853
854 if (sc->gif_psrc && sc->gif_pdst)
855 ifp->if_flags |= IFF_RUNNING;
856 else
857 ifp->if_flags &= ~IFF_RUNNING;
858
859 splx(s);
860 return error;
861 }
862
863 static void
864 gif_delete_tunnel(struct ifnet *ifp)
865 {
866 struct gif_softc *sc = ifp->if_softc;
867 int s;
868
869 s = splsoftnet();
870
871 if (sc->gif_psrc) {
872 sockaddr_free(sc->gif_psrc);
873 sc->gif_psrc = NULL;
874 }
875 if (sc->gif_pdst) {
876 sockaddr_free(sc->gif_pdst);
877 sc->gif_pdst = NULL;
878 }
879 /* it is safe to detach from both */
880 #ifdef INET
881 (void)in_gif_detach(sc);
882 #endif
883 #ifdef INET6
884 (void)in6_gif_detach(sc);
885 #endif
886
887 if (sc->gif_psrc && sc->gif_pdst)
888 ifp->if_flags |= IFF_RUNNING;
889 else
890 ifp->if_flags &= ~IFF_RUNNING;
891 splx(s);
892 }
893