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