FreeBSD/Linux Kernel Cross Reference
sys/net/if_gif.c
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 $ */
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.75 2008/06/15 16:37:21 christos Exp $");
35
36 #include "opt_inet.h"
37 #include "opt_iso.h"
38
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>
54
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>
60
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>
68
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 */
79
80 #ifdef ISO
81 #include <netiso/iso.h>
82 #include <netiso/iso_var.h>
83 #endif
84
85 #include <netinet/ip_encap.h>
86 #include <net/if_gif.h>
87
88 #include "bpfilter.h"
89
90 #include <net/net_osdep.h>
91
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
98
99 /*
100 * gif global variable definitions
101 */
102 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */
103
104 static int gif_clone_create(struct if_clone *, int);
105 static int gif_clone_destroy(struct ifnet *);
106
107 static struct if_clone gif_cloner =
108 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
109
110 #ifndef MAX_GIF_NEST
111 /*
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.
118 */
119 #define MAX_GIF_NEST 1
120 #endif
121 static int max_gif_nesting = MAX_GIF_NEST;
122
123 /* ARGSUSED */
124 void
125 gifattach(int count)
126 {
127
128 LIST_INIT(&gif_softc_list);
129 if_clone_attach(&gif_cloner);
130 }
131
132 static int
133 gif_clone_create(struct if_clone *ifc, int unit)
134 {
135 struct gif_softc *sc;
136
137 sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO);
138
139 if_initname(&sc->gif_if, ifc->ifc_name, unit);
140
141 gifattach0(sc);
142
143 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
144 return (0);
145 }
146
147 void
148 gifattach0(struct gif_softc *sc)
149 {
150
151 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
152
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 IFQ_SET_READY(&sc->gif_if.if_snd);
161 if_attach(&sc->gif_if);
162 if_alloc_sadl(&sc->gif_if);
163 #if NBPFILTER > 0
164 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
165 #endif
166 }
167
168 static int
169 gif_clone_destroy(struct ifnet *ifp)
170 {
171 struct gif_softc *sc = (void *) ifp;
172
173 gif_delete_tunnel(&sc->gif_if);
174 LIST_REMOVE(sc, gif_list);
175 #ifdef INET6
176 encap_detach(sc->encap_cookie6);
177 #endif
178 #ifdef INET
179 encap_detach(sc->encap_cookie4);
180 #endif
181
182 #if NBPFILTER > 0
183 bpfdetach(ifp);
184 #endif
185 if_detach(ifp);
186 rtcache_free(&sc->gif_ro);
187
188 free(sc, M_DEVBUF);
189
190 return (0);
191 }
192
193 #ifdef GIF_ENCAPCHECK
194 int
195 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
196 {
197 struct ip ip;
198 struct gif_softc *sc;
199
200 sc = (struct gif_softc *)arg;
201 if (sc == NULL)
202 return 0;
203
204 if ((sc->gif_if.if_flags & IFF_UP) == 0)
205 return 0;
206
207 /* no physical address */
208 if (!sc->gif_psrc || !sc->gif_pdst)
209 return 0;
210
211 switch (proto) {
212 #ifdef INET
213 case IPPROTO_IPV4:
214 break;
215 #endif
216 #ifdef INET6
217 case IPPROTO_IPV6:
218 break;
219 #endif
220 #ifdef ISO
221 case IPPROTO_EON:
222 break;
223 #endif
224 default:
225 return 0;
226 }
227
228 /* Bail on short packets */
229 KASSERT(m->m_flags & M_PKTHDR);
230 if (m->m_pkthdr.len < sizeof(ip))
231 return 0;
232
233 m_copydata(m, 0, sizeof(ip), (void *)&ip);
234
235 switch (ip.ip_v) {
236 #ifdef INET
237 case 4:
238 if (sc->gif_psrc->sa_family != AF_INET ||
239 sc->gif_pdst->sa_family != AF_INET)
240 return 0;
241 return gif_encapcheck4(m, off, proto, arg);
242 #endif
243 #ifdef INET6
244 case 6:
245 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
246 return 0;
247 if (sc->gif_psrc->sa_family != AF_INET6 ||
248 sc->gif_pdst->sa_family != AF_INET6)
249 return 0;
250 return gif_encapcheck6(m, off, proto, arg);
251 #endif
252 default:
253 return 0;
254 }
255 }
256 #endif
257
258 int
259 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
260 struct rtentry *rt)
261 {
262 struct gif_softc *sc = (struct gif_softc*)ifp;
263 int error = 0;
264 static int called = 0; /* XXX: MUTEX */
265 ALTQ_DECL(struct altq_pktattr pktattr;)
266 int s;
267
268 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
269
270 /*
271 * gif may cause infinite recursion calls when misconfigured.
272 * We'll prevent this by introducing upper limit.
273 * XXX: this mechanism may introduce another problem about
274 * mutual exclusion of the variable CALLED, especially if we
275 * use kernel thread.
276 */
277 if (++called > max_gif_nesting) {
278 log(LOG_NOTICE,
279 "gif_output: recursively called too many times(%d)\n",
280 called);
281 m_freem(m);
282 error = EIO; /* is there better errno? */
283 goto end;
284 }
285
286 m->m_flags &= ~(M_BCAST|M_MCAST);
287 if (!(ifp->if_flags & IFF_UP) ||
288 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
289 m_freem(m);
290 error = ENETDOWN;
291 goto end;
292 }
293
294 /* inner AF-specific encapsulation */
295 switch (dst->sa_family) {
296 #ifdef ISO
297 case AF_ISO:
298 m = gif_eon_encap(m);
299 if (!m) {
300 error = ENOBUFS;
301 goto end;
302 }
303 break;
304 #endif
305 default:
306 break;
307 }
308
309 /* XXX should we check if our outer source is legal? */
310
311 /* use DLT_NULL encapsulation here to pass inner af type */
312 M_PREPEND(m, sizeof(int), M_DONTWAIT);
313 if (!m) {
314 error = ENOBUFS;
315 goto end;
316 }
317 *mtod(m, int *) = dst->sa_family;
318
319 s = splnet();
320 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
321 if (error) {
322 splx(s);
323 goto end;
324 }
325 splx(s);
326
327 softint_schedule(sc->gif_si);
328 error = 0;
329
330 end:
331 called = 0; /* reset recursion counter */
332 if (error)
333 ifp->if_oerrors++;
334 return error;
335 }
336
337 static void
338 gifintr(void *arg)
339 {
340 struct gif_softc *sc;
341 struct ifnet *ifp;
342 struct mbuf *m;
343 int family;
344 int len;
345 int s;
346 int error;
347
348 sc = (struct gif_softc *)arg;
349 ifp = &sc->gif_if;
350
351 /* output processing */
352 while (1) {
353 s = splnet();
354 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
355 splx(s);
356 if (m == NULL)
357 break;
358
359 /* grab and chop off inner af type */
360 if (sizeof(int) > m->m_len) {
361 m = m_pullup(m, sizeof(int));
362 if (!m) {
363 ifp->if_oerrors++;
364 continue;
365 }
366 }
367 family = *mtod(m, int *);
368 #if NBPFILTER > 0
369 if (ifp->if_bpf)
370 bpf_mtap(ifp->if_bpf, m);
371 #endif
372 m_adj(m, sizeof(int));
373
374 len = m->m_pkthdr.len;
375
376 /* dispatch to output logic based on outer AF */
377 switch (sc->gif_psrc->sa_family) {
378 #ifdef INET
379 case AF_INET:
380 error = in_gif_output(ifp, family, m);
381 break;
382 #endif
383 #ifdef INET6
384 case AF_INET6:
385 error = in6_gif_output(ifp, family, m);
386 break;
387 #endif
388 default:
389 m_freem(m);
390 error = ENETDOWN;
391 break;
392 }
393
394 if (error)
395 ifp->if_oerrors++;
396 else {
397 ifp->if_opackets++;
398 ifp->if_obytes += len;
399 }
400 }
401 }
402
403 void
404 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
405 {
406 int s, isr;
407 struct ifqueue *ifq = NULL;
408
409 if (ifp == NULL) {
410 /* just in case */
411 m_freem(m);
412 return;
413 }
414
415 m->m_pkthdr.rcvif = ifp;
416
417 #if NBPFILTER > 0
418 if (ifp->if_bpf)
419 bpf_mtap_af(ifp->if_bpf, af, m);
420 #endif /*NBPFILTER > 0*/
421
422 /*
423 * Put the packet to the network layer input queue according to the
424 * specified address family.
425 * Note: older versions of gif_input directly called network layer
426 * input functions, e.g. ip6_input, here. We changed the policy to
427 * prevent too many recursive calls of such input functions, which
428 * might cause kernel panic. But the change may introduce another
429 * problem; if the input queue is full, packets are discarded.
430 * The kernel stack overflow really happened, and we believed
431 * queue-full rarely occurs, so we changed the policy.
432 */
433 switch (af) {
434 #ifdef INET
435 case AF_INET:
436 ifq = &ipintrq;
437 isr = NETISR_IP;
438 break;
439 #endif
440 #ifdef INET6
441 case AF_INET6:
442 ifq = &ip6intrq;
443 isr = NETISR_IPV6;
444 break;
445 #endif
446 #ifdef ISO
447 case AF_ISO:
448 m = gif_eon_decap(ifp, m);
449 if (!m)
450 return;
451 ifq = &clnlintrq;
452 isr = NETISR_ISO;
453 break;
454 #endif
455 default:
456 m_freem(m);
457 return;
458 }
459
460 s = splnet();
461 if (IF_QFULL(ifq)) {
462 IF_DROP(ifq); /* update statistics */
463 m_freem(m);
464 splx(s);
465 return;
466 }
467 ifp->if_ipackets++;
468 ifp->if_ibytes += m->m_pkthdr.len;
469 IF_ENQUEUE(ifq, m);
470 /* we need schednetisr since the address family may change */
471 schednetisr(isr);
472 splx(s);
473 }
474
475 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
476 int
477 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
478 {
479 struct lwp *l = curlwp; /* XXX */
480 struct gif_softc *sc = (struct gif_softc*)ifp;
481 struct ifreq *ifr = (struct ifreq*)data;
482 int error = 0, size;
483 struct sockaddr *dst, *src;
484
485 switch (cmd) {
486 case SIOCSIFMTU:
487 case SIOCSLIFPHYADDR:
488 #ifdef SIOCDIFPHYADDR
489 case SIOCDIFPHYADDR:
490 #endif
491 if ((error = kauth_authorize_network(l->l_cred,
492 KAUTH_NETWORK_INTERFACE,
493 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
494 NULL)) != 0)
495 return (error);
496 /* FALLTHROUGH */
497 default:
498 break;
499 }
500
501 switch (cmd) {
502 case SIOCSIFADDR:
503 ifp->if_flags |= IFF_UP;
504 break;
505
506 case SIOCSIFDSTADDR:
507 break;
508
509 case SIOCADDMULTI:
510 case SIOCDELMULTI:
511 switch (ifr->ifr_addr.sa_family) {
512 #ifdef INET
513 case AF_INET: /* IP supports Multicast */
514 break;
515 #endif /* INET */
516 #ifdef INET6
517 case AF_INET6: /* IP6 supports Multicast */
518 break;
519 #endif /* INET6 */
520 default: /* Other protocols doesn't support Multicast */
521 error = EAFNOSUPPORT;
522 break;
523 }
524 break;
525
526 case SIOCGIFMTU:
527 break;
528
529 case SIOCSIFMTU:
530 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
531 return EINVAL;
532 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
533 error = 0;
534 break;
535
536 #ifdef INET
537 case SIOCSIFPHYADDR:
538 #endif
539 #ifdef INET6
540 case SIOCSIFPHYADDR_IN6:
541 #endif /* INET6 */
542 case SIOCSLIFPHYADDR:
543 switch (cmd) {
544 #ifdef INET
545 case SIOCSIFPHYADDR:
546 src = (struct sockaddr *)
547 &(((struct in_aliasreq *)data)->ifra_addr);
548 dst = (struct sockaddr *)
549 &(((struct in_aliasreq *)data)->ifra_dstaddr);
550 break;
551 #endif
552 #ifdef INET6
553 case SIOCSIFPHYADDR_IN6:
554 src = (struct sockaddr *)
555 &(((struct in6_aliasreq *)data)->ifra_addr);
556 dst = (struct sockaddr *)
557 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
558 break;
559 #endif
560 case SIOCSLIFPHYADDR:
561 src = (struct sockaddr *)
562 &(((struct if_laddrreq *)data)->addr);
563 dst = (struct sockaddr *)
564 &(((struct if_laddrreq *)data)->dstaddr);
565 break;
566 default:
567 return EINVAL;
568 }
569
570 /* sa_family must be equal */
571 if (src->sa_family != dst->sa_family)
572 return EINVAL;
573
574 /* validate sa_len */
575 switch (src->sa_family) {
576 #ifdef INET
577 case AF_INET:
578 if (src->sa_len != sizeof(struct sockaddr_in))
579 return EINVAL;
580 break;
581 #endif
582 #ifdef INET6
583 case AF_INET6:
584 if (src->sa_len != sizeof(struct sockaddr_in6))
585 return EINVAL;
586 break;
587 #endif
588 default:
589 return EAFNOSUPPORT;
590 }
591 switch (dst->sa_family) {
592 #ifdef INET
593 case AF_INET:
594 if (dst->sa_len != sizeof(struct sockaddr_in))
595 return EINVAL;
596 break;
597 #endif
598 #ifdef INET6
599 case AF_INET6:
600 if (dst->sa_len != sizeof(struct sockaddr_in6))
601 return EINVAL;
602 break;
603 #endif
604 default:
605 return EAFNOSUPPORT;
606 }
607
608 /* check sa_family looks sane for the cmd */
609 switch (cmd) {
610 case SIOCSIFPHYADDR:
611 if (src->sa_family == AF_INET)
612 break;
613 return EAFNOSUPPORT;
614 #ifdef INET6
615 case SIOCSIFPHYADDR_IN6:
616 if (src->sa_family == AF_INET6)
617 break;
618 return EAFNOSUPPORT;
619 #endif /* INET6 */
620 case SIOCSLIFPHYADDR:
621 /* checks done in the above */
622 break;
623 }
624
625 error = gif_set_tunnel(&sc->gif_if, src, dst);
626 break;
627
628 #ifdef SIOCDIFPHYADDR
629 case SIOCDIFPHYADDR:
630 gif_delete_tunnel(&sc->gif_if);
631 break;
632 #endif
633
634 case SIOCGIFPSRCADDR:
635 #ifdef INET6
636 case SIOCGIFPSRCADDR_IN6:
637 #endif /* INET6 */
638 if (sc->gif_psrc == NULL) {
639 error = EADDRNOTAVAIL;
640 goto bad;
641 }
642 src = sc->gif_psrc;
643 switch (cmd) {
644 #ifdef INET
645 case SIOCGIFPSRCADDR:
646 dst = &ifr->ifr_addr;
647 size = sizeof(ifr->ifr_addr);
648 break;
649 #endif /* INET */
650 #ifdef INET6
651 case SIOCGIFPSRCADDR_IN6:
652 dst = (struct sockaddr *)
653 &(((struct in6_ifreq *)data)->ifr_addr);
654 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
655 break;
656 #endif /* INET6 */
657 default:
658 error = EADDRNOTAVAIL;
659 goto bad;
660 }
661 if (src->sa_len > size)
662 return EINVAL;
663 memcpy(dst, src, src->sa_len);
664 break;
665
666 case SIOCGIFPDSTADDR:
667 #ifdef INET6
668 case SIOCGIFPDSTADDR_IN6:
669 #endif /* INET6 */
670 if (sc->gif_pdst == NULL) {
671 error = EADDRNOTAVAIL;
672 goto bad;
673 }
674 src = sc->gif_pdst;
675 switch (cmd) {
676 #ifdef INET
677 case SIOCGIFPDSTADDR:
678 dst = &ifr->ifr_addr;
679 size = sizeof(ifr->ifr_addr);
680 break;
681 #endif /* INET */
682 #ifdef INET6
683 case SIOCGIFPDSTADDR_IN6:
684 dst = (struct sockaddr *)
685 &(((struct in6_ifreq *)data)->ifr_addr);
686 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
687 break;
688 #endif /* INET6 */
689 default:
690 error = EADDRNOTAVAIL;
691 goto bad;
692 }
693 if (src->sa_len > size)
694 return EINVAL;
695 memcpy(dst, src, src->sa_len);
696 break;
697
698 case SIOCGLIFPHYADDR:
699 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
700 error = EADDRNOTAVAIL;
701 goto bad;
702 }
703
704 /* copy src */
705 src = sc->gif_psrc;
706 dst = (struct sockaddr *)
707 &(((struct if_laddrreq *)data)->addr);
708 size = sizeof(((struct if_laddrreq *)data)->addr);
709 if (src->sa_len > size)
710 return EINVAL;
711 memcpy(dst, src, src->sa_len);
712
713 /* copy dst */
714 src = sc->gif_pdst;
715 dst = (struct sockaddr *)
716 &(((struct if_laddrreq *)data)->dstaddr);
717 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
718 if (src->sa_len > size)
719 return EINVAL;
720 memcpy(dst, src, src->sa_len);
721 break;
722
723 case SIOCSIFFLAGS:
724 /* if_ioctl() takes care of it */
725 break;
726
727 default:
728 error = EINVAL;
729 break;
730 }
731 bad:
732 return error;
733 }
734
735 int
736 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
737 {
738 struct gif_softc *sc = (struct gif_softc *)ifp;
739 struct gif_softc *sc2;
740 struct sockaddr *osrc, *odst;
741 int s;
742 int error;
743
744 s = splsoftnet();
745
746 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
747 if (sc2 == sc)
748 continue;
749 if (!sc2->gif_pdst || !sc2->gif_psrc)
750 continue;
751 /* can't configure same pair of address onto two gifs */
752 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
753 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
754 error = EADDRNOTAVAIL;
755 goto bad;
756 }
757
758 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
759 }
760
761 if (sc->gif_si) {
762 softint_disestablish(sc->gif_si);
763 sc->gif_si = NULL;
764 }
765
766 /* XXX we can detach from both, but be polite just in case */
767 if (sc->gif_psrc)
768 switch (sc->gif_psrc->sa_family) {
769 #ifdef INET
770 case AF_INET:
771 (void)in_gif_detach(sc);
772 break;
773 #endif
774 #ifdef INET6
775 case AF_INET6:
776 (void)in6_gif_detach(sc);
777 break;
778 #endif
779 }
780
781 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
782 if (sc->gif_si == NULL) {
783 error = ENOMEM;
784 goto bad;
785 }
786
787 osrc = sc->gif_psrc;
788 sc->gif_psrc = sockaddr_dup(src, M_WAITOK);
789
790 odst = sc->gif_pdst;
791 sc->gif_pdst = sockaddr_dup(dst, M_WAITOK);
792
793 switch (sc->gif_psrc->sa_family) {
794 #ifdef INET
795 case AF_INET:
796 error = in_gif_attach(sc);
797 break;
798 #endif
799 #ifdef INET6
800 case AF_INET6:
801 error = in6_gif_attach(sc);
802 break;
803 #endif
804 default:
805 error = EINVAL;
806 break;
807 }
808 if (error) {
809 /* rollback */
810 sockaddr_free(sc->gif_psrc);
811 sockaddr_free(sc->gif_pdst);
812 sc->gif_psrc = osrc;
813 sc->gif_pdst = odst;
814 goto bad;
815 }
816
817 if (osrc)
818 sockaddr_free(osrc);
819 if (odst)
820 sockaddr_free(odst);
821
822 if (sc->gif_psrc && sc->gif_pdst)
823 ifp->if_flags |= IFF_RUNNING;
824 else
825 ifp->if_flags &= ~IFF_RUNNING;
826 splx(s);
827
828 return 0;
829
830 bad:
831 if (sc->gif_si) {
832 softint_disestablish(sc->gif_si);
833 sc->gif_si = NULL;
834 }
835 if (sc->gif_psrc && sc->gif_pdst)
836 ifp->if_flags |= IFF_RUNNING;
837 else
838 ifp->if_flags &= ~IFF_RUNNING;
839 splx(s);
840
841 return error;
842 }
843
844 void
845 gif_delete_tunnel(struct ifnet *ifp)
846 {
847 struct gif_softc *sc = (struct gif_softc *)ifp;
848 int s;
849
850 s = splsoftnet();
851
852 if (sc->gif_si) {
853 softint_disestablish(sc->gif_si);
854 sc->gif_si = NULL;
855 }
856 if (sc->gif_psrc) {
857 sockaddr_free(sc->gif_psrc);
858 sc->gif_psrc = NULL;
859 }
860 if (sc->gif_pdst) {
861 sockaddr_free(sc->gif_pdst);
862 sc->gif_pdst = NULL;
863 }
864 /* it is safe to detach from both */
865 #ifdef INET
866 (void)in_gif_detach(sc);
867 #endif
868 #ifdef INET6
869 (void)in6_gif_detach(sc);
870 #endif
871
872 if (sc->gif_psrc && sc->gif_pdst)
873 ifp->if_flags |= IFF_RUNNING;
874 else
875 ifp->if_flags &= ~IFF_RUNNING;
876 splx(s);
877 }
878
879 #ifdef ISO
880 struct eonhdr {
881 uint8_t version;
882 uint8_t class;
883 uint16_t cksum;
884 };
885
886 /*
887 * prepend EON header to ISO PDU
888 */
889 static struct mbuf *
890 gif_eon_encap(struct mbuf *m)
891 {
892 struct eonhdr *ehdr;
893
894 M_PREPEND(m, sizeof(*ehdr), M_DONTWAIT);
895 if (m && m->m_len < sizeof(*ehdr))
896 m = m_pullup(m, sizeof(*ehdr));
897 if (m == NULL)
898 return NULL;
899 ehdr = mtod(m, struct eonhdr *);
900 ehdr->version = 1;
901 ehdr->class = 0; /* always unicast */
902 #if 0
903 /* calculate the checksum of the eonhdr */
904 {
905 struct mbuf mhead;
906 memset(&mhead, 0, sizeof(mhead));
907 ehdr->cksum = 0;
908 mhead.m_data = (void *)ehdr;
909 mhead.m_len = sizeof(*ehdr);
910 mhead.m_next = 0;
911 iso_gen_csum(&mhead, offsetof(struct eonhdr, cksum),
912 mhead.m_len);
913 }
914 #else
915 /* since the data is always constant we'll just plug the value in */
916 ehdr->cksum = htons(0xfc02);
917 #endif
918 return m;
919 }
920
921 /*
922 * remove EON header and check checksum
923 */
924 static struct mbuf *
925 gif_eon_decap(struct ifnet *ifp, struct mbuf *m)
926 {
927 struct eonhdr *ehdr;
928
929 if (m->m_len < sizeof(*ehdr) &&
930 (m = m_pullup(m, sizeof(*ehdr))) == NULL) {
931 ifp->if_ierrors++;
932 return NULL;
933 }
934 if (iso_check_csum(m, sizeof(struct eonhdr))) {
935 m_freem(m);
936 return NULL;
937 }
938 m_adj(m, sizeof(*ehdr));
939 return m;
940 }
941 #endif /*ISO*/
Cache object: cff68937df2ca233c0629cd3c8f19688
|