if_gif.c revision 1.113 1 /* $NetBSD: if_gif.c,v 1.113 2016/06/27 09:06:56 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.113 2016/06/27 09:06:56 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_extflags = IFEF_NO_LINK_STATE_CHANGE;
189 sc->gif_if.if_ioctl = gif_ioctl;
190 sc->gif_if.if_output = gif_output;
191 sc->gif_if.if_type = IFT_GIF;
192 sc->gif_if.if_dlt = DLT_NULL;
193 sc->gif_if.if_softc = sc;
194 IFQ_SET_READY(&sc->gif_if.if_snd);
195 if_initialize(&sc->gif_if);
196 if_register(&sc->gif_if);
197 if_alloc_sadl(&sc->gif_if);
198 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
199 }
200
201 static int
202 gif_clone_destroy(struct ifnet *ifp)
203 {
204 struct gif_softc *sc = (void *) ifp;
205
206 LIST_REMOVE(sc, gif_list);
207
208 gif_delete_tunnel(&sc->gif_if);
209 bpf_detach(ifp);
210 if_detach(ifp);
211 rtcache_free(&sc->gif_ro);
212
213 kmem_free(sc, sizeof(struct gif_softc));
214
215 return (0);
216 }
217
218 #ifdef GIF_ENCAPCHECK
219 int
220 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
221 {
222 struct ip ip;
223 struct gif_softc *sc;
224
225 sc = arg;
226 if (sc == NULL)
227 return 0;
228
229 if ((sc->gif_if.if_flags & IFF_UP) == 0)
230 return 0;
231
232 /* no physical address */
233 if (!sc->gif_psrc || !sc->gif_pdst)
234 return 0;
235
236 switch (proto) {
237 #ifdef INET
238 case IPPROTO_IPV4:
239 break;
240 #endif
241 #ifdef INET6
242 case IPPROTO_IPV6:
243 break;
244 #endif
245 default:
246 return 0;
247 }
248
249 /* Bail on short packets */
250 KASSERT(m->m_flags & M_PKTHDR);
251 if (m->m_pkthdr.len < sizeof(ip))
252 return 0;
253
254 m_copydata(m, 0, sizeof(ip), &ip);
255
256 switch (ip.ip_v) {
257 #ifdef INET
258 case 4:
259 if (sc->gif_psrc->sa_family != AF_INET ||
260 sc->gif_pdst->sa_family != AF_INET)
261 return 0;
262 return gif_encapcheck4(m, off, proto, arg);
263 #endif
264 #ifdef INET6
265 case 6:
266 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
267 return 0;
268 if (sc->gif_psrc->sa_family != AF_INET6 ||
269 sc->gif_pdst->sa_family != AF_INET6)
270 return 0;
271 return gif_encapcheck6(m, off, proto, arg);
272 #endif
273 default:
274 return 0;
275 }
276 }
277 #endif
278
279 /*
280 * gif may cause infinite recursion calls when misconfigured.
281 * We'll prevent this by introducing upper limit.
282 */
283 static int
284 gif_check_nesting(struct ifnet *ifp, struct mbuf *m)
285 {
286 struct m_tag *mtag;
287 int *count;
288
289 mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL);
290 if (mtag != NULL) {
291 count = (int *)(mtag + 1);
292 if (++(*count) > max_gif_nesting) {
293 log(LOG_NOTICE,
294 "%s: recursively called too many times(%d)\n",
295 if_name(ifp),
296 *count);
297 return EIO;
298 }
299 } else {
300 mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count),
301 M_NOWAIT);
302 if (mtag != NULL) {
303 m_tag_prepend(m, mtag);
304 count = (int *)(mtag + 1);
305 *count = 0;
306 } else {
307 log(LOG_DEBUG,
308 "%s: m_tag_get() failed, recursion calls are not prevented.\n",
309 if_name(ifp));
310 }
311 }
312
313 return 0;
314 }
315
316 static int
317 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
318 const struct rtentry *rt)
319 {
320 struct gif_softc *sc = ifp->if_softc;
321 int error = 0;
322 int s;
323
324 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
325
326 if ((error = gif_check_nesting(ifp, m)) != 0) {
327 m_free(m);
328 goto end;
329 }
330
331 m->m_flags &= ~(M_BCAST|M_MCAST);
332 if (!(ifp->if_flags & IFF_UP) ||
333 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
334 m_freem(m);
335 error = ENETDOWN;
336 goto end;
337 }
338
339 /* XXX should we check if our outer source is legal? */
340
341 /* use DLT_NULL encapsulation here to pass inner af type */
342 M_PREPEND(m, sizeof(int), M_DONTWAIT);
343 if (!m) {
344 error = ENOBUFS;
345 goto end;
346 }
347 *mtod(m, int *) = dst->sa_family;
348
349 /* Clear checksum-offload flags. */
350 m->m_pkthdr.csum_flags = 0;
351 m->m_pkthdr.csum_data = 0;
352
353 s = splnet();
354 IFQ_ENQUEUE(&ifp->if_snd, m, error);
355 if (error) {
356 splx(s);
357 goto end;
358 }
359 splx(s);
360
361 gif_start(ifp);
362
363 error = 0;
364
365 end:
366 if (error)
367 ifp->if_oerrors++;
368 return error;
369 }
370
371 static void
372 gif_start(struct ifnet *ifp)
373 {
374 struct gif_softc *sc;
375 struct mbuf *m;
376 int family;
377 int len;
378 int s;
379 int error;
380
381 sc = ifp->if_softc;
382
383 /* output processing */
384 while (1) {
385 s = splnet();
386 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
387 splx(s);
388 if (m == NULL)
389 break;
390
391 /* grab and chop off inner af type */
392 if (sizeof(int) > m->m_len) {
393 m = m_pullup(m, sizeof(int));
394 if (!m) {
395 ifp->if_oerrors++;
396 continue;
397 }
398 }
399 family = *mtod(m, int *);
400 bpf_mtap(ifp, m);
401 m_adj(m, sizeof(int));
402
403 len = m->m_pkthdr.len;
404
405 /* dispatch to output logic based on outer AF */
406 switch (sc->gif_psrc->sa_family) {
407 #ifdef INET
408 case AF_INET:
409 /* XXX
410 * To add mutex_enter(softnet_lock) or
411 * KASSERT(mutex_owned(softnet_lock)) here, we shold
412 * coordinate softnet_lock between in6_if_up() and
413 * in6_purgeif().
414 */
415 error = in_gif_output(ifp, family, m);
416 break;
417 #endif
418 #ifdef INET6
419 case AF_INET6:
420 /* XXX
421 * the same as in_gif_output()
422 */
423 error = in6_gif_output(ifp, family, m);
424 break;
425 #endif
426 default:
427 m_freem(m);
428 error = ENETDOWN;
429 break;
430 }
431
432 if (error)
433 ifp->if_oerrors++;
434 else {
435 ifp->if_opackets++;
436 ifp->if_obytes += len;
437 }
438 }
439 }
440
441 void
442 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
443 {
444 pktqueue_t *pktq;
445 size_t pktlen;
446 int s;
447
448 if (ifp == NULL) {
449 /* just in case */
450 m_freem(m);
451 return;
452 }
453
454 m_set_rcvif(m, ifp);
455 pktlen = m->m_pkthdr.len;
456
457 bpf_mtap_af(ifp, af, m);
458
459 /*
460 * Put the packet to the network layer input queue according to the
461 * specified address family. Note: we avoid direct call to the
462 * input function of the network layer in order to avoid recursion.
463 * This may be revisited in the future.
464 */
465 switch (af) {
466 #ifdef INET
467 case AF_INET:
468 pktq = ip_pktq;
469 break;
470 #endif
471 #ifdef INET6
472 case AF_INET6:
473 pktq = ip6_pktq;
474 break;
475 #endif
476 default:
477 m_freem(m);
478 return;
479 }
480
481 s = splnet();
482 if (__predict_true(pktq_enqueue(pktq, m, 0))) {
483 ifp->if_ibytes += pktlen;
484 ifp->if_ipackets++;
485 } else {
486 m_freem(m);
487 }
488 splx(s);
489 }
490
491 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
492 static int
493 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
494 {
495 struct gif_softc *sc = ifp->if_softc;
496 struct ifreq *ifr = (struct ifreq*)data;
497 struct ifaddr *ifa = (struct ifaddr*)data;
498 int error = 0, size;
499 struct sockaddr *dst, *src;
500
501 switch (cmd) {
502 case SIOCINITIFADDR:
503 ifp->if_flags |= IFF_UP;
504 ifa->ifa_rtrequest = p2p_rtrequest;
505 break;
506
507 case SIOCADDMULTI:
508 case SIOCDELMULTI:
509 switch (ifr->ifr_addr.sa_family) {
510 #ifdef INET
511 case AF_INET: /* IP supports Multicast */
512 break;
513 #endif /* INET */
514 #ifdef INET6
515 case AF_INET6: /* IP6 supports Multicast */
516 break;
517 #endif /* INET6 */
518 default: /* Other protocols doesn't support Multicast */
519 error = EAFNOSUPPORT;
520 break;
521 }
522 break;
523
524 case SIOCSIFMTU:
525 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
526 return EINVAL;
527 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
528 error = 0;
529 break;
530
531 #ifdef INET
532 case SIOCSIFPHYADDR:
533 #endif
534 #ifdef INET6
535 case SIOCSIFPHYADDR_IN6:
536 #endif /* INET6 */
537 case SIOCSLIFPHYADDR:
538 switch (cmd) {
539 #ifdef INET
540 case SIOCSIFPHYADDR:
541 src = (struct sockaddr *)
542 &(((struct in_aliasreq *)data)->ifra_addr);
543 dst = (struct sockaddr *)
544 &(((struct in_aliasreq *)data)->ifra_dstaddr);
545 break;
546 #endif
547 #ifdef INET6
548 case SIOCSIFPHYADDR_IN6:
549 src = (struct sockaddr *)
550 &(((struct in6_aliasreq *)data)->ifra_addr);
551 dst = (struct sockaddr *)
552 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
553 break;
554 #endif
555 case SIOCSLIFPHYADDR:
556 src = (struct sockaddr *)
557 &(((struct if_laddrreq *)data)->addr);
558 dst = (struct sockaddr *)
559 &(((struct if_laddrreq *)data)->dstaddr);
560 break;
561 default:
562 return EINVAL;
563 }
564
565 /* sa_family must be equal */
566 if (src->sa_family != dst->sa_family)
567 return EINVAL;
568
569 /* validate sa_len */
570 switch (src->sa_family) {
571 #ifdef INET
572 case AF_INET:
573 if (src->sa_len != sizeof(struct sockaddr_in))
574 return EINVAL;
575 break;
576 #endif
577 #ifdef INET6
578 case AF_INET6:
579 if (src->sa_len != sizeof(struct sockaddr_in6))
580 return EINVAL;
581 break;
582 #endif
583 default:
584 return EAFNOSUPPORT;
585 }
586 switch (dst->sa_family) {
587 #ifdef INET
588 case AF_INET:
589 if (dst->sa_len != sizeof(struct sockaddr_in))
590 return EINVAL;
591 break;
592 #endif
593 #ifdef INET6
594 case AF_INET6:
595 if (dst->sa_len != sizeof(struct sockaddr_in6))
596 return EINVAL;
597 break;
598 #endif
599 default:
600 return EAFNOSUPPORT;
601 }
602
603 /* check sa_family looks sane for the cmd */
604 switch (cmd) {
605 case SIOCSIFPHYADDR:
606 if (src->sa_family == AF_INET)
607 break;
608 return EAFNOSUPPORT;
609 #ifdef INET6
610 case SIOCSIFPHYADDR_IN6:
611 if (src->sa_family == AF_INET6)
612 break;
613 return EAFNOSUPPORT;
614 #endif /* INET6 */
615 case SIOCSLIFPHYADDR:
616 /* checks done in the above */
617 break;
618 }
619
620 error = gif_set_tunnel(&sc->gif_if, src, dst);
621 break;
622
623 #ifdef SIOCDIFPHYADDR
624 case SIOCDIFPHYADDR:
625 gif_delete_tunnel(&sc->gif_if);
626 break;
627 #endif
628
629 case SIOCGIFPSRCADDR:
630 #ifdef INET6
631 case SIOCGIFPSRCADDR_IN6:
632 #endif /* INET6 */
633 if (sc->gif_psrc == NULL) {
634 error = EADDRNOTAVAIL;
635 goto bad;
636 }
637 src = sc->gif_psrc;
638 switch (cmd) {
639 #ifdef INET
640 case SIOCGIFPSRCADDR:
641 dst = &ifr->ifr_addr;
642 size = sizeof(ifr->ifr_addr);
643 break;
644 #endif /* INET */
645 #ifdef INET6
646 case SIOCGIFPSRCADDR_IN6:
647 dst = (struct sockaddr *)
648 &(((struct in6_ifreq *)data)->ifr_addr);
649 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
650 break;
651 #endif /* INET6 */
652 default:
653 error = EADDRNOTAVAIL;
654 goto bad;
655 }
656 if (src->sa_len > size)
657 return EINVAL;
658 memcpy(dst, src, src->sa_len);
659 break;
660
661 case SIOCGIFPDSTADDR:
662 #ifdef INET6
663 case SIOCGIFPDSTADDR_IN6:
664 #endif /* INET6 */
665 if (sc->gif_pdst == NULL) {
666 error = EADDRNOTAVAIL;
667 goto bad;
668 }
669 src = sc->gif_pdst;
670 switch (cmd) {
671 #ifdef INET
672 case SIOCGIFPDSTADDR:
673 dst = &ifr->ifr_addr;
674 size = sizeof(ifr->ifr_addr);
675 break;
676 #endif /* INET */
677 #ifdef INET6
678 case SIOCGIFPDSTADDR_IN6:
679 dst = (struct sockaddr *)
680 &(((struct in6_ifreq *)data)->ifr_addr);
681 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
682 break;
683 #endif /* INET6 */
684 default:
685 error = EADDRNOTAVAIL;
686 goto bad;
687 }
688 if (src->sa_len > size)
689 return EINVAL;
690 memcpy(dst, src, src->sa_len);
691 break;
692
693 case SIOCGLIFPHYADDR:
694 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
695 error = EADDRNOTAVAIL;
696 goto bad;
697 }
698
699 /* copy src */
700 src = sc->gif_psrc;
701 dst = (struct sockaddr *)
702 &(((struct if_laddrreq *)data)->addr);
703 size = sizeof(((struct if_laddrreq *)data)->addr);
704 if (src->sa_len > size)
705 return EINVAL;
706 memcpy(dst, src, src->sa_len);
707
708 /* copy dst */
709 src = sc->gif_pdst;
710 dst = (struct sockaddr *)
711 &(((struct if_laddrreq *)data)->dstaddr);
712 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
713 if (src->sa_len > size)
714 return EINVAL;
715 memcpy(dst, src, src->sa_len);
716 break;
717
718 default:
719 return ifioctl_common(ifp, cmd, data);
720 }
721 bad:
722 return error;
723 }
724
725 static int
726 gif_encap_attach(struct gif_softc *sc)
727 {
728 int error;
729
730 if (sc == NULL || sc->gif_psrc == NULL)
731 return EINVAL;
732
733 switch (sc->gif_psrc->sa_family) {
734 #ifdef INET
735 case AF_INET:
736 error = in_gif_attach(sc);
737 break;
738 #endif
739 #ifdef INET6
740 case AF_INET6:
741 error = in6_gif_attach(sc);
742 break;
743 #endif
744 default:
745 error = EINVAL;
746 break;
747 }
748
749 return error;
750 }
751
752 static int
753 gif_encap_detach(struct gif_softc *sc)
754 {
755 int error;
756
757 if (sc == NULL || sc->gif_psrc == NULL)
758 return EINVAL;
759
760 switch (sc->gif_psrc->sa_family) {
761 #ifdef INET
762 case AF_INET:
763 error = in_gif_detach(sc);
764 break;
765 #endif
766 #ifdef INET6
767 case AF_INET6:
768 error = in6_gif_detach(sc);
769 break;
770 #endif
771 default:
772 error = EINVAL;
773 break;
774 }
775
776 return error;
777 }
778
779 static int
780 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
781 {
782 struct gif_softc *sc = ifp->if_softc;
783 struct gif_softc *sc2;
784 struct sockaddr *osrc, *odst;
785 struct sockaddr *nsrc, *ndst;
786 int s;
787 int error;
788
789 s = splsoftnet();
790
791 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
792 if (sc2 == sc)
793 continue;
794 if (!sc2->gif_pdst || !sc2->gif_psrc)
795 continue;
796 /* can't configure same pair of address onto two gifs */
797 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
798 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
799 /* continue to use the old configureation. */
800 splx(s);
801 return EADDRNOTAVAIL;
802 }
803
804 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
805 }
806
807 if ((nsrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
808 splx(s);
809 return ENOMEM;
810 }
811 if ((ndst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
812 sockaddr_free(nsrc);
813 splx(s);
814 return ENOMEM;
815 }
816
817 /* Firstly, clear old configurations. */
818 /* XXX we can detach from both, but be polite just in case */
819 if (sc->gif_psrc)
820 (void)gif_encap_detach(sc);
821
822 /*
823 * Secondly, try to set new configurations.
824 * If the setup failed, rollback to old configurations.
825 */
826 do {
827 osrc = sc->gif_psrc;
828 odst = sc->gif_pdst;
829 sc->gif_psrc = nsrc;
830 sc->gif_pdst = ndst;
831
832 error = gif_encap_attach(sc);
833 if (error) {
834 /* rollback to the last configuration. */
835 nsrc = osrc;
836 ndst = odst;
837 osrc = sc->gif_psrc;
838 odst = sc->gif_pdst;
839
840 continue;
841 }
842 } while (error != 0 && (nsrc != NULL && ndst != NULL));
843 /* Thirdly, even rollback failed, clear configurations. */
844 if (error) {
845 osrc = sc->gif_psrc;
846 odst = sc->gif_pdst;
847 sc->gif_psrc = NULL;
848 sc->gif_pdst = NULL;
849 }
850
851 if (osrc)
852 sockaddr_free(osrc);
853 if (odst)
854 sockaddr_free(odst);
855
856 if (sc->gif_psrc && sc->gif_pdst)
857 ifp->if_flags |= IFF_RUNNING;
858 else
859 ifp->if_flags &= ~IFF_RUNNING;
860
861 splx(s);
862 return error;
863 }
864
865 static void
866 gif_delete_tunnel(struct ifnet *ifp)
867 {
868 struct gif_softc *sc = ifp->if_softc;
869 int s;
870
871 s = splsoftnet();
872
873 if (sc->gif_psrc) {
874 sockaddr_free(sc->gif_psrc);
875 sc->gif_psrc = NULL;
876 }
877 if (sc->gif_pdst) {
878 sockaddr_free(sc->gif_pdst);
879 sc->gif_pdst = NULL;
880 }
881 /* it is safe to detach from both */
882 #ifdef INET
883 (void)in_gif_detach(sc);
884 #endif
885 #ifdef INET6
886 (void)in6_gif_detach(sc);
887 #endif
888
889 if (sc->gif_psrc && sc->gif_pdst)
890 ifp->if_flags |= IFF_RUNNING;
891 else
892 ifp->if_flags &= ~IFF_RUNNING;
893 splx(s);
894 }
895