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