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