if_gif.c revision 1.94 1 /* $NetBSD: if_gif.c,v 1.94 2015/12/03 03:03:58 knakahara 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.94 2015/12/03 03:03:58 knakahara 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 LIST_REMOVE(sc, gif_list);
164
165 gif_delete_tunnel(&sc->gif_if);
166 bpf_detach(ifp);
167 if_detach(ifp);
168 rtcache_free(&sc->gif_ro);
169
170 free(sc, M_DEVBUF);
171
172 return (0);
173 }
174
175 #ifdef GIF_ENCAPCHECK
176 int
177 gif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
178 {
179 struct ip ip;
180 struct gif_softc *sc;
181
182 sc = arg;
183 if (sc == NULL)
184 return 0;
185
186 if ((sc->gif_if.if_flags & IFF_UP) == 0)
187 return 0;
188
189 /* no physical address */
190 if (!sc->gif_psrc || !sc->gif_pdst)
191 return 0;
192
193 switch (proto) {
194 #ifdef INET
195 case IPPROTO_IPV4:
196 break;
197 #endif
198 #ifdef INET6
199 case IPPROTO_IPV6:
200 break;
201 #endif
202 default:
203 return 0;
204 }
205
206 /* Bail on short packets */
207 KASSERT(m->m_flags & M_PKTHDR);
208 if (m->m_pkthdr.len < sizeof(ip))
209 return 0;
210
211 m_copydata(m, 0, sizeof(ip), &ip);
212
213 switch (ip.ip_v) {
214 #ifdef INET
215 case 4:
216 if (sc->gif_psrc->sa_family != AF_INET ||
217 sc->gif_pdst->sa_family != AF_INET)
218 return 0;
219 return gif_encapcheck4(m, off, proto, arg);
220 #endif
221 #ifdef INET6
222 case 6:
223 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
224 return 0;
225 if (sc->gif_psrc->sa_family != AF_INET6 ||
226 sc->gif_pdst->sa_family != AF_INET6)
227 return 0;
228 return gif_encapcheck6(m, off, proto, arg);
229 #endif
230 default:
231 return 0;
232 }
233 }
234 #endif
235
236 int
237 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
238 struct rtentry *rt)
239 {
240 struct gif_softc *sc = ifp->if_softc;
241 int error = 0;
242 static int called = 0; /* XXX: MUTEX */
243 ALTQ_DECL(struct altq_pktattr pktattr;)
244 int s;
245
246 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
247
248 /*
249 * gif may cause infinite recursion calls when misconfigured.
250 * We'll prevent this by introducing upper limit.
251 * XXX: this mechanism may introduce another problem about
252 * mutual exclusion of the variable CALLED, especially if we
253 * use kernel thread.
254 */
255 if (++called > max_gif_nesting) {
256 log(LOG_NOTICE,
257 "gif_output: recursively called too many times(%d)\n",
258 called);
259 m_freem(m);
260 error = EIO; /* is there better errno? */
261 goto end;
262 }
263
264 m->m_flags &= ~(M_BCAST|M_MCAST);
265 if (!(ifp->if_flags & IFF_UP) ||
266 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
267 m_freem(m);
268 error = ENETDOWN;
269 goto end;
270 }
271
272 /* XXX should we check if our outer source is legal? */
273
274 /* use DLT_NULL encapsulation here to pass inner af type */
275 M_PREPEND(m, sizeof(int), M_DONTWAIT);
276 if (!m) {
277 error = ENOBUFS;
278 goto end;
279 }
280 *mtod(m, int *) = dst->sa_family;
281
282 /* Clear checksum-offload flags. */
283 m->m_pkthdr.csum_flags = 0;
284 m->m_pkthdr.csum_data = 0;
285
286 s = splnet();
287 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
288 if (error) {
289 splx(s);
290 goto end;
291 }
292 splx(s);
293
294 softint_schedule(sc->gif_si);
295 error = 0;
296
297 end:
298 called = 0; /* reset recursion counter */
299 if (error)
300 ifp->if_oerrors++;
301 return error;
302 }
303
304 static void
305 gifintr(void *arg)
306 {
307 struct gif_softc *sc;
308 struct ifnet *ifp;
309 struct mbuf *m;
310 int family;
311 int len;
312 int s;
313 int error;
314
315 sc = arg;
316 ifp = &sc->gif_if;
317
318 /* output processing */
319 while (1) {
320 s = splnet();
321 IFQ_DEQUEUE(&sc->gif_if.if_snd, m);
322 splx(s);
323 if (m == NULL)
324 break;
325
326 /* grab and chop off inner af type */
327 if (sizeof(int) > m->m_len) {
328 m = m_pullup(m, sizeof(int));
329 if (!m) {
330 ifp->if_oerrors++;
331 continue;
332 }
333 }
334 family = *mtod(m, int *);
335 bpf_mtap(ifp, m);
336 m_adj(m, sizeof(int));
337
338 len = m->m_pkthdr.len;
339
340 /* dispatch to output logic based on outer AF */
341 switch (sc->gif_psrc->sa_family) {
342 #ifdef INET
343 case AF_INET:
344 mutex_enter(softnet_lock);
345 error = in_gif_output(ifp, family, m);
346 mutex_exit(softnet_lock);
347 break;
348 #endif
349 #ifdef INET6
350 case AF_INET6:
351 mutex_enter(softnet_lock);
352 error = in6_gif_output(ifp, family, m);
353 mutex_exit(softnet_lock);
354 break;
355 #endif
356 default:
357 m_freem(m);
358 error = ENETDOWN;
359 break;
360 }
361
362 if (error)
363 ifp->if_oerrors++;
364 else {
365 ifp->if_opackets++;
366 ifp->if_obytes += len;
367 }
368 }
369 }
370
371 void
372 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
373 {
374 pktqueue_t *pktq;
375 size_t pktlen;
376 int s;
377
378 if (ifp == NULL) {
379 /* just in case */
380 m_freem(m);
381 return;
382 }
383
384 m->m_pkthdr.rcvif = ifp;
385 pktlen = m->m_pkthdr.len;
386
387 bpf_mtap_af(ifp, af, m);
388
389 /*
390 * Put the packet to the network layer input queue according to the
391 * specified address family. Note: we avoid direct call to the
392 * input function of the network layer in order to avoid recursion.
393 * This may be revisited in the future.
394 */
395 switch (af) {
396 #ifdef INET
397 case AF_INET:
398 pktq = ip_pktq;
399 break;
400 #endif
401 #ifdef INET6
402 case AF_INET6:
403 pktq = ip6_pktq;
404 break;
405 #endif
406 default:
407 m_freem(m);
408 return;
409 }
410
411 s = splnet();
412 if (__predict_true(pktq_enqueue(pktq, m, 0))) {
413 ifp->if_ibytes += pktlen;
414 ifp->if_ipackets++;
415 } else {
416 m_freem(m);
417 }
418 splx(s);
419 }
420
421 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
422 int
423 gif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
424 {
425 struct gif_softc *sc = ifp->if_softc;
426 struct ifreq *ifr = (struct ifreq*)data;
427 struct ifaddr *ifa = (struct ifaddr*)data;
428 int error = 0, size;
429 struct sockaddr *dst, *src;
430
431 switch (cmd) {
432 case SIOCINITIFADDR:
433 ifp->if_flags |= IFF_UP;
434 ifa->ifa_rtrequest = p2p_rtrequest;
435 break;
436
437 case SIOCADDMULTI:
438 case SIOCDELMULTI:
439 switch (ifr->ifr_addr.sa_family) {
440 #ifdef INET
441 case AF_INET: /* IP supports Multicast */
442 break;
443 #endif /* INET */
444 #ifdef INET6
445 case AF_INET6: /* IP6 supports Multicast */
446 break;
447 #endif /* INET6 */
448 default: /* Other protocols doesn't support Multicast */
449 error = EAFNOSUPPORT;
450 break;
451 }
452 break;
453
454 case SIOCSIFMTU:
455 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
456 return EINVAL;
457 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
458 error = 0;
459 break;
460
461 #ifdef INET
462 case SIOCSIFPHYADDR:
463 #endif
464 #ifdef INET6
465 case SIOCSIFPHYADDR_IN6:
466 #endif /* INET6 */
467 case SIOCSLIFPHYADDR:
468 switch (cmd) {
469 #ifdef INET
470 case SIOCSIFPHYADDR:
471 src = (struct sockaddr *)
472 &(((struct in_aliasreq *)data)->ifra_addr);
473 dst = (struct sockaddr *)
474 &(((struct in_aliasreq *)data)->ifra_dstaddr);
475 break;
476 #endif
477 #ifdef INET6
478 case SIOCSIFPHYADDR_IN6:
479 src = (struct sockaddr *)
480 &(((struct in6_aliasreq *)data)->ifra_addr);
481 dst = (struct sockaddr *)
482 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
483 break;
484 #endif
485 case SIOCSLIFPHYADDR:
486 src = (struct sockaddr *)
487 &(((struct if_laddrreq *)data)->addr);
488 dst = (struct sockaddr *)
489 &(((struct if_laddrreq *)data)->dstaddr);
490 break;
491 default:
492 return EINVAL;
493 }
494
495 /* sa_family must be equal */
496 if (src->sa_family != dst->sa_family)
497 return EINVAL;
498
499 /* validate sa_len */
500 switch (src->sa_family) {
501 #ifdef INET
502 case AF_INET:
503 if (src->sa_len != sizeof(struct sockaddr_in))
504 return EINVAL;
505 break;
506 #endif
507 #ifdef INET6
508 case AF_INET6:
509 if (src->sa_len != sizeof(struct sockaddr_in6))
510 return EINVAL;
511 break;
512 #endif
513 default:
514 return EAFNOSUPPORT;
515 }
516 switch (dst->sa_family) {
517 #ifdef INET
518 case AF_INET:
519 if (dst->sa_len != sizeof(struct sockaddr_in))
520 return EINVAL;
521 break;
522 #endif
523 #ifdef INET6
524 case AF_INET6:
525 if (dst->sa_len != sizeof(struct sockaddr_in6))
526 return EINVAL;
527 break;
528 #endif
529 default:
530 return EAFNOSUPPORT;
531 }
532
533 /* check sa_family looks sane for the cmd */
534 switch (cmd) {
535 case SIOCSIFPHYADDR:
536 if (src->sa_family == AF_INET)
537 break;
538 return EAFNOSUPPORT;
539 #ifdef INET6
540 case SIOCSIFPHYADDR_IN6:
541 if (src->sa_family == AF_INET6)
542 break;
543 return EAFNOSUPPORT;
544 #endif /* INET6 */
545 case SIOCSLIFPHYADDR:
546 /* checks done in the above */
547 break;
548 }
549
550 error = gif_set_tunnel(&sc->gif_if, src, dst);
551 break;
552
553 #ifdef SIOCDIFPHYADDR
554 case SIOCDIFPHYADDR:
555 gif_delete_tunnel(&sc->gif_if);
556 break;
557 #endif
558
559 case SIOCGIFPSRCADDR:
560 #ifdef INET6
561 case SIOCGIFPSRCADDR_IN6:
562 #endif /* INET6 */
563 if (sc->gif_psrc == NULL) {
564 error = EADDRNOTAVAIL;
565 goto bad;
566 }
567 src = sc->gif_psrc;
568 switch (cmd) {
569 #ifdef INET
570 case SIOCGIFPSRCADDR:
571 dst = &ifr->ifr_addr;
572 size = sizeof(ifr->ifr_addr);
573 break;
574 #endif /* INET */
575 #ifdef INET6
576 case SIOCGIFPSRCADDR_IN6:
577 dst = (struct sockaddr *)
578 &(((struct in6_ifreq *)data)->ifr_addr);
579 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
580 break;
581 #endif /* INET6 */
582 default:
583 error = EADDRNOTAVAIL;
584 goto bad;
585 }
586 if (src->sa_len > size)
587 return EINVAL;
588 memcpy(dst, src, src->sa_len);
589 break;
590
591 case SIOCGIFPDSTADDR:
592 #ifdef INET6
593 case SIOCGIFPDSTADDR_IN6:
594 #endif /* INET6 */
595 if (sc->gif_pdst == NULL) {
596 error = EADDRNOTAVAIL;
597 goto bad;
598 }
599 src = sc->gif_pdst;
600 switch (cmd) {
601 #ifdef INET
602 case SIOCGIFPDSTADDR:
603 dst = &ifr->ifr_addr;
604 size = sizeof(ifr->ifr_addr);
605 break;
606 #endif /* INET */
607 #ifdef INET6
608 case SIOCGIFPDSTADDR_IN6:
609 dst = (struct sockaddr *)
610 &(((struct in6_ifreq *)data)->ifr_addr);
611 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
612 break;
613 #endif /* INET6 */
614 default:
615 error = EADDRNOTAVAIL;
616 goto bad;
617 }
618 if (src->sa_len > size)
619 return EINVAL;
620 memcpy(dst, src, src->sa_len);
621 break;
622
623 case SIOCGLIFPHYADDR:
624 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
625 error = EADDRNOTAVAIL;
626 goto bad;
627 }
628
629 /* copy src */
630 src = sc->gif_psrc;
631 dst = (struct sockaddr *)
632 &(((struct if_laddrreq *)data)->addr);
633 size = sizeof(((struct if_laddrreq *)data)->addr);
634 if (src->sa_len > size)
635 return EINVAL;
636 memcpy(dst, src, src->sa_len);
637
638 /* copy dst */
639 src = sc->gif_pdst;
640 dst = (struct sockaddr *)
641 &(((struct if_laddrreq *)data)->dstaddr);
642 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
643 if (src->sa_len > size)
644 return EINVAL;
645 memcpy(dst, src, src->sa_len);
646 break;
647
648 default:
649 return ifioctl_common(ifp, cmd, data);
650 }
651 bad:
652 return error;
653 }
654
655 int
656 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
657 {
658 struct gif_softc *sc = ifp->if_softc;
659 struct gif_softc *sc2;
660 struct sockaddr *osrc, *odst;
661 int s;
662 int error;
663
664 s = splsoftnet();
665
666 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
667 if (sc2 == sc)
668 continue;
669 if (!sc2->gif_pdst || !sc2->gif_psrc)
670 continue;
671 /* can't configure same pair of address onto two gifs */
672 if (sockaddr_cmp(sc2->gif_pdst, dst) == 0 &&
673 sockaddr_cmp(sc2->gif_psrc, src) == 0) {
674 error = EADDRNOTAVAIL;
675 /* continue to use the old configureation. */
676 goto out;
677 }
678
679 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
680 }
681
682 if (sc->gif_si) {
683 softint_disestablish(sc->gif_si);
684 sc->gif_si = NULL;
685 }
686
687 /* XXX we can detach from both, but be polite just in case */
688 if (sc->gif_psrc)
689 switch (sc->gif_psrc->sa_family) {
690 #ifdef INET
691 case AF_INET:
692 (void)in_gif_detach(sc);
693 break;
694 #endif
695 #ifdef INET6
696 case AF_INET6:
697 (void)in6_gif_detach(sc);
698 break;
699 #endif
700 }
701
702 osrc = sc->gif_psrc;
703 odst = sc->gif_pdst;
704 sc->gif_psrc = sc->gif_pdst = NULL;
705 sc->gif_si = softint_establish(SOFTINT_NET, gifintr, sc);
706 if (sc->gif_si == NULL) {
707 error = ENOMEM;
708 goto rollback;
709 }
710
711 if ((sc->gif_psrc = sockaddr_dup(src, M_WAITOK)) == NULL) {
712 error = ENOMEM;
713 goto rollback;
714 }
715
716 if ((sc->gif_pdst = sockaddr_dup(dst, M_WAITOK)) == NULL) {
717 error = ENOMEM;
718 goto rollback;
719 }
720
721 switch (sc->gif_psrc->sa_family) {
722 #ifdef INET
723 case AF_INET:
724 error = in_gif_attach(sc);
725 break;
726 #endif
727 #ifdef INET6
728 case AF_INET6:
729 error = in6_gif_attach(sc);
730 break;
731 #endif
732 default:
733 error = EINVAL;
734 break;
735 }
736 if (error)
737 goto rollback;
738
739 if (osrc)
740 sockaddr_free(osrc);
741 if (odst)
742 sockaddr_free(odst);
743
744 error = 0;
745 goto out;
746
747 rollback:
748 if (sc->gif_psrc != NULL)
749 sockaddr_free(sc->gif_psrc);
750 if (sc->gif_pdst != NULL)
751 sockaddr_free(sc->gif_pdst);
752 sc->gif_psrc = osrc;
753 sc->gif_pdst = odst;
754
755 if (sc->gif_si) {
756 softint_disestablish(sc->gif_si);
757 sc->gif_si = NULL;
758 }
759
760 out:
761 if (sc->gif_psrc && sc->gif_pdst)
762 ifp->if_flags |= IFF_RUNNING;
763 else
764 ifp->if_flags &= ~IFF_RUNNING;
765
766 splx(s);
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