FreeBSD/Linux Kernel Cross Reference
sys/net/if_gif.c
1 /* $FreeBSD: releng/7.4/sys/net/if_gif.c 215368 2010-11-16 04:40:03Z sobomax $ */
2 /* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun 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 "opt_inet.h"
34 #include "opt_inet6.h"
35 #include "opt_mac.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/module.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <sys/sysctl.h>
48 #include <sys/syslog.h>
49 #include <sys/priv.h>
50 #include <sys/proc.h>
51 #include <sys/protosw.h>
52 #include <sys/conf.h>
53 #include <machine/cpu.h>
54
55 #include <net/if.h>
56 #include <net/if_clone.h>
57 #include <net/if_types.h>
58 #include <net/netisr.h>
59 #include <net/route.h>
60 #include <net/bpf.h>
61
62 #include <netinet/in.h>
63 #include <netinet/in_systm.h>
64 #include <netinet/ip.h>
65 #ifdef INET
66 #include <netinet/in_var.h>
67 #include <netinet/in_gif.h>
68 #include <netinet/ip_var.h>
69 #endif /* INET */
70
71 #ifdef INET6
72 #ifndef INET
73 #include <netinet/in.h>
74 #endif
75 #include <netinet6/in6_var.h>
76 #include <netinet/ip6.h>
77 #include <netinet6/ip6_var.h>
78 #include <netinet6/scope6_var.h>
79 #include <netinet6/in6_gif.h>
80 #include <netinet6/ip6protosw.h>
81 #endif /* INET6 */
82
83 #include <netinet/ip_encap.h>
84 #include <net/ethernet.h>
85 #include <net/if_bridgevar.h>
86 #include <net/if_gif.h>
87
88 #include <security/mac/mac_framework.h>
89
90 #define GIFNAME "gif"
91
92 /*
93 * gif_mtx protects the global gif_softc_list.
94 */
95 static struct mtx gif_mtx;
96 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
97 static LIST_HEAD(, gif_softc) gif_softc_list;
98
99 void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
100 void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
101 void (*ng_gif_attach_p)(struct ifnet *ifp);
102 void (*ng_gif_detach_p)(struct ifnet *ifp);
103
104 static void gif_start(struct ifnet *);
105 static int gif_clone_create(struct if_clone *, int, caddr_t);
106 static void gif_clone_destroy(struct ifnet *);
107
108 IFC_SIMPLE_DECLARE(gif, 0);
109
110 static int gifmodevent(module_t, int, void *);
111
112 SYSCTL_DECL(_net_link);
113 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
114 "Generic Tunnel Interface");
115 #ifndef MAX_GIF_NEST
116 /*
117 * This macro controls the default upper limitation on nesting of gif tunnels.
118 * Since, setting a large value to this macro with a careless configuration
119 * may introduce system crash, we don't allow any nestings by default.
120 * If you need to configure nested gif tunnels, you can define this macro
121 * in your kernel configuration file. However, if you do so, please be
122 * careful to configure the tunnels so that it won't make a loop.
123 */
124 #define MAX_GIF_NEST 1
125 #endif
126 static int max_gif_nesting = MAX_GIF_NEST;
127 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
128 &max_gif_nesting, 0, "Max nested tunnels");
129
130 /*
131 * By default, we disallow creation of multiple tunnels between the same
132 * pair of addresses. Some applications require this functionality so
133 * we allow control over this check here.
134 */
135 #ifdef XBONEHACK
136 static int parallel_tunnels = 1;
137 #else
138 static int parallel_tunnels = 0;
139 #endif
140 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
141 ¶llel_tunnels, 0, "Allow parallel tunnels?");
142
143 /* copy from src/sys/net/if_ethersubr.c */
144 static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
145 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
146 #ifndef ETHER_IS_BROADCAST
147 #define ETHER_IS_BROADCAST(addr) \
148 (bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0)
149 #endif
150
151 static int
152 gif_clone_create(ifc, unit, params)
153 struct if_clone *ifc;
154 int unit;
155 caddr_t params;
156 {
157 struct gif_softc *sc;
158
159 sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
160 sc->gif_fibnum = curthread->td_proc->p_fibnum;
161 GIF2IFP(sc) = if_alloc(IFT_GIF);
162 if (GIF2IFP(sc) == NULL) {
163 free(sc, M_GIF);
164 return (ENOSPC);
165 }
166
167 GIF_LOCK_INIT(sc);
168
169 GIF2IFP(sc)->if_softc = sc;
170 if_initname(GIF2IFP(sc), ifc->ifc_name, unit);
171
172 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
173 sc->gif_options = GIF_ACCEPT_REVETHIP;
174
175 GIF2IFP(sc)->if_addrlen = 0;
176 GIF2IFP(sc)->if_mtu = GIF_MTU;
177 GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
178 #if 0
179 /* turn off ingress filter */
180 GIF2IFP(sc)->if_flags |= IFF_LINK2;
181 #endif
182 GIF2IFP(sc)->if_ioctl = gif_ioctl;
183 GIF2IFP(sc)->if_start = gif_start;
184 GIF2IFP(sc)->if_output = gif_output;
185 GIF2IFP(sc)->if_snd.ifq_maxlen = ifqmaxlen;
186 if_attach(GIF2IFP(sc));
187 bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
188 if (ng_gif_attach_p != NULL)
189 (*ng_gif_attach_p)(GIF2IFP(sc));
190
191 mtx_lock(&gif_mtx);
192 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
193 mtx_unlock(&gif_mtx);
194
195 return (0);
196 }
197
198 static void
199 gif_clone_destroy(ifp)
200 struct ifnet *ifp;
201 {
202 int err;
203 struct gif_softc *sc = ifp->if_softc;
204
205 mtx_lock(&gif_mtx);
206 LIST_REMOVE(sc, gif_list);
207 mtx_unlock(&gif_mtx);
208
209 gif_delete_tunnel(ifp);
210 #ifdef INET6
211 if (sc->encap_cookie6 != NULL) {
212 err = encap_detach(sc->encap_cookie6);
213 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
214 }
215 #endif
216 #ifdef INET
217 if (sc->encap_cookie4 != NULL) {
218 err = encap_detach(sc->encap_cookie4);
219 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
220 }
221 #endif
222
223 if (ng_gif_detach_p != NULL)
224 (*ng_gif_detach_p)(ifp);
225 bpfdetach(ifp);
226 if_detach(ifp);
227 if_free(ifp);
228
229 GIF_LOCK_DESTROY(sc);
230
231 free(sc, M_GIF);
232 }
233
234 static int
235 gifmodevent(mod, type, data)
236 module_t mod;
237 int type;
238 void *data;
239 {
240
241 switch (type) {
242 case MOD_LOAD:
243 mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF);
244 LIST_INIT(&gif_softc_list);
245 if_clone_attach(&gif_cloner);
246
247 #ifdef INET6
248 ip6_gif_hlim = GIF_HLIM;
249 #endif
250
251 break;
252 case MOD_UNLOAD:
253 if_clone_detach(&gif_cloner);
254 mtx_destroy(&gif_mtx);
255 #ifdef INET6
256 ip6_gif_hlim = 0;
257 #endif
258 break;
259 default:
260 return EOPNOTSUPP;
261 }
262 return 0;
263 }
264
265 static moduledata_t gif_mod = {
266 "if_gif",
267 gifmodevent,
268 0
269 };
270
271 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
272 MODULE_VERSION(if_gif, 1);
273
274 int
275 gif_encapcheck(m, off, proto, arg)
276 const struct mbuf *m;
277 int off;
278 int proto;
279 void *arg;
280 {
281 struct ip ip;
282 struct gif_softc *sc;
283
284 sc = (struct gif_softc *)arg;
285 if (sc == NULL)
286 return 0;
287
288 if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0)
289 return 0;
290
291 /* no physical address */
292 if (!sc->gif_psrc || !sc->gif_pdst)
293 return 0;
294
295 switch (proto) {
296 #ifdef INET
297 case IPPROTO_IPV4:
298 break;
299 #endif
300 #ifdef INET6
301 case IPPROTO_IPV6:
302 break;
303 #endif
304 case IPPROTO_ETHERIP:
305 break;
306
307 default:
308 return 0;
309 }
310
311 /* Bail on short packets */
312 if (m->m_pkthdr.len < sizeof(ip))
313 return 0;
314
315 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
316
317 switch (ip.ip_v) {
318 #ifdef INET
319 case 4:
320 if (sc->gif_psrc->sa_family != AF_INET ||
321 sc->gif_pdst->sa_family != AF_INET)
322 return 0;
323 return gif_encapcheck4(m, off, proto, arg);
324 #endif
325 #ifdef INET6
326 case 6:
327 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
328 return 0;
329 if (sc->gif_psrc->sa_family != AF_INET6 ||
330 sc->gif_pdst->sa_family != AF_INET6)
331 return 0;
332 return gif_encapcheck6(m, off, proto, arg);
333 #endif
334 default:
335 return 0;
336 }
337 }
338
339 static void
340 gif_start(struct ifnet *ifp)
341 {
342 struct gif_softc *sc;
343 struct mbuf *m;
344
345 sc = ifp->if_softc;
346
347 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
348 for (;;) {
349 IFQ_DEQUEUE(&ifp->if_snd, m);
350 if (m == 0)
351 break;
352
353 gif_output(ifp, m, sc->gif_pdst, NULL);
354
355 }
356 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
357
358 return;
359 }
360
361 int
362 gif_output(ifp, m, dst, rt)
363 struct ifnet *ifp;
364 struct mbuf *m;
365 struct sockaddr *dst;
366 struct rtentry *rt; /* added in net2 */
367 {
368 struct gif_softc *sc = ifp->if_softc;
369 struct m_tag *mtag;
370 int error = 0;
371 int gif_called;
372 u_int32_t af;
373
374 #ifdef MAC
375 error = mac_check_ifnet_transmit(ifp, m);
376 if (error) {
377 m_freem(m);
378 goto end;
379 }
380 #endif
381
382 /*
383 * gif may cause infinite recursion calls when misconfigured.
384 * We'll prevent this by detecting loops.
385 *
386 * High nesting level may cause stack exhaustion.
387 * We'll prevent this by introducing upper limit.
388 */
389 gif_called = 1;
390 mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL);
391 while (mtag != NULL) {
392 if (*(struct ifnet **)(mtag + 1) == ifp) {
393 log(LOG_NOTICE,
394 "gif_output: loop detected on %s\n",
395 (*(struct ifnet **)(mtag + 1))->if_xname);
396 m_freem(m);
397 error = EIO; /* is there better errno? */
398 goto end;
399 }
400 mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag);
401 gif_called++;
402 }
403 if (gif_called > max_gif_nesting) {
404 log(LOG_NOTICE,
405 "gif_output: recursively called too many times(%d)\n",
406 gif_called);
407 m_freem(m);
408 error = EIO; /* is there better errno? */
409 goto end;
410 }
411 mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *),
412 M_NOWAIT);
413 if (mtag == NULL) {
414 m_freem(m);
415 error = ENOMEM;
416 goto end;
417 }
418 *(struct ifnet **)(mtag + 1) = ifp;
419 m_tag_prepend(m, mtag);
420
421 m->m_flags &= ~(M_BCAST|M_MCAST);
422
423 GIF_LOCK(sc);
424
425 if (!(ifp->if_flags & IFF_UP) ||
426 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
427 GIF_UNLOCK(sc);
428 m_freem(m);
429 error = ENETDOWN;
430 goto end;
431 }
432
433 /* BPF writes need to be handled specially. */
434 if (dst->sa_family == AF_UNSPEC) {
435 bcopy(dst->sa_data, &af, sizeof(af));
436 dst->sa_family = af;
437 }
438
439 af = dst->sa_family;
440 BPF_MTAP2(ifp, &af, sizeof(af), m);
441 ifp->if_opackets++;
442 ifp->if_obytes += m->m_pkthdr.len;
443
444 /* override to IPPROTO_ETHERIP for bridged traffic */
445 if (ifp->if_bridge)
446 af = AF_LINK;
447
448 M_SETFIB(m, sc->gif_fibnum);
449 /* inner AF-specific encapsulation */
450
451 /* XXX should we check if our outer source is legal? */
452
453 /* dispatch to output logic based on outer AF */
454 switch (sc->gif_psrc->sa_family) {
455 #ifdef INET
456 case AF_INET:
457 error = in_gif_output(ifp, af, m);
458 break;
459 #endif
460 #ifdef INET6
461 case AF_INET6:
462 error = in6_gif_output(ifp, af, m);
463 break;
464 #endif
465 default:
466 m_freem(m);
467 error = ENETDOWN;
468 }
469
470 GIF_UNLOCK(sc);
471 end:
472 if (error)
473 ifp->if_oerrors++;
474 return (error);
475 }
476
477 void
478 gif_input(m, af, ifp)
479 struct mbuf *m;
480 int af;
481 struct ifnet *ifp;
482 {
483 int isr, n;
484 struct gif_softc *sc = ifp->if_softc;
485 struct etherip_header *eip;
486 struct ether_header *eh;
487 struct ifnet *oldifp;
488
489 if (ifp == NULL) {
490 /* just in case */
491 m_freem(m);
492 return;
493 }
494
495 m->m_pkthdr.rcvif = ifp;
496
497 #ifdef MAC
498 mac_create_mbuf_from_ifnet(ifp, m);
499 #endif
500
501 if (bpf_peers_present(ifp->if_bpf)) {
502 u_int32_t af1 = af;
503 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
504 }
505
506 if (ng_gif_input_p != NULL) {
507 (*ng_gif_input_p)(ifp, &m, af);
508 if (m == NULL)
509 return;
510 }
511
512 /*
513 * Put the packet to the network layer input queue according to the
514 * specified address family.
515 * Note: older versions of gif_input directly called network layer
516 * input functions, e.g. ip6_input, here. We changed the policy to
517 * prevent too many recursive calls of such input functions, which
518 * might cause kernel panic. But the change may introduce another
519 * problem; if the input queue is full, packets are discarded.
520 * The kernel stack overflow really happened, and we believed
521 * queue-full rarely occurs, so we changed the policy.
522 */
523 switch (af) {
524 #ifdef INET
525 case AF_INET:
526 isr = NETISR_IP;
527 break;
528 #endif
529 #ifdef INET6
530 case AF_INET6:
531 isr = NETISR_IPV6;
532 break;
533 #endif
534 case AF_LINK:
535 n = sizeof(struct etherip_header) + sizeof(struct ether_header);
536 if (n > m->m_len) {
537 m = m_pullup(m, n);
538 if (m == NULL) {
539 ifp->if_ierrors++;
540 return;
541 }
542 }
543
544 eip = mtod(m, struct etherip_header *);
545 /*
546 * GIF_ACCEPT_REVETHIP (enabled by default) intentionally
547 * accepts an EtherIP packet with revered version field in
548 * the header. This is a knob for backward compatibility
549 * with FreeBSD 7.2R or prior.
550 */
551 if (sc->gif_options & GIF_ACCEPT_REVETHIP) {
552 if (eip->eip_resvl != ETHERIP_VERSION
553 && eip->eip_ver != ETHERIP_VERSION) {
554 /* discard unknown versions */
555 m_freem(m);
556 return;
557 }
558 } else {
559 if (eip->eip_ver != ETHERIP_VERSION) {
560 /* discard unknown versions */
561 m_freem(m);
562 return;
563 }
564 }
565 m_adj(m, sizeof(struct etherip_header));
566
567 m->m_flags &= ~(M_BCAST|M_MCAST);
568 m->m_pkthdr.rcvif = ifp;
569
570 if (ifp->if_bridge) {
571 oldifp = ifp;
572 eh = mtod(m, struct ether_header *);
573 if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
574 if (ETHER_IS_BROADCAST(eh->ether_dhost))
575 m->m_flags |= M_BCAST;
576 else
577 m->m_flags |= M_MCAST;
578 ifp->if_imcasts++;
579 }
580 BRIDGE_INPUT(ifp, m);
581
582 if (m != NULL && ifp != oldifp) {
583 /*
584 * The bridge gave us back itself or one of the
585 * members for which the frame is addressed.
586 */
587 ether_demux(ifp, m);
588 return;
589 }
590 }
591 if (m != NULL)
592 m_freem(m);
593 return;
594
595 default:
596 if (ng_gif_input_orphan_p != NULL)
597 (*ng_gif_input_orphan_p)(ifp, m, af);
598 else
599 m_freem(m);
600 return;
601 }
602
603 ifp->if_ipackets++;
604 ifp->if_ibytes += m->m_pkthdr.len;
605 netisr_dispatch(isr, m);
606 }
607
608 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
609 int
610 gif_ioctl(ifp, cmd, data)
611 struct ifnet *ifp;
612 u_long cmd;
613 caddr_t data;
614 {
615 struct gif_softc *sc = ifp->if_softc;
616 struct ifreq *ifr = (struct ifreq*)data;
617 int error = 0, size;
618 u_int options;
619 struct sockaddr *dst, *src;
620 #ifdef SIOCSIFMTU /* xxx */
621 u_long mtu;
622 #endif
623
624 switch (cmd) {
625 case SIOCSIFADDR:
626 ifp->if_flags |= IFF_UP;
627 break;
628
629 case SIOCSIFDSTADDR:
630 break;
631
632 case SIOCADDMULTI:
633 case SIOCDELMULTI:
634 break;
635
636 #ifdef SIOCSIFMTU /* xxx */
637 case SIOCGIFMTU:
638 break;
639
640 case SIOCSIFMTU:
641 mtu = ifr->ifr_mtu;
642 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
643 return (EINVAL);
644 ifp->if_mtu = mtu;
645 break;
646 #endif /* SIOCSIFMTU */
647
648 #ifdef INET
649 case SIOCSIFPHYADDR:
650 #endif
651 #ifdef INET6
652 case SIOCSIFPHYADDR_IN6:
653 #endif /* INET6 */
654 case SIOCSLIFPHYADDR:
655 switch (cmd) {
656 #ifdef INET
657 case SIOCSIFPHYADDR:
658 src = (struct sockaddr *)
659 &(((struct in_aliasreq *)data)->ifra_addr);
660 dst = (struct sockaddr *)
661 &(((struct in_aliasreq *)data)->ifra_dstaddr);
662 break;
663 #endif
664 #ifdef INET6
665 case SIOCSIFPHYADDR_IN6:
666 src = (struct sockaddr *)
667 &(((struct in6_aliasreq *)data)->ifra_addr);
668 dst = (struct sockaddr *)
669 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
670 break;
671 #endif
672 case SIOCSLIFPHYADDR:
673 src = (struct sockaddr *)
674 &(((struct if_laddrreq *)data)->addr);
675 dst = (struct sockaddr *)
676 &(((struct if_laddrreq *)data)->dstaddr);
677 break;
678 default:
679 return EINVAL;
680 }
681
682 /* sa_family must be equal */
683 if (src->sa_family != dst->sa_family)
684 return EINVAL;
685
686 /* validate sa_len */
687 switch (src->sa_family) {
688 #ifdef INET
689 case AF_INET:
690 if (src->sa_len != sizeof(struct sockaddr_in))
691 return EINVAL;
692 break;
693 #endif
694 #ifdef INET6
695 case AF_INET6:
696 if (src->sa_len != sizeof(struct sockaddr_in6))
697 return EINVAL;
698 break;
699 #endif
700 default:
701 return EAFNOSUPPORT;
702 }
703 switch (dst->sa_family) {
704 #ifdef INET
705 case AF_INET:
706 if (dst->sa_len != sizeof(struct sockaddr_in))
707 return EINVAL;
708 break;
709 #endif
710 #ifdef INET6
711 case AF_INET6:
712 if (dst->sa_len != sizeof(struct sockaddr_in6))
713 return EINVAL;
714 break;
715 #endif
716 default:
717 return EAFNOSUPPORT;
718 }
719
720 /* check sa_family looks sane for the cmd */
721 switch (cmd) {
722 case SIOCSIFPHYADDR:
723 if (src->sa_family == AF_INET)
724 break;
725 return EAFNOSUPPORT;
726 #ifdef INET6
727 case SIOCSIFPHYADDR_IN6:
728 if (src->sa_family == AF_INET6)
729 break;
730 return EAFNOSUPPORT;
731 #endif /* INET6 */
732 case SIOCSLIFPHYADDR:
733 /* checks done in the above */
734 break;
735 }
736
737 error = gif_set_tunnel(GIF2IFP(sc), src, dst);
738 break;
739
740 #ifdef SIOCDIFPHYADDR
741 case SIOCDIFPHYADDR:
742 gif_delete_tunnel(GIF2IFP(sc));
743 break;
744 #endif
745
746 case SIOCGIFPSRCADDR:
747 #ifdef INET6
748 case SIOCGIFPSRCADDR_IN6:
749 #endif /* INET6 */
750 if (sc->gif_psrc == NULL) {
751 error = EADDRNOTAVAIL;
752 goto bad;
753 }
754 src = sc->gif_psrc;
755 switch (cmd) {
756 #ifdef INET
757 case SIOCGIFPSRCADDR:
758 dst = &ifr->ifr_addr;
759 size = sizeof(ifr->ifr_addr);
760 break;
761 #endif /* INET */
762 #ifdef INET6
763 case SIOCGIFPSRCADDR_IN6:
764 dst = (struct sockaddr *)
765 &(((struct in6_ifreq *)data)->ifr_addr);
766 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
767 break;
768 #endif /* INET6 */
769 default:
770 error = EADDRNOTAVAIL;
771 goto bad;
772 }
773 if (src->sa_len > size)
774 return EINVAL;
775 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
776 #ifdef INET6
777 if (dst->sa_family == AF_INET6) {
778 error = sa6_recoverscope((struct sockaddr_in6 *)dst);
779 if (error != 0)
780 return (error);
781 }
782 #endif
783 break;
784
785 case SIOCGIFPDSTADDR:
786 #ifdef INET6
787 case SIOCGIFPDSTADDR_IN6:
788 #endif /* INET6 */
789 if (sc->gif_pdst == NULL) {
790 error = EADDRNOTAVAIL;
791 goto bad;
792 }
793 src = sc->gif_pdst;
794 switch (cmd) {
795 #ifdef INET
796 case SIOCGIFPDSTADDR:
797 dst = &ifr->ifr_addr;
798 size = sizeof(ifr->ifr_addr);
799 break;
800 #endif /* INET */
801 #ifdef INET6
802 case SIOCGIFPDSTADDR_IN6:
803 dst = (struct sockaddr *)
804 &(((struct in6_ifreq *)data)->ifr_addr);
805 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
806 break;
807 #endif /* INET6 */
808 default:
809 error = EADDRNOTAVAIL;
810 goto bad;
811 }
812 if (src->sa_len > size)
813 return EINVAL;
814 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
815 #ifdef INET6
816 if (dst->sa_family == AF_INET6) {
817 error = sa6_recoverscope((struct sockaddr_in6 *)dst);
818 if (error != 0)
819 return (error);
820 }
821 #endif
822 break;
823
824 case SIOCGLIFPHYADDR:
825 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
826 error = EADDRNOTAVAIL;
827 goto bad;
828 }
829
830 /* copy src */
831 src = sc->gif_psrc;
832 dst = (struct sockaddr *)
833 &(((struct if_laddrreq *)data)->addr);
834 size = sizeof(((struct if_laddrreq *)data)->addr);
835 if (src->sa_len > size)
836 return EINVAL;
837 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
838
839 /* copy dst */
840 src = sc->gif_pdst;
841 dst = (struct sockaddr *)
842 &(((struct if_laddrreq *)data)->dstaddr);
843 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
844 if (src->sa_len > size)
845 return EINVAL;
846 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
847 break;
848
849 case SIOCSIFFLAGS:
850 /* if_ioctl() takes care of it */
851 break;
852
853 case GIFGOPTS:
854 options = sc->gif_options;
855 error = copyout(&options, ifr->ifr_data,
856 sizeof(options));
857 break;
858
859 case GIFSOPTS:
860 if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
861 break;
862 error = copyin(ifr->ifr_data, &options, sizeof(options));
863 if (error)
864 break;
865 if (options & ~GIF_OPTMASK)
866 error = EINVAL;
867 else
868 sc->gif_options = options;
869 break;
870
871 default:
872 error = EINVAL;
873 break;
874 }
875 bad:
876 return error;
877 }
878
879 /*
880 * XXXRW: There's a general event-ordering issue here: the code to check
881 * if a given tunnel is already present happens before we perform a
882 * potentially blocking setup of the tunnel. This code needs to be
883 * re-ordered so that the check and replacement can be atomic using
884 * a mutex.
885 */
886 int
887 gif_set_tunnel(ifp, src, dst)
888 struct ifnet *ifp;
889 struct sockaddr *src;
890 struct sockaddr *dst;
891 {
892 struct gif_softc *sc = ifp->if_softc;
893 struct gif_softc *sc2;
894 struct sockaddr *osrc, *odst, *sa;
895 int error = 0;
896
897 mtx_lock(&gif_mtx);
898 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
899 if (sc2 == sc)
900 continue;
901 if (!sc2->gif_pdst || !sc2->gif_psrc)
902 continue;
903 if (sc2->gif_pdst->sa_family != dst->sa_family ||
904 sc2->gif_pdst->sa_len != dst->sa_len ||
905 sc2->gif_psrc->sa_family != src->sa_family ||
906 sc2->gif_psrc->sa_len != src->sa_len)
907 continue;
908
909 /*
910 * Disallow parallel tunnels unless instructed
911 * otherwise.
912 */
913 if (!parallel_tunnels &&
914 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
915 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
916 error = EADDRNOTAVAIL;
917 mtx_unlock(&gif_mtx);
918 goto bad;
919 }
920
921 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
922 }
923 mtx_unlock(&gif_mtx);
924
925 /* XXX we can detach from both, but be polite just in case */
926 if (sc->gif_psrc)
927 switch (sc->gif_psrc->sa_family) {
928 #ifdef INET
929 case AF_INET:
930 (void)in_gif_detach(sc);
931 break;
932 #endif
933 #ifdef INET6
934 case AF_INET6:
935 (void)in6_gif_detach(sc);
936 break;
937 #endif
938 }
939
940 osrc = sc->gif_psrc;
941 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
942 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
943 sc->gif_psrc = sa;
944
945 odst = sc->gif_pdst;
946 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
947 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
948 sc->gif_pdst = sa;
949
950 switch (sc->gif_psrc->sa_family) {
951 #ifdef INET
952 case AF_INET:
953 error = in_gif_attach(sc);
954 break;
955 #endif
956 #ifdef INET6
957 case AF_INET6:
958 /*
959 * Check validity of the scope zone ID of the addresses, and
960 * convert it into the kernel internal form if necessary.
961 */
962 error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0);
963 if (error != 0)
964 break;
965 error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0);
966 if (error != 0)
967 break;
968 error = in6_gif_attach(sc);
969 break;
970 #endif
971 }
972 if (error) {
973 /* rollback */
974 free((caddr_t)sc->gif_psrc, M_IFADDR);
975 free((caddr_t)sc->gif_pdst, M_IFADDR);
976 sc->gif_psrc = osrc;
977 sc->gif_pdst = odst;
978 goto bad;
979 }
980
981 if (osrc)
982 free((caddr_t)osrc, M_IFADDR);
983 if (odst)
984 free((caddr_t)odst, M_IFADDR);
985
986 bad:
987 if (sc->gif_psrc && sc->gif_pdst)
988 ifp->if_drv_flags |= IFF_DRV_RUNNING;
989 else
990 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
991
992 return error;
993 }
994
995 void
996 gif_delete_tunnel(ifp)
997 struct ifnet *ifp;
998 {
999 struct gif_softc *sc = ifp->if_softc;
1000
1001 if (sc->gif_psrc) {
1002 free((caddr_t)sc->gif_psrc, M_IFADDR);
1003 sc->gif_psrc = NULL;
1004 }
1005 if (sc->gif_pdst) {
1006 free((caddr_t)sc->gif_pdst, M_IFADDR);
1007 sc->gif_pdst = NULL;
1008 }
1009 /* it is safe to detach from both */
1010 #ifdef INET
1011 (void)in_gif_detach(sc);
1012 #endif
1013 #ifdef INET6
1014 (void)in6_gif_detach(sc);
1015 #endif
1016 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1017 }
Cache object: 9594d04c38caf50474f3facba690b72b
|