if_gif.c revision 1.134 1 /* $NetBSD: if_gif.c,v 1.134 2017/11/27 05:05:50 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.134 2017/11/27 05:05:50 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 <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 struct m_tag *mtag;
449 int *count;
450
451 mtag = m_tag_find(m, PACKET_TAG_TUNNEL_INFO, NULL);
452 if (mtag != NULL) {
453 count = (int *)(mtag + 1);
454 if (++(*count) > max_gif_nesting) {
455 log(LOG_NOTICE,
456 "%s: recursively called too many times(%d)\n",
457 if_name(ifp),
458 *count);
459 return EIO;
460 }
461 } else {
462 mtag = m_tag_get(PACKET_TAG_TUNNEL_INFO, sizeof(*count),
463 M_NOWAIT);
464 if (mtag != NULL) {
465 m_tag_prepend(m, mtag);
466 count = (int *)(mtag + 1);
467 *count = 0;
468 } else {
469 log(LOG_DEBUG,
470 "%s: m_tag_get() failed, recursion calls are not prevented.\n",
471 if_name(ifp));
472 }
473 }
474
475 return 0;
476 }
477
478 static int
479 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
480 const struct rtentry *rt)
481 {
482 struct gif_softc *sc = ifp->if_softc;
483 struct gif_variant *var = NULL;
484 struct psref psref;
485 int error = 0;
486
487 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
488
489 if ((error = gif_check_nesting(ifp, m)) != 0) {
490 m_free(m);
491 goto end;
492 }
493
494 if ((ifp->if_flags & IFF_UP) == 0) {
495 m_freem(m);
496 error = ENETDOWN;
497 goto end;
498 }
499
500 var = gif_getref_variant(sc, &psref);
501 if (var->gv_psrc == NULL || var->gv_pdst == NULL) {
502 m_freem(m);
503 error = ENETDOWN;
504 goto end;
505 }
506 /* XXX should we check if our outer source is legal? */
507
508 m->m_flags &= ~(M_BCAST|M_MCAST);
509
510 /* use DLT_NULL encapsulation here to pass inner af type */
511 M_PREPEND(m, sizeof(int), M_DONTWAIT);
512 if (!m) {
513 error = ENOBUFS;
514 goto end;
515 }
516 *mtod(m, int *) = dst->sa_family;
517
518 /* Clear checksum-offload flags. */
519 m->m_pkthdr.csum_flags = 0;
520 m->m_pkthdr.csum_data = 0;
521
522 error = gif_transmit_direct(var, m);
523 end:
524 if (var != NULL)
525 gif_putref_variant(var, &psref);
526 if (error)
527 ifp->if_oerrors++;
528 return error;
529 }
530
531 static void
532 gif_start(struct ifnet *ifp)
533 {
534 struct gif_softc *sc;
535 struct gif_variant *var;
536 struct mbuf *m;
537 struct psref psref;
538 int family;
539 int len;
540 int error;
541
542 sc = ifp->if_softc;
543 var = gif_getref_variant(sc, &psref);
544
545 KASSERT(var->gv_output != NULL);
546
547 /* output processing */
548 while (1) {
549 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
550 if (m == NULL)
551 break;
552
553 /* grab and chop off inner af type */
554 if (sizeof(int) > m->m_len) {
555 m = m_pullup(m, sizeof(int));
556 if (!m) {
557 ifp->if_oerrors++;
558 continue;
559 }
560 }
561 family = *mtod(m, int *);
562 bpf_mtap(ifp, m);
563 m_adj(m, sizeof(int));
564
565 len = m->m_pkthdr.len;
566
567 error = var->gv_output(var, family, m);
568 if (error)
569 ifp->if_oerrors++;
570 else {
571 ifp->if_opackets++;
572 ifp->if_obytes += len;
573 }
574 }
575
576 gif_putref_variant(var, &psref);
577 }
578
579 static int
580 gif_transmit(struct ifnet *ifp, struct mbuf *m)
581 {
582 struct gif_softc *sc;
583 struct gif_variant *var;
584 struct psref psref;
585 int error;
586
587 sc = ifp->if_softc;
588
589 /* output processing */
590 if (m == NULL)
591 return EINVAL;
592
593 var = gif_getref_variant(sc, &psref);
594 error = gif_transmit_direct(var, m);
595 gif_putref_variant(var, &psref);
596
597 return error;
598 }
599
600 static int
601 gif_transmit_direct(struct gif_variant *var, struct mbuf *m)
602 {
603 struct ifnet *ifp = &var->gv_softc->gif_if;
604 int error;
605 int family;
606 int len;
607
608 KASSERT(gif_heldref_variant(var));
609 KASSERT(var->gv_output != NULL);
610
611 /* grab and chop off inner af type */
612 if (sizeof(int) > m->m_len) {
613 m = m_pullup(m, sizeof(int));
614 if (!m) {
615 ifp->if_oerrors++;
616 return ENOBUFS;
617 }
618 }
619 family = *mtod(m, int *);
620 bpf_mtap(ifp, m);
621 m_adj(m, sizeof(int));
622
623 len = m->m_pkthdr.len;
624
625 error = var->gv_output(var, family, m);
626 if (error)
627 ifp->if_oerrors++;
628 else {
629 ifp->if_opackets++;
630 ifp->if_obytes += len;
631 }
632
633 return error;
634 }
635
636 void
637 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
638 {
639 pktqueue_t *pktq;
640 size_t pktlen;
641
642 if (ifp == NULL) {
643 /* just in case */
644 m_freem(m);
645 return;
646 }
647
648 m_set_rcvif(m, ifp);
649 pktlen = m->m_pkthdr.len;
650
651 bpf_mtap_af(ifp, af, m);
652
653 /*
654 * Put the packet to the network layer input queue according to the
655 * specified address family. Note: we avoid direct call to the
656 * input function of the network layer in order to avoid recursion.
657 * This may be revisited in the future.
658 */
659 switch (af) {
660 #ifdef INET
661 case AF_INET:
662 pktq = ip_pktq;
663 break;
664 #endif
665 #ifdef INET6
666 case AF_INET6:
667 pktq = ip6_pktq;
668 break;
669 #endif
670 default:
671 m_freem(m);
672 return;
673 }
674
675 #ifdef GIF_MPSAFE
676 const u_int h = curcpu()->ci_index;
677 #else
678 const uint32_t h = pktq_rps_hash(m);
679 #endif
680 if (__predict_true(pktq_enqueue(pktq, m, h))) {
681 ifp->if_ibytes += pktlen;
682 ifp->if_ipackets++;
683 } else {
684 m_freem(m);
685 }
686 }
687
688 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
689 static int
690 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
691 {
692 struct gif_softc *sc = ifp->if_softc;
693 struct ifreq *ifr = (struct ifreq*)data;
694 struct ifaddr *ifa = (struct ifaddr*)data;
695 int error = 0, size, bound;
696 struct sockaddr *dst, *src;
697 struct gif_variant *var;
698 struct psref psref;
699
700 switch (cmd) {
701 case SIOCINITIFADDR:
702 ifp->if_flags |= IFF_UP;
703 ifa->ifa_rtrequest = p2p_rtrequest;
704 break;
705
706 case SIOCADDMULTI:
707 case SIOCDELMULTI:
708 switch (ifr->ifr_addr.sa_family) {
709 #ifdef INET
710 case AF_INET: /* IP supports Multicast */
711 break;
712 #endif /* INET */
713 #ifdef INET6
714 case AF_INET6: /* IP6 supports Multicast */
715 break;
716 #endif /* INET6 */
717 default: /* Other protocols doesn't support Multicast */
718 error = EAFNOSUPPORT;
719 break;
720 }
721 break;
722
723 case SIOCSIFMTU:
724 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
725 return EINVAL;
726 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
727 error = 0;
728 break;
729
730 #ifdef INET
731 case SIOCSIFPHYADDR:
732 #endif
733 #ifdef INET6
734 case SIOCSIFPHYADDR_IN6:
735 #endif /* INET6 */
736 case SIOCSLIFPHYADDR:
737 switch (cmd) {
738 #ifdef INET
739 case SIOCSIFPHYADDR:
740 src = (struct sockaddr *)
741 &(((struct in_aliasreq *)data)->ifra_addr);
742 dst = (struct sockaddr *)
743 &(((struct in_aliasreq *)data)->ifra_dstaddr);
744 break;
745 #endif
746 #ifdef INET6
747 case SIOCSIFPHYADDR_IN6:
748 src = (struct sockaddr *)
749 &(((struct in6_aliasreq *)data)->ifra_addr);
750 dst = (struct sockaddr *)
751 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
752 break;
753 #endif
754 case SIOCSLIFPHYADDR:
755 src = (struct sockaddr *)
756 &(((struct if_laddrreq *)data)->addr);
757 dst = (struct sockaddr *)
758 &(((struct if_laddrreq *)data)->dstaddr);
759 break;
760 default:
761 return EINVAL;
762 }
763
764 /* sa_family must be equal */
765 if (src->sa_family != dst->sa_family)
766 return EINVAL;
767
768 /* validate sa_len */
769 switch (src->sa_family) {
770 #ifdef INET
771 case AF_INET:
772 if (src->sa_len != sizeof(struct sockaddr_in))
773 return EINVAL;
774 break;
775 #endif
776 #ifdef INET6
777 case AF_INET6:
778 if (src->sa_len != sizeof(struct sockaddr_in6))
779 return EINVAL;
780 break;
781 #endif
782 default:
783 return EAFNOSUPPORT;
784 }
785 switch (dst->sa_family) {
786 #ifdef INET
787 case AF_INET:
788 if (dst->sa_len != sizeof(struct sockaddr_in))
789 return EINVAL;
790 break;
791 #endif
792 #ifdef INET6
793 case AF_INET6:
794 if (dst->sa_len != sizeof(struct sockaddr_in6))
795 return EINVAL;
796 break;
797 #endif
798 default:
799 return EAFNOSUPPORT;
800 }
801
802 /* check sa_family looks sane for the cmd */
803 switch (cmd) {
804 case SIOCSIFPHYADDR:
805 if (src->sa_family == AF_INET)
806 break;
807 return EAFNOSUPPORT;
808 #ifdef INET6
809 case SIOCSIFPHYADDR_IN6:
810 if (src->sa_family == AF_INET6)
811 break;
812 return EAFNOSUPPORT;
813 #endif /* INET6 */
814 case SIOCSLIFPHYADDR:
815 /* checks done in the above */
816 break;
817 }
818 /*
819 * calls gif_getref_variant() for other softcs to check
820 * address pair duplicattion
821 */
822 bound = curlwp_bind();
823 error = gif_set_tunnel(&sc->gif_if, src, dst);
824 curlwp_bindx(bound);
825 break;
826
827 #ifdef SIOCDIFPHYADDR
828 case SIOCDIFPHYADDR:
829 bound = curlwp_bind();
830 gif_delete_tunnel(&sc->gif_if);
831 curlwp_bindx(bound);
832 break;
833 #endif
834
835 case SIOCGIFPSRCADDR:
836 #ifdef INET6
837 case SIOCGIFPSRCADDR_IN6:
838 #endif /* INET6 */
839 bound = curlwp_bind();
840 var = gif_getref_variant(sc, &psref);
841 if (var->gv_psrc == NULL) {
842 gif_putref_variant(var, &psref);
843 curlwp_bindx(bound);
844 error = EADDRNOTAVAIL;
845 goto bad;
846 }
847 src = var->gv_psrc;
848 switch (cmd) {
849 #ifdef INET
850 case SIOCGIFPSRCADDR:
851 dst = &ifr->ifr_addr;
852 size = sizeof(ifr->ifr_addr);
853 break;
854 #endif /* INET */
855 #ifdef INET6
856 case SIOCGIFPSRCADDR_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 gif_putref_variant(var, &psref);
864 curlwp_bindx(bound);
865 error = EADDRNOTAVAIL;
866 goto bad;
867 }
868 if (src->sa_len > size) {
869 gif_putref_variant(var, &psref);
870 curlwp_bindx(bound);
871 return EINVAL;
872 }
873 memcpy(dst, src, src->sa_len);
874 gif_putref_variant(var, &psref);
875 curlwp_bindx(bound);
876 break;
877
878 case SIOCGIFPDSTADDR:
879 #ifdef INET6
880 case SIOCGIFPDSTADDR_IN6:
881 #endif /* INET6 */
882 bound = curlwp_bind();
883 var = gif_getref_variant(sc, &psref);
884 if (var->gv_pdst == NULL) {
885 gif_putref_variant(var, &psref);
886 curlwp_bindx(bound);
887 error = EADDRNOTAVAIL;
888 goto bad;
889 }
890 src = var->gv_pdst;
891 switch (cmd) {
892 #ifdef INET
893 case SIOCGIFPDSTADDR:
894 dst = &ifr->ifr_addr;
895 size = sizeof(ifr->ifr_addr);
896 break;
897 #endif /* INET */
898 #ifdef INET6
899 case SIOCGIFPDSTADDR_IN6:
900 dst = (struct sockaddr *)
901 &(((struct in6_ifreq *)data)->ifr_addr);
902 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
903 break;
904 #endif /* INET6 */
905 default:
906 gif_putref_variant(var, &psref);
907 curlwp_bindx(bound);
908 error = EADDRNOTAVAIL;
909 goto bad;
910 }
911 if (src->sa_len > size) {
912 gif_putref_variant(var, &psref);
913 curlwp_bindx(bound);
914 return EINVAL;
915 }
916 memcpy(dst, src, src->sa_len);
917 gif_putref_variant(var, &psref);
918 curlwp_bindx(bound);
919 break;
920
921 case SIOCGLIFPHYADDR:
922 bound = curlwp_bind();
923 var = gif_getref_variant(sc, &psref);
924 if (var->gv_psrc == NULL || var->gv_pdst == NULL) {
925 gif_putref_variant(var, &psref);
926 curlwp_bindx(bound);
927 error = EADDRNOTAVAIL;
928 goto bad;
929 }
930
931 /* copy src */
932 src = var->gv_psrc;
933 dst = (struct sockaddr *)
934 &(((struct if_laddrreq *)data)->addr);
935 size = sizeof(((struct if_laddrreq *)data)->addr);
936 if (src->sa_len > size) {
937 gif_putref_variant(var, &psref);
938 curlwp_bindx(bound);
939 return EINVAL;
940 }
941 memcpy(dst, src, src->sa_len);
942
943 /* copy dst */
944 src = var->gv_pdst;
945 dst = (struct sockaddr *)
946 &(((struct if_laddrreq *)data)->dstaddr);
947 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
948 if (src->sa_len > size) {
949 gif_putref_variant(var, &psref);
950 curlwp_bindx(bound);
951 return EINVAL;
952 }
953 memcpy(dst, src, src->sa_len);
954 gif_putref_variant(var, &psref);
955 curlwp_bindx(bound);
956 break;
957
958 default:
959 return ifioctl_common(ifp, cmd, data);
960 }
961 bad:
962 return error;
963 }
964
965 static int
966 gif_encap_attach(struct gif_variant *var)
967 {
968 int error;
969
970 if (var == NULL || var->gv_psrc == NULL)
971 return EINVAL;
972
973 switch (var->gv_psrc->sa_family) {
974 #ifdef INET
975 case AF_INET:
976 error = in_gif_attach(var);
977 break;
978 #endif
979 #ifdef INET6
980 case AF_INET6:
981 error = in6_gif_attach(var);
982 break;
983 #endif
984 default:
985 error = EINVAL;
986 break;
987 }
988
989 return error;
990 }
991
992 static int
993 gif_encap_detach(struct gif_variant *var)
994 {
995 int error;
996
997 if (var == NULL || var->gv_psrc == NULL)
998 return EINVAL;
999
1000 switch (var->gv_psrc->sa_family) {
1001 #ifdef INET
1002 case AF_INET:
1003 error = in_gif_detach(var);
1004 break;
1005 #endif
1006 #ifdef INET6
1007 case AF_INET6:
1008 error = in6_gif_detach(var);
1009 break;
1010 #endif
1011 default:
1012 error = EINVAL;
1013 break;
1014 }
1015
1016 return error;
1017 }
1018
1019 static int
1020 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
1021 {
1022 struct gif_softc *sc = ifp->if_softc;
1023 struct gif_softc *sc2;
1024 struct gif_variant *ovar, *nvar;
1025 struct sockaddr *osrc, *odst;
1026 struct sockaddr *nsrc, *ndst;
1027 int error;
1028 #ifndef GIF_MPSAFE
1029 int s;
1030
1031 s = splsoftnet();
1032 #endif
1033 error = encap_lock_enter();
1034 if (error) {
1035 #ifndef GIF_MPSAFE
1036 splx(s);
1037 #endif
1038 return error;
1039 }
1040
1041 nsrc = sockaddr_dup(src, M_WAITOK);
1042 ndst = sockaddr_dup(dst, M_WAITOK);
1043 nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP);
1044
1045 mutex_enter(&sc->gif_lock);
1046
1047 ovar = sc->gif_var;
1048
1049 if ((ovar->gv_pdst && sockaddr_cmp(ovar->gv_pdst, dst) == 0) &&
1050 (ovar->gv_psrc && sockaddr_cmp(ovar->gv_psrc, src) == 0)) {
1051 /* address and port pair not changed. */
1052 error = 0;
1053 goto out;
1054 }
1055
1056 mutex_enter(&gif_softcs.lock);
1057 LIST_FOREACH(sc2, &gif_softcs.list, gif_list) {
1058 struct gif_variant *var2;
1059 struct psref psref;
1060
1061 if (sc2 == sc)
1062 continue;
1063 var2 = gif_getref_variant(sc, &psref);
1064 if (!var2->gv_pdst || !var2->gv_psrc) {
1065 gif_putref_variant(var2, &psref);
1066 continue;
1067 }
1068 /* can't configure same pair of address onto two gifs */
1069 if (sockaddr_cmp(var2->gv_pdst, dst) == 0 &&
1070 sockaddr_cmp(var2->gv_psrc, src) == 0) {
1071 /* continue to use the old configureation. */
1072 gif_putref_variant(var2, &psref);
1073 mutex_exit(&gif_softcs.lock);
1074 error = EADDRNOTAVAIL;
1075 goto out;
1076 }
1077 gif_putref_variant(var2, &psref);
1078 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
1079 }
1080 mutex_exit(&gif_softcs.lock);
1081
1082 osrc = ovar->gv_psrc;
1083 odst = ovar->gv_pdst;
1084
1085 *nvar = *ovar;
1086 nvar->gv_psrc = nsrc;
1087 nvar->gv_pdst = ndst;
1088 nvar->gv_encap_cookie4 = NULL;
1089 nvar->gv_encap_cookie6 = NULL;
1090 error = gif_encap_attach(nvar);
1091 if (error)
1092 goto out;
1093 psref_target_init(&nvar->gv_psref, gv_psref_class);
1094 membar_producer();
1095 gif_update_variant(sc, nvar);
1096
1097 mutex_exit(&sc->gif_lock);
1098
1099 (void)gif_encap_detach(ovar);
1100 encap_lock_exit();
1101
1102 if (osrc)
1103 sockaddr_free(osrc);
1104 if (odst)
1105 sockaddr_free(odst);
1106 kmem_free(ovar, sizeof(*ovar));
1107
1108 #ifndef GIF_MPSAFE
1109 splx(s);
1110 #endif
1111 return 0;
1112
1113 out:
1114 sockaddr_free(nsrc);
1115 sockaddr_free(ndst);
1116 kmem_free(nvar, sizeof(*nvar));
1117
1118 mutex_exit(&sc->gif_lock);
1119 encap_lock_exit();
1120 #ifndef GIF_MPSAFE
1121 splx(s);
1122 #endif
1123 return error;
1124 }
1125
1126 static void
1127 gif_delete_tunnel(struct ifnet *ifp)
1128 {
1129 struct gif_softc *sc = ifp->if_softc;
1130 struct gif_variant *ovar, *nvar;
1131 struct sockaddr *osrc, *odst;
1132 int error;
1133 #ifndef GIF_MPSAFE
1134 int s;
1135
1136 s = splsoftnet();
1137 #endif
1138 error = encap_lock_enter();
1139 if (error) {
1140 #ifndef GIF_MPSAFE
1141 splx(s);
1142 #endif
1143 return;
1144 }
1145
1146 nvar = kmem_alloc(sizeof(*nvar), KM_SLEEP);
1147
1148 mutex_enter(&sc->gif_lock);
1149
1150 ovar = sc->gif_var;
1151 osrc = ovar->gv_psrc;
1152 odst = ovar->gv_pdst;
1153 if (osrc == NULL || odst == NULL) {
1154 /* address pair not changed. */
1155 mutex_exit(&sc->gif_lock);
1156 encap_lock_exit();
1157 kmem_free(nvar, sizeof(*nvar));
1158 return;
1159 }
1160
1161 *nvar = *ovar;
1162 nvar->gv_psrc = NULL;
1163 nvar->gv_pdst = NULL;
1164 nvar->gv_encap_cookie4 = NULL;
1165 nvar->gv_encap_cookie6 = NULL;
1166 nvar->gv_output = NULL;
1167 psref_target_init(&nvar->gv_psref, gv_psref_class);
1168 membar_producer();
1169 gif_update_variant(sc, nvar);
1170
1171 mutex_exit(&sc->gif_lock);
1172
1173 gif_encap_detach(ovar);
1174 encap_lock_exit();
1175
1176 sockaddr_free(osrc);
1177 sockaddr_free(odst);
1178 kmem_free(ovar, sizeof(*ovar));
1179
1180 #ifndef GIF_MPSAFE
1181 splx(s);
1182 #endif
1183 }
1184
1185 /*
1186 * gif_variant update API.
1187 *
1188 * Assumption:
1189 * reader side dereferences sc->gif_var in reader critical section only,
1190 * that is, all of reader sides do not reader the sc->gif_var after
1191 * pserialize_perform().
1192 */
1193 static void
1194 gif_update_variant(struct gif_softc *sc, struct gif_variant *nvar)
1195 {
1196 struct ifnet *ifp = &sc->gif_if;
1197 struct gif_variant *ovar = sc->gif_var;
1198
1199 KASSERT(mutex_owned(&sc->gif_lock));
1200
1201 sc->gif_var = nvar;
1202 pserialize_perform(gif_psz);
1203 psref_target_destroy(&ovar->gv_psref, gv_psref_class);
1204
1205 if (nvar->gv_psrc != NULL && nvar->gv_pdst != NULL)
1206 ifp->if_flags |= IFF_RUNNING;
1207 else
1208 ifp->if_flags &= ~IFF_RUNNING;
1209 }
1210
1211 /*
1212 * Module infrastructure
1213 */
1214 #include "if_module.h"
1215
1216 IF_MODULE(MODULE_CLASS_DRIVER, gif, "")
1217