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