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