No empty .Rs/.Re
[netbsd-mini2440.git] / sys / net / if_gif.c
blobf81b126bd57cde62d6e5f8c0f92d453691cf155a
1 /* $NetBSD: if_gif.c,v 1.75 2008/06/15 16:37:21 christos Exp $ */
2 /* $KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $ */
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
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.
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.75 2008/06/15 16:37:21 christos Exp $");
36 #include "opt_inet.h"
37 #include "opt_iso.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/errno.h>
46 #include <sys/ioctl.h>
47 #include <sys/time.h>
48 #include <sys/syslog.h>
49 #include <sys/proc.h>
50 #include <sys/protosw.h>
51 #include <sys/kauth.h>
52 #include <sys/cpu.h>
53 #include <sys/intr.h>
55 #include <net/if.h>
56 #include <net/if_types.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59 #include <net/bpf.h>
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #ifdef INET
65 #include <netinet/in_var.h>
66 #endif /* INET */
67 #include <netinet/in_gif.h>
69 #ifdef INET6
70 #ifndef INET
71 #include <netinet/in.h>
72 #endif
73 #include <netinet6/in6_var.h>
74 #include <netinet/ip6.h>
75 #include <netinet6/ip6_var.h>
76 #include <netinet6/in6_gif.h>
77 #include <netinet6/ip6protosw.h>
78 #endif /* INET6 */
80 #ifdef ISO
81 #include <netiso/iso.h>
82 #include <netiso/iso_var.h>
83 #endif
85 #include <netinet/ip_encap.h>
86 #include <net/if_gif.h>
88 #include "bpfilter.h"
90 #include <net/net_osdep.h>
92 void gifattach(int);
93 static void gifintr(void *);
94 #ifdef ISO
95 static struct mbuf *gif_eon_encap(struct mbuf *);
96 static struct mbuf *gif_eon_decap(struct ifnet *, struct mbuf *);
97 #endif
100 * gif global variable definitions
102 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */
104 static int gif_clone_create(struct if_clone *, int);
105 static int gif_clone_destroy(struct ifnet *);
107 static struct if_clone gif_cloner =
108 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
110 #ifndef MAX_GIF_NEST
112 * This macro controls the upper limitation on nesting of gif tunnels.
113 * Since, setting a large value to this macro with a careless configuration
114 * may introduce system crash, we don't allow any nestings by default.
115 * If you need to configure nested gif tunnels, you can define this macro
116 * in your kernel configuration file. However, if you do so, please be
117 * careful to configure the tunnels so that it won't make a loop.
119 #define MAX_GIF_NEST 1
120 #endif
121 static int max_gif_nesting = MAX_GIF_NEST;
123 /* ARGSUSED */
124 void
125 gifattach(int count)
128 LIST_INIT(&gif_softc_list);
129 if_clone_attach(&gif_cloner);
132 static int
133 gif_clone_create(struct if_clone *ifc, int unit)
135 struct gif_softc *sc;
137 sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO);
139 if_initname(&sc->gif_if, ifc->ifc_name, unit);
141 gifattach0(sc);
143 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
144 return (0);
147 void
148 gifattach0(struct gif_softc *sc)
151 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
153 sc->gif_if.if_addrlen = 0;
154 sc->gif_if.if_mtu = GIF_MTU;
155 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
156 sc->gif_if.if_ioctl = gif_ioctl;
157 sc->gif_if.if_output = gif_output;
158 sc->gif_if.if_type = IFT_GIF;
159 sc->gif_if.if_dlt = DLT_NULL;
160 sc->gif_if.if_softc = sc;
161 IFQ_SET_READY(&sc->gif_if.if_snd);
162 if_attach(&sc->gif_if);
163 if_alloc_sadl(&sc->gif_if);
164 #if NBPFILTER > 0
165 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
166 #endif
169 static int
170 gif_clone_destroy(struct ifnet *ifp)
172 struct gif_softc *sc = (void *) ifp;
174 gif_delete_tunnel(&sc->gif_if);
175 LIST_REMOVE(sc, gif_list);
176 #ifdef INET6
177 encap_detach(sc->encap_cookie6);
178 #endif
179 #ifdef INET
180 encap_detach(sc->encap_cookie4);
181 #endif
183 #if NBPFILTER > 0
184 bpfdetach(ifp);
185 #endif
186 if_detach(ifp);
187 rtcache_free(&sc->gif_ro);
189 free(sc, M_DEVBUF);
191 return (0);
194 #ifdef GIF_ENCAPCHECK
196 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
198 struct ip ip;
199 struct gif_softc *sc;
201 sc = arg;
202 if (sc == NULL)
203 return 0;
205 if ((sc->gif_if.if_flags & IFF_UP) == 0)
206 return 0;
208 /* no physical address */
209 if (!sc->gif_psrc || !sc->gif_pdst)
210 return 0;
212 switch (proto) {
213 #ifdef INET
214 case IPPROTO_IPV4:
215 break;
216 #endif
217 #ifdef INET6
218 case IPPROTO_IPV6:
219 break;
220 #endif
221 #ifdef ISO
222 case IPPROTO_EON:
223 break;
224 #endif
225 default:
226 return 0;
229 /* Bail on short packets */
230 KASSERT(m->m_flags & M_PKTHDR);
231 if (m->m_pkthdr.len < sizeof(ip))
232 return 0;
234 m_copydata(m, 0, sizeof(ip), &ip);
236 switch (ip.ip_v) {
237 #ifdef INET
238 case 4:
239 if (sc->gif_psrc->sa_family != AF_INET ||
240 sc->gif_pdst->sa_family != AF_INET)
241 return 0;
242 return gif_encapcheck4(m, off, proto, arg);
243 #endif
244 #ifdef INET6
245 case 6:
246 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
247 return 0;
248 if (sc->gif_psrc->sa_family != AF_INET6 ||
249 sc->gif_pdst->sa_family != AF_INET6)
250 return 0;
251 return gif_encapcheck6(m, off, proto, arg);
252 #endif
253 default:
254 return 0;
257 #endif
260 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
261 struct rtentry *rt)
263 struct gif_softc *sc = ifp->if_softc;
264 int error = 0;
265 static int called = 0; /* XXX: MUTEX */
266 ALTQ_DECL(struct altq_pktattr pktattr;)
267 int s;
269 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
272 * gif may cause infinite recursion calls when misconfigured.
273 * We'll prevent this by introducing upper limit.
274 * XXX: this mechanism may introduce another problem about
275 * mutual exclusion of the variable CALLED, especially if we
276 * use kernel thread.
278 if (++called > max_gif_nesting) {
279 log(LOG_NOTICE,
280 "gif_output: recursively called too many times(%d)\n",
281 called);
282 m_freem(m);
283 error = EIO; /* is there better errno? */
284 goto end;
287 m->m_flags &= ~(M_BCAST|M_MCAST);
288 if (!(ifp->if_flags & IFF_UP) ||
289 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
290 m_freem(m);
291 error = ENETDOWN;
292 goto end;
295 /* inner AF-specific encapsulation */
296 switch (dst->sa_family) {
297 #ifdef ISO
298 case AF_ISO:
299 m = gif_eon_encap(m);
300 if (!m) {
301 error = ENOBUFS;
302 goto end;
304 break;
305 #endif
306 default:
307 break;
310 /* XXX should we check if our outer source is legal? */
312 /* use DLT_NULL encapsulation here to pass inner af type */
313 M_PREPEND(m, sizeof(int), M_DONTWAIT);
314 if (!m) {
315 error = ENOBUFS;
316 goto end;
318 *mtod(m, int *) = dst->sa_family;
320 s = splnet();
321 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
322 if (error) {
323 splx(s);
324 goto end;
326 splx(s);
328 softint_schedule(sc->gif_si);
329 error = 0;
331 end:
332 called = 0; /* reset recursion counter */
333 if (error)
334 ifp->if_oerrors++;
335 return error;
338 static void
339 gifintr(void *arg)
341 struct gif_softc *sc;
342 struct ifnet *ifp;
343 struct mbuf *m;
344 int family;
345 int len;
346 int s;
347 int error;
349 sc = arg;
350 ifp = &sc->gif_if;
352 /* output processing */
353 while (1) {
354 s = splnet();
355 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
356 splx(s);
357 if (m == NULL)
358 break;
360 /* grab and chop off inner af type */
361 if (sizeof(int) > m->m_len) {
362 m = m_pullup(m, sizeof(int));
363 if (!m) {
364 ifp->if_oerrors++;
365 continue;
368 family = *mtod(m, int *);
369 #if NBPFILTER > 0
370 if (ifp->if_bpf)
371 bpf_mtap(ifp->if_bpf, m);
372 #endif
373 m_adj(m, sizeof(int));
375 len = m->m_pkthdr.len;
377 /* dispatch to output logic based on outer AF */
378 switch (sc->gif_psrc->sa_family) {
379 #ifdef INET
380 case AF_INET:
381 error = in_gif_output(ifp, family, m);
382 break;
383 #endif
384 #ifdef INET6
385 case AF_INET6:
386 error = in6_gif_output(ifp, family, m);
387 break;
388 #endif
389 default:
390 m_freem(m);
391 error = ENETDOWN;
392 break;
395 if (error)
396 ifp->if_oerrors++;
397 else {
398 ifp->if_opackets++;
399 ifp->if_obytes += len;
404 void
405 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
407 int s, isr;
408 struct ifqueue *ifq = NULL;
410 if (ifp == NULL) {
411 /* just in case */
412 m_freem(m);
413 return;
416 m->m_pkthdr.rcvif = ifp;
418 #if NBPFILTER > 0
419 if (ifp->if_bpf)
420 bpf_mtap_af(ifp->if_bpf, af, m);
421 #endif /*NBPFILTER > 0*/
424 * Put the packet to the network layer input queue according to the
425 * specified address family.
426 * Note: older versions of gif_input directly called network layer
427 * input functions, e.g. ip6_input, here. We changed the policy to
428 * prevent too many recursive calls of such input functions, which
429 * might cause kernel panic. But the change may introduce another
430 * problem; if the input queue is full, packets are discarded.
431 * The kernel stack overflow really happened, and we believed
432 * queue-full rarely occurs, so we changed the policy.
434 switch (af) {
435 #ifdef INET
436 case AF_INET:
437 ifq = &ipintrq;
438 isr = NETISR_IP;
439 break;
440 #endif
441 #ifdef INET6
442 case AF_INET6:
443 ifq = &ip6intrq;
444 isr = NETISR_IPV6;
445 break;
446 #endif
447 #ifdef ISO
448 case AF_ISO:
449 m = gif_eon_decap(ifp, m);
450 if (!m)
451 return;
452 ifq = &clnlintrq;
453 isr = NETISR_ISO;
454 break;
455 #endif
456 default:
457 m_freem(m);
458 return;
461 s = splnet();
462 if (IF_QFULL(ifq)) {
463 IF_DROP(ifq); /* update statistics */
464 m_freem(m);
465 splx(s);
466 return;
468 ifp->if_ipackets++;
469 ifp->if_ibytes += m->m_pkthdr.len;
470 IF_ENQUEUE(ifq, m);
471 /* we need schednetisr since the address family may change */
472 schednetisr(isr);
473 splx(s);
476 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
478 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
480 struct lwp *l = curlwp; /* XXX */
481 struct gif_softc *sc = ifp->if_softc;
482 struct ifreq *ifr = (struct ifreq*)data;
483 int error = 0, size;
484 struct sockaddr *dst, *src;
486 switch (cmd) {
487 case SIOCSIFMTU:
488 case SIOCSLIFPHYADDR:
489 #ifdef SIOCDIFPHYADDR
490 case SIOCDIFPHYADDR:
491 #endif
492 if ((error = kauth_authorize_network(l->l_cred,
493 KAUTH_NETWORK_INTERFACE,
494 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
495 NULL)) != 0)
496 return (error);
497 /* FALLTHROUGH */
498 default:
499 break;
502 switch (cmd) {
503 case SIOCINITIFADDR:
504 ifp->if_flags |= IFF_UP;
505 break;
507 case SIOCSIFDSTADDR:
508 break;
510 case SIOCADDMULTI:
511 case SIOCDELMULTI:
512 switch (ifr->ifr_addr.sa_family) {
513 #ifdef INET
514 case AF_INET: /* IP supports Multicast */
515 break;
516 #endif /* INET */
517 #ifdef INET6
518 case AF_INET6: /* IP6 supports Multicast */
519 break;
520 #endif /* INET6 */
521 default: /* Other protocols doesn't support Multicast */
522 error = EAFNOSUPPORT;
523 break;
525 break;
527 case SIOCGIFMTU:
528 break;
530 case SIOCSIFMTU:
531 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
532 return EINVAL;
533 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
534 error = 0;
535 break;
537 #ifdef INET
538 case SIOCSIFPHYADDR:
539 #endif
540 #ifdef INET6
541 case SIOCSIFPHYADDR_IN6:
542 #endif /* INET6 */
543 case SIOCSLIFPHYADDR:
544 switch (cmd) {
545 #ifdef INET
546 case SIOCSIFPHYADDR:
547 src = (struct sockaddr *)
548 &(((struct in_aliasreq *)data)->ifra_addr);
549 dst = (struct sockaddr *)
550 &(((struct in_aliasreq *)data)->ifra_dstaddr);
551 break;
552 #endif
553 #ifdef INET6
554 case SIOCSIFPHYADDR_IN6:
555 src = (struct sockaddr *)
556 &(((struct in6_aliasreq *)data)->ifra_addr);
557 dst = (struct sockaddr *)
558 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
559 break;
560 #endif
561 case SIOCSLIFPHYADDR:
562 src = (struct sockaddr *)
563 &(((struct if_laddrreq *)data)->addr);
564 dst = (struct sockaddr *)
565 &(((struct if_laddrreq *)data)->dstaddr);
566 break;
567 default:
568 return EINVAL;
571 /* sa_family must be equal */
572 if (src->sa_family != dst->sa_family)
573 return EINVAL;
575 /* validate sa_len */
576 switch (src->sa_family) {
577 #ifdef INET
578 case AF_INET:
579 if (src->sa_len != sizeof(struct sockaddr_in))
580 return EINVAL;
581 break;
582 #endif
583 #ifdef INET6
584 case AF_INET6:
585 if (src->sa_len != sizeof(struct sockaddr_in6))
586 return EINVAL;
587 break;
588 #endif
589 default:
590 return EAFNOSUPPORT;
592 switch (dst->sa_family) {
593 #ifdef INET
594 case AF_INET:
595 if (dst->sa_len != sizeof(struct sockaddr_in))
596 return EINVAL;
597 break;
598 #endif
599 #ifdef INET6
600 case AF_INET6:
601 if (dst->sa_len != sizeof(struct sockaddr_in6))
602 return EINVAL;
603 break;
604 #endif
605 default:
606 return EAFNOSUPPORT;
609 /* check sa_family looks sane for the cmd */
610 switch (cmd) {
611 case SIOCSIFPHYADDR:
612 if (src->sa_family == AF_INET)
613 break;
614 return EAFNOSUPPORT;
615 #ifdef INET6
616 case SIOCSIFPHYADDR_IN6:
617 if (src->sa_family == AF_INET6)
618 break;
619 return EAFNOSUPPORT;
620 #endif /* INET6 */
621 case SIOCSLIFPHYADDR:
622 /* checks done in the above */
623 break;
626 error = gif_set_tunnel(&sc->gif_if, src, dst);
627 break;
629 #ifdef SIOCDIFPHYADDR
630 case SIOCDIFPHYADDR:
631 gif_delete_tunnel(&sc->gif_if);
632 break;
633 #endif
635 case SIOCGIFPSRCADDR:
636 #ifdef INET6
637 case SIOCGIFPSRCADDR_IN6:
638 #endif /* INET6 */
639 if (sc->gif_psrc == NULL) {
640 error = EADDRNOTAVAIL;
641 goto bad;
643 src = sc->gif_psrc;
644 switch (cmd) {
645 #ifdef INET
646 case SIOCGIFPSRCADDR:
647 dst = &ifr->ifr_addr;
648 size = sizeof(ifr->ifr_addr);
649 break;
650 #endif /* INET */
651 #ifdef INET6
652 case SIOCGIFPSRCADDR_IN6:
653 dst = (struct sockaddr *)
654 &(((struct in6_ifreq *)data)->ifr_addr);
655 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
656 break;
657 #endif /* INET6 */
658 default:
659 error = EADDRNOTAVAIL;
660 goto bad;
662 if (src->sa_len > size)
663 return EINVAL;
664 memcpy(dst, src, src->sa_len);
665 break;
667 case SIOCGIFPDSTADDR:
668 #ifdef INET6
669 case SIOCGIFPDSTADDR_IN6:
670 #endif /* INET6 */
671 if (sc->gif_pdst == NULL) {
672 error = EADDRNOTAVAIL;
673 goto bad;
675 src = sc->gif_pdst;
676 switch (cmd) {
677 #ifdef INET
678 case SIOCGIFPDSTADDR:
679 dst = &ifr->ifr_addr;
680 size = sizeof(ifr->ifr_addr);
681 break;
682 #endif /* INET */
683 #ifdef INET6
684 case SIOCGIFPDSTADDR_IN6:
685 dst = (struct sockaddr *)
686 &(((struct in6_ifreq *)data)->ifr_addr);
687 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
688 break;
689 #endif /* INET6 */
690 default:
691 error = EADDRNOTAVAIL;
692 goto bad;
694 if (src->sa_len > size)
695 return EINVAL;
696 memcpy(dst, src, src->sa_len);
697 break;
699 case SIOCGLIFPHYADDR:
700 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
701 error = EADDRNOTAVAIL;
702 goto bad;
705 /* copy src */
706 src = sc->gif_psrc;
707 dst = (struct sockaddr *)
708 &(((struct if_laddrreq *)data)->addr);
709 size = sizeof(((struct if_laddrreq *)data)->addr);
710 if (src->sa_len > size)
711 return EINVAL;
712 memcpy(dst, src, src->sa_len);
714 /* copy dst */
715 src = sc->gif_pdst;
716 dst = (struct sockaddr *)
717 &(((struct if_laddrreq *)data)->dstaddr);
718 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
719 if (src->sa_len > size)
720 return EINVAL;
721 memcpy(dst, src, src->sa_len);
722 break;
724 default:
725 return ifioctl_common(ifp, cmd, data);
727 bad:
728 return error;
732 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
734 struct gif_softc *sc = ifp->if_softc;
735 struct gif_softc *sc2;
736 struct sockaddr *osrc, *odst;
737 int s;
738 int error;
740 s = splsoftnet();
742 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
743 if (sc2 == sc)
744 continue;
745 if (!sc2->gif_pdst || !sc2->gif_psrc)
746 continue;
747 /* can't configure same pair of address onto two gifs */
748 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
749 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
750 error = EADDRNOTAVAIL;
751 goto bad;
754 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
757 if (sc->gif_si) {
758 softint_disestablish(sc->gif_si);
759 sc->gif_si = NULL;
762 /* XXX we can detach from both, but be polite just in case */
763 if (sc->gif_psrc)
764 switch (sc->gif_psrc->sa_family) {
765 #ifdef INET
766 case AF_INET:
767 (void)in_gif_detach(sc);
768 break;
769 #endif
770 #ifdef INET6
771 case AF_INET6:
772 (void)in6_gif_detach(sc);
773 break;
774 #endif
777 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
778 if (sc->gif_si == NULL) {
779 error = ENOMEM;
780 goto bad;
783 osrc = sc->gif_psrc;
784 sc->gif_psrc = sockaddr_dup(src, M_WAITOK);
786 odst = sc->gif_pdst;
787 sc->gif_pdst = sockaddr_dup(dst, M_WAITOK);
789 switch (sc->gif_psrc->sa_family) {
790 #ifdef INET
791 case AF_INET:
792 error = in_gif_attach(sc);
793 break;
794 #endif
795 #ifdef INET6
796 case AF_INET6:
797 error = in6_gif_attach(sc);
798 break;
799 #endif
800 default:
801 error = EINVAL;
802 break;
804 if (error) {
805 /* rollback */
806 sockaddr_free(sc->gif_psrc);
807 sockaddr_free(sc->gif_pdst);
808 sc->gif_psrc = osrc;
809 sc->gif_pdst = odst;
810 goto bad;
813 if (osrc)
814 sockaddr_free(osrc);
815 if (odst)
816 sockaddr_free(odst);
818 if (sc->gif_psrc && sc->gif_pdst)
819 ifp->if_flags |= IFF_RUNNING;
820 else
821 ifp->if_flags &= ~IFF_RUNNING;
822 splx(s);
824 return 0;
826 bad:
827 if (sc->gif_si) {
828 softint_disestablish(sc->gif_si);
829 sc->gif_si = NULL;
831 if (sc->gif_psrc && sc->gif_pdst)
832 ifp->if_flags |= IFF_RUNNING;
833 else
834 ifp->if_flags &= ~IFF_RUNNING;
835 splx(s);
837 return error;
840 void
841 gif_delete_tunnel(struct ifnet *ifp)
843 struct gif_softc *sc = ifp->if_softc;
844 int s;
846 s = splsoftnet();
848 if (sc->gif_si) {
849 softint_disestablish(sc->gif_si);
850 sc->gif_si = NULL;
852 if (sc->gif_psrc) {
853 sockaddr_free(sc->gif_psrc);
854 sc->gif_psrc = NULL;
856 if (sc->gif_pdst) {
857 sockaddr_free(sc->gif_pdst);
858 sc->gif_pdst = NULL;
860 /* it is safe to detach from both */
861 #ifdef INET
862 (void)in_gif_detach(sc);
863 #endif
864 #ifdef INET6
865 (void)in6_gif_detach(sc);
866 #endif
868 if (sc->gif_psrc && sc->gif_pdst)
869 ifp->if_flags |= IFF_RUNNING;
870 else
871 ifp->if_flags &= ~IFF_RUNNING;
872 splx(s);
875 #ifdef ISO
876 struct eonhdr {
877 uint8_t version;
878 uint8_t class;
879 uint16_t cksum;
883 * prepend EON header to ISO PDU
885 static struct mbuf *
886 gif_eon_encap(struct mbuf *m)
888 struct eonhdr *ehdr;
890 M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT);
891 if (m && m->m_len < sizeof(*ehdr))
892 m = m_pullup(m, sizeof(*ehdr));
893 if (m == NULL)
894 return NULL;
895 ehdr = mtod(m, struct eonhdr *);
896 ehdr->version = 1;
897 ehdr->class = 0; /* always unicast */
898 #if 0
899 /* calculate the checksum of the eonhdr */
901 struct mbuf mhead;
902 memset(&mhead, 0, sizeof(mhead));
903 ehdr->cksum = 0;
904 mhead.m_data = (void *)ehdr;
905 mhead.m_len = sizeof(*ehdr);
906 mhead.m_next = 0;
907 iso_gen_csum(&mhead, offsetof(struct eonhdr, cksum),
908 mhead.m_len);
910 #else
911 /* since the data is always constant we'll just plug the value in */
912 ehdr->cksum = htons(0xfc02);
913 #endif
914 return m;
918 * remove EON header and check checksum
920 static struct mbuf *
921 gif_eon_decap(struct ifnet *ifp, struct mbuf *m)
923 struct eonhdr *ehdr;
925 if (m->m_len < sizeof(*ehdr) &&
926 (m = m_pullup(m, sizeof(*ehdr))) == NULL) {
927 ifp->if_ierrors++;
928 return NULL;
930 if (iso_check_csum(m, sizeof(struct eonhdr))) {
931 m_freem(m);
932 return NULL;
934 m_adj(m, sizeof(*ehdr));
935 return m;
937 #endif /*ISO*/