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