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