if_gif.c revision 1.88 1 /* $NetBSD: if_gif.c,v 1.88 2015/08/24 22:21:26 pooka 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.88 2015/08/24 22:21:26 pooka Exp $");
35
36 #ifdef _KERNEL_OPT
37 #include "opt_inet.h"
38 #endif
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <sys/errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/time.h>
49 #include <sys/socketvar.h>
50 #include <sys/syslog.h>
51 #include <sys/proc.h>
52 #include <sys/protosw.h>
53 #include <sys/cpu.h>
54 #include <sys/intr.h>
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 #endif /* INET */
68 #include <netinet/in_gif.h>
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 #include <netinet/ip_encap.h>
82 #include <net/if_gif.h>
83
84 #include <net/net_osdep.h>
85
86 #include "ioconf.h"
87
88 static void gifintr(void *);
89
90 /*
91 * gif global variable definitions
92 */
93 LIST_HEAD(, gif_softc) gif_softc_list; /* XXX should be static */
94
95 static int gif_clone_create(struct if_clone *, int);
96 static int gif_clone_destroy(struct ifnet *);
97
98 static struct if_clone gif_cloner =
99 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
100
101 #ifndef MAX_GIF_NEST
102 /*
103 * This macro controls the upper limitation on nesting of gif tunnels.
104 * Since, setting a large value to this macro with a careless configuration
105 * may introduce system crash, we don't allow any nestings by default.
106 * If you need to configure nested gif tunnels, you can define this macro
107 * in your kernel configuration file. However, if you do so, please be
108 * careful to configure the tunnels so that it won't make a loop.
109 */
110 #define MAX_GIF_NEST 1
111 #endif
112 static int max_gif_nesting = MAX_GIF_NEST;
113
114 /* ARGSUSED */
115 void
116 gifattach(int count)
117 {
118
119 LIST_INIT(&gif_softc_list);
120 if_clone_attach(&gif_cloner);
121 }
122
123 static int
124 gif_clone_create(struct if_clone *ifc, int unit)
125 {
126 struct gif_softc *sc;
127
128 sc = malloc(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK|M_ZERO);
129
130 if_initname(&sc->gif_if, ifc->ifc_name, unit);
131
132 gifattach0(sc);
133
134 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
135 return (0);
136 }
137
138 void
139 gifattach0(struct gif_softc *sc)
140 {
141
142 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
143
144 sc->gif_if.if_addrlen = 0;
145 sc->gif_if.if_mtu = GIF_MTU;
146 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
147 sc->gif_if.if_ioctl = gif_ioctl;
148 sc->gif_if.if_output = gif_output;
149 sc->gif_if.if_type = IFT_GIF;
150 sc->gif_if.if_dlt = DLT_NULL;
151 sc->gif_if.if_softc = sc;
152 IFQ_SET_READY(&sc->gif_if.if_snd);
153 if_attach(&sc->gif_if);
154 if_alloc_sadl(&sc->gif_if);
155 bpf_attach(&sc->gif_if, DLT_NULL, sizeof(u_int));
156 }
157
158 static int
159 gif_clone_destroy(struct ifnet *ifp)
160 {
161 struct gif_softc *sc = (void *) ifp;
162
163 gif_delete_tunnel(&sc->gif_if);
164 LIST_REMOVE(sc, gif_list);
165 #ifdef INET6
166 encap_detach(sc->encap_cookie6);
167 #endif
168 #ifdef INET
169 encap_detach(sc->encap_cookie4);
170 #endif
171
172 bpf_detach(ifp);
173 if_detach(ifp);
174 rtcache_free(&sc->gif_ro);
175
176 free(sc, M_DEVBUF);
177
178 return (0);
179 }
180
181 #ifdef GIF_ENCAPCHECK
182 int
183 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
184 {
185 struct ip ip;
186 struct gif_softc *sc;
187
188 sc = arg;
189 if (sc == NULL)
190 return 0;
191
192 if ((sc->gif_if.if_flags & IFF_UP) == 0)
193 return 0;
194
195 /* no physical address */
196 if (!sc->gif_psrc || !sc->gif_pdst)
197 return 0;
198
199 switch (proto) {
200 #ifdef INET
201 case IPPROTO_IPV4:
202 break;
203 #endif
204 #ifdef INET6
205 case IPPROTO_IPV6:
206 break;
207 #endif
208 default:
209 return 0;
210 }
211
212 /* Bail on short packets */
213 KASSERT(m->m_flags & M_PKTHDR);
214 if (m->m_pkthdr.len < sizeof(ip))
215 return 0;
216
217 m_copydata(m, 0, sizeof(ip), &ip);
218
219 switch (ip.ip_v) {
220 #ifdef INET
221 case 4:
222 if (sc->gif_psrc->sa_family != AF_INET ||
223 sc->gif_pdst->sa_family != AF_INET)
224 return 0;
225 return gif_encapcheck4(m, off, proto, arg);
226 #endif
227 #ifdef INET6
228 case 6:
229 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
230 return 0;
231 if (sc->gif_psrc->sa_family != AF_INET6 ||
232 sc->gif_pdst->sa_family != AF_INET6)
233 return 0;
234 return gif_encapcheck6(m, off, proto, arg);
235 #endif
236 default:
237 return 0;
238 }
239 }
240 #endif
241
242 int
243 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
244 struct rtentry *rt)
245 {
246 struct gif_softc *sc = ifp->if_softc;
247 int error = 0;
248 static int called = 0; /* XXX: MUTEX */
249 ALTQ_DECL(struct altq_pktattr pktattr;)
250 int s;
251
252 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
253
254 /*
255 * gif may cause infinite recursion calls when misconfigured.
256 * We'll prevent this by introducing upper limit.
257 * XXX: this mechanism may introduce another problem about
258 * mutual exclusion of the variable CALLED, especially if we
259 * use kernel thread.
260 */
261 if (++called > max_gif_nesting) {
262 log(LOG_NOTICE,
263 "gif_output: recursively called too many times(%d)\n",
264 called);
265 m_freem(m);
266 error = EIO; /* is there better errno? */
267 goto end;
268 }
269
270 m->m_flags &= ~(M_BCAST|M_MCAST);
271 if (!(ifp->if_flags & IFF_UP) ||
272 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
273 m_freem(m);
274 error = ENETDOWN;
275 goto end;
276 }
277
278 /* XXX should we check if our outer source is legal? */
279
280 /* use DLT_NULL encapsulation here to pass inner af type */
281 M_PREPEND(m, sizeof(int), M_DONTWAIT);
282 if (!m) {
283 error = ENOBUFS;
284 goto end;
285 }
286 *mtod(m, int *) = dst->sa_family;
287
288 /* Clear checksum-offload flags. */
289 m->m_pkthdr.csum_flags = 0;
290 m->m_pkthdr.csum_data = 0;
291
292 s = splnet();
293 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
294 if (error) {
295 splx(s);
296 goto end;
297 }
298 splx(s);
299
300 softint_schedule(sc->gif_si);
301 error = 0;
302
303 end:
304 called = 0; /* reset recursion counter */
305 if (error)
306 ifp->if_oerrors++;
307 return error;
308 }
309
310 static void
311 gifintr(void *arg)
312 {
313 struct gif_softc *sc;
314 struct ifnet *ifp;
315 struct mbuf *m;
316 int family;
317 int len;
318 int s;
319 int error;
320
321 sc = arg;
322 ifp = &sc->gif_if;
323
324 /* output processing */
325 while (1) {
326 s = splnet();
327 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
328 splx(s);
329 if (m == NULL)
330 break;
331
332 /* grab and chop off inner af type */
333 if (sizeof(int) > m->m_len) {
334 m = m_pullup(m, sizeof(int));
335 if (!m) {
336 ifp->if_oerrors++;
337 continue;
338 }
339 }
340 family = *mtod(m, int *);
341 bpf_mtap(ifp, m);
342 m_adj(m, sizeof(int));
343
344 len = m->m_pkthdr.len;
345
346 /* dispatch to output logic based on outer AF */
347 switch (sc->gif_psrc->sa_family) {
348 #ifdef INET
349 case AF_INET:
350 mutex_enter(softnet_lock);
351 error = in_gif_output(ifp, family, m);
352 mutex_exit(softnet_lock);
353 break;
354 #endif
355 #ifdef INET6
356 case AF_INET6:
357 mutex_enter(softnet_lock);
358 error = in6_gif_output(ifp, family, m);
359 mutex_exit(softnet_lock);
360 break;
361 #endif
362 default:
363 m_freem(m);
364 error = ENETDOWN;
365 break;
366 }
367
368 if (error)
369 ifp->if_oerrors++;
370 else {
371 ifp->if_opackets++;
372 ifp->if_obytes += len;
373 }
374 }
375 }
376
377 void
378 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
379 {
380 pktqueue_t *pktq;
381 size_t pktlen;
382 int s;
383
384 if (ifp == NULL) {
385 /* just in case */
386 m_freem(m);
387 return;
388 }
389
390 m->m_pkthdr.rcvif = ifp;
391 pktlen = m->m_pkthdr.len;
392
393 bpf_mtap_af(ifp, af, m);
394
395 /*
396 * Put the packet to the network layer input queue according to the
397 * specified address family. Note: we avoid direct call to the
398 * input function of the network layer in order to avoid recursion.
399 * This may be revisited in the future.
400 */
401 switch (af) {
402 #ifdef INET
403 case AF_INET:
404 pktq = ip_pktq;
405 break;
406 #endif
407 #ifdef INET6
408 case AF_INET6:
409 pktq = ip6_pktq;
410 break;
411 #endif
412 default:
413 m_freem(m);
414 return;
415 }
416
417 s = splnet();
418 if (__predict_true(pktq_enqueue(pktq, m, 0))) {
419 ifp->if_ibytes += pktlen;
420 ifp->if_ipackets++;
421 } else {
422 m_freem(m);
423 }
424 splx(s);
425 }
426
427 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
428 int
429 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
430 {
431 struct gif_softc *sc = ifp->if_softc;
432 struct ifreq *ifr = (struct ifreq*)data;
433 struct ifaddr *ifa = (struct ifaddr*)data;
434 int error = 0, size;
435 struct sockaddr *dst, *src;
436
437 switch (cmd) {
438 case SIOCINITIFADDR:
439 ifp->if_flags |= IFF_UP;
440 ifa->ifa_rtrequest = p2p_rtrequest;
441 break;
442
443 case SIOCADDMULTI:
444 case SIOCDELMULTI:
445 switch (ifr->ifr_addr.sa_family) {
446 #ifdef INET
447 case AF_INET: /* IP supports Multicast */
448 break;
449 #endif /* INET */
450 #ifdef INET6
451 case AF_INET6: /* IP6 supports Multicast */
452 break;
453 #endif /* INET6 */
454 default: /* Other protocols doesn't support Multicast */
455 error = EAFNOSUPPORT;
456 break;
457 }
458 break;
459
460 case SIOCSIFMTU:
461 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
462 return EINVAL;
463 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
464 error = 0;
465 break;
466
467 #ifdef INET
468 case SIOCSIFPHYADDR:
469 #endif
470 #ifdef INET6
471 case SIOCSIFPHYADDR_IN6:
472 #endif /* INET6 */
473 case SIOCSLIFPHYADDR:
474 switch (cmd) {
475 #ifdef INET
476 case SIOCSIFPHYADDR:
477 src = (struct sockaddr *)
478 &(((struct in_aliasreq *)data)->ifra_addr);
479 dst = (struct sockaddr *)
480 &(((struct in_aliasreq *)data)->ifra_dstaddr);
481 break;
482 #endif
483 #ifdef INET6
484 case SIOCSIFPHYADDR_IN6:
485 src = (struct sockaddr *)
486 &(((struct in6_aliasreq *)data)->ifra_addr);
487 dst = (struct sockaddr *)
488 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
489 break;
490 #endif
491 case SIOCSLIFPHYADDR:
492 src = (struct sockaddr *)
493 &(((struct if_laddrreq *)data)->addr);
494 dst = (struct sockaddr *)
495 &(((struct if_laddrreq *)data)->dstaddr);
496 break;
497 default:
498 return EINVAL;
499 }
500
501 /* sa_family must be equal */
502 if (src->sa_family != dst->sa_family)
503 return EINVAL;
504
505 /* validate sa_len */
506 switch (src->sa_family) {
507 #ifdef INET
508 case AF_INET:
509 if (src->sa_len != sizeof(struct sockaddr_in))
510 return EINVAL;
511 break;
512 #endif
513 #ifdef INET6
514 case AF_INET6:
515 if (src->sa_len != sizeof(struct sockaddr_in6))
516 return EINVAL;
517 break;
518 #endif
519 default:
520 return EAFNOSUPPORT;
521 }
522 switch (dst->sa_family) {
523 #ifdef INET
524 case AF_INET:
525 if (dst->sa_len != sizeof(struct sockaddr_in))
526 return EINVAL;
527 break;
528 #endif
529 #ifdef INET6
530 case AF_INET6:
531 if (dst->sa_len != sizeof(struct sockaddr_in6))
532 return EINVAL;
533 break;
534 #endif
535 default:
536 return EAFNOSUPPORT;
537 }
538
539 /* check sa_family looks sane for the cmd */
540 switch (cmd) {
541 case SIOCSIFPHYADDR:
542 if (src->sa_family == AF_INET)
543 break;
544 return EAFNOSUPPORT;
545 #ifdef INET6
546 case SIOCSIFPHYADDR_IN6:
547 if (src->sa_family == AF_INET6)
548 break;
549 return EAFNOSUPPORT;
550 #endif /* INET6 */
551 case SIOCSLIFPHYADDR:
552 /* checks done in the above */
553 break;
554 }
555
556 error = gif_set_tunnel(&sc->gif_if, src, dst);
557 break;
558
559 #ifdef SIOCDIFPHYADDR
560 case SIOCDIFPHYADDR:
561 gif_delete_tunnel(&sc->gif_if);
562 break;
563 #endif
564
565 case SIOCGIFPSRCADDR:
566 #ifdef INET6
567 case SIOCGIFPSRCADDR_IN6:
568 #endif /* INET6 */
569 if (sc->gif_psrc == NULL) {
570 error = EADDRNOTAVAIL;
571 goto bad;
572 }
573 src = sc->gif_psrc;
574 switch (cmd) {
575 #ifdef INET
576 case SIOCGIFPSRCADDR:
577 dst = &ifr->ifr_addr;
578 size = sizeof(ifr->ifr_addr);
579 break;
580 #endif /* INET */
581 #ifdef INET6
582 case SIOCGIFPSRCADDR_IN6:
583 dst = (struct sockaddr *)
584 &(((struct in6_ifreq *)data)->ifr_addr);
585 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
586 break;
587 #endif /* INET6 */
588 default:
589 error = EADDRNOTAVAIL;
590 goto bad;
591 }
592 if (src->sa_len > size)
593 return EINVAL;
594 memcpy(dst, src, src->sa_len);
595 break;
596
597 case SIOCGIFPDSTADDR:
598 #ifdef INET6
599 case SIOCGIFPDSTADDR_IN6:
600 #endif /* INET6 */
601 if (sc->gif_pdst == NULL) {
602 error = EADDRNOTAVAIL;
603 goto bad;
604 }
605 src = sc->gif_pdst;
606 switch (cmd) {
607 #ifdef INET
608 case SIOCGIFPDSTADDR:
609 dst = &ifr->ifr_addr;
610 size = sizeof(ifr->ifr_addr);
611 break;
612 #endif /* INET */
613 #ifdef INET6
614 case SIOCGIFPDSTADDR_IN6:
615 dst = (struct sockaddr *)
616 &(((struct in6_ifreq *)data)->ifr_addr);
617 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
618 break;
619 #endif /* INET6 */
620 default:
621 error = EADDRNOTAVAIL;
622 goto bad;
623 }
624 if (src->sa_len > size)
625 return EINVAL;
626 memcpy(dst, src, src->sa_len);
627 break;
628
629 case SIOCGLIFPHYADDR:
630 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
631 error = EADDRNOTAVAIL;
632 goto bad;
633 }
634
635 /* copy src */
636 src = sc->gif_psrc;
637 dst = (struct sockaddr *)
638 &(((struct if_laddrreq *)data)->addr);
639 size = sizeof(((struct if_laddrreq *)data)->addr);
640 if (src->sa_len > size)
641 return EINVAL;
642 memcpy(dst, src, src->sa_len);
643
644 /* copy dst */
645 src = sc->gif_pdst;
646 dst = (struct sockaddr *)
647 &(((struct if_laddrreq *)data)->dstaddr);
648 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
649 if (src->sa_len > size)
650 return EINVAL;
651 memcpy(dst, src, src->sa_len);
652 break;
653
654 default:
655 return ifioctl_common(ifp, cmd, data);
656 }
657 bad:
658 return error;
659 }
660
661 int
662 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
663 {
664 struct gif_softc *sc = ifp->if_softc;
665 struct gif_softc *sc2;
666 struct sockaddr *osrc, *odst;
667 int s;
668 int error;
669
670 s = splsoftnet();
671
672 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
673 if (sc2 == sc)
674 continue;
675 if (!sc2->gif_pdst || !sc2->gif_psrc)
676 continue;
677 /* can't configure same pair of address onto two gifs */
678 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
679 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
680 error = EADDRNOTAVAIL;
681 goto bad;
682 }
683
684 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
685 }
686
687 if (sc->gif_si) {
688 softint_disestablish(sc->gif_si);
689 sc->gif_si = NULL;
690 }
691
692 /* XXX we can detach from both, but be polite just in case */
693 if (sc->gif_psrc)
694 switch (sc->gif_psrc->sa_family) {
695 #ifdef INET
696 case AF_INET:
697 (void)in_gif_detach(sc);
698 break;
699 #endif
700 #ifdef INET6
701 case AF_INET6:
702 (void)in6_gif_detach(sc);
703 break;
704 #endif
705 }
706
707 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
708 if (sc->gif_si == NULL) {
709 error = ENOMEM;
710 goto bad;
711 }
712
713 osrc = sc->gif_psrc;
714 sc->gif_psrc = sockaddr_dup(src, M_WAITOK);
715
716 odst = sc->gif_pdst;
717 sc->gif_pdst = sockaddr_dup(dst, M_WAITOK);
718
719 switch (sc->gif_psrc->sa_family) {
720 #ifdef INET
721 case AF_INET:
722 error = in_gif_attach(sc);
723 break;
724 #endif
725 #ifdef INET6
726 case AF_INET6:
727 error = in6_gif_attach(sc);
728 break;
729 #endif
730 default:
731 error = EINVAL;
732 break;
733 }
734 if (error) {
735 /* rollback */
736 sockaddr_free(sc->gif_psrc);
737 sockaddr_free(sc->gif_pdst);
738 sc->gif_psrc = osrc;
739 sc->gif_pdst = odst;
740 goto bad;
741 }
742
743 if (osrc)
744 sockaddr_free(osrc);
745 if (odst)
746 sockaddr_free(odst);
747
748 if (sc->gif_psrc && sc->gif_pdst)
749 ifp->if_flags |= IFF_RUNNING;
750 else
751 ifp->if_flags &= ~IFF_RUNNING;
752 splx(s);
753
754 return 0;
755
756 bad:
757 if (sc->gif_si) {
758 softint_disestablish(sc->gif_si);
759 sc->gif_si = NULL;
760 }
761 if (sc->gif_psrc && sc->gif_pdst)
762 ifp->if_flags |= IFF_RUNNING;
763 else
764 ifp->if_flags &= ~IFF_RUNNING;
765 splx(s);
766
767 return error;
768 }
769
770 void
771 gif_delete_tunnel(struct ifnet *ifp)
772 {
773 struct gif_softc *sc = ifp->if_softc;
774 int s;
775
776 s = splsoftnet();
777
778 if (sc->gif_si) {
779 softint_disestablish(sc->gif_si);
780 sc->gif_si = NULL;
781 }
782 if (sc->gif_psrc) {
783 sockaddr_free(sc->gif_psrc);
784 sc->gif_psrc = NULL;
785 }
786 if (sc->gif_pdst) {
787 sockaddr_free(sc->gif_pdst);
788 sc->gif_pdst = NULL;
789 }
790 /* it is safe to detach from both */
791 #ifdef INET
792 (void)in_gif_detach(sc);
793 #endif
794 #ifdef INET6
795 (void)in6_gif_detach(sc);
796 #endif
797
798 if (sc->gif_psrc && sc->gif_pdst)
799 ifp->if_flags |= IFF_RUNNING;
800 else
801 ifp->if_flags &= ~IFF_RUNNING;
802 splx(s);
803 }
804