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