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