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