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