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