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