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