1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org> 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 * $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "opt_inet.h" 39 #include "opt_inet6.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/lock.h> 45 #include <sys/malloc.h> 46 #include <sys/mbuf.h> 47 #include <sys/module.h> 48 #include <sys/rmlock.h> 49 #include <sys/socket.h> 50 #include <sys/sockio.h> 51 #include <sys/sx.h> 52 #include <sys/errno.h> 53 #include <sys/time.h> 54 #include <sys/sysctl.h> 55 #include <sys/syslog.h> 56 #include <sys/priv.h> 57 #include <sys/proc.h> 58 #include <sys/conf.h> 59 #include <machine/cpu.h> 60 61 #include <net/if.h> 62 #include <net/if_var.h> 63 #include <net/if_clone.h> 64 #include <net/if_types.h> 65 #include <net/netisr.h> 66 #include <net/route.h> 67 #include <net/bpf.h> 68 #include <net/vnet.h> 69 70 #include <netinet/in.h> 71 #include <netinet/in_systm.h> 72 #include <netinet/ip.h> 73 #include <netinet/ip_ecn.h> 74 #ifdef INET 75 #include <netinet/in_var.h> 76 #include <netinet/ip_var.h> 77 #endif /* INET */ 78 79 #ifdef INET6 80 #ifndef INET 81 #include <netinet/in.h> 82 #endif 83 #include <netinet6/in6_var.h> 84 #include <netinet/ip6.h> 85 #include <netinet6/ip6_ecn.h> 86 #include <netinet6/ip6_var.h> 87 #endif /* INET6 */ 88 89 #include <netinet/ip_encap.h> 90 #include <net/ethernet.h> 91 #include <net/if_bridgevar.h> 92 #include <net/if_gif.h> 93 94 #include <security/mac/mac_framework.h> 95 96 static const char gifname[] = "gif"; 97 98 MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); 99 static struct sx gif_ioctl_sx; 100 SX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl"); 101 102 void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); 103 void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); 104 void (*ng_gif_attach_p)(struct ifnet *ifp); 105 void (*ng_gif_detach_p)(struct ifnet *ifp); 106 107 static void gif_delete_tunnel(struct gif_softc *); 108 static int gif_ioctl(struct ifnet *, u_long, caddr_t); 109 static int gif_transmit(struct ifnet *, struct mbuf *); 110 static void gif_qflush(struct ifnet *); 111 static int gif_clone_create(struct if_clone *, int, caddr_t); 112 static void gif_clone_destroy(struct ifnet *); 113 VNET_DEFINE_STATIC(struct if_clone *, gif_cloner); 114 #define V_gif_cloner VNET(gif_cloner) 115 116 SYSCTL_DECL(_net_link); 117 static SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0, 118 "Generic Tunnel Interface"); 119 #ifndef MAX_GIF_NEST 120 /* 121 * This macro controls the default upper limitation on nesting of gif tunnels. 122 * Since, setting a large value to this macro with a careless configuration 123 * may introduce system crash, we don't allow any nestings by default. 124 * If you need to configure nested gif tunnels, you can define this macro 125 * in your kernel configuration file. However, if you do so, please be 126 * careful to configure the tunnels so that it won't make a loop. 127 */ 128 #define MAX_GIF_NEST 1 129 #endif 130 VNET_DEFINE_STATIC(int, max_gif_nesting) = MAX_GIF_NEST; 131 #define V_max_gif_nesting VNET(max_gif_nesting) 132 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_VNET | CTLFLAG_RW, 133 &VNET_NAME(max_gif_nesting), 0, "Max nested tunnels"); 134 135 static int 136 gif_clone_create(struct if_clone *ifc, int unit, caddr_t params) 137 { 138 struct gif_softc *sc; 139 140 sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO); 141 sc->gif_fibnum = curthread->td_proc->p_fibnum; 142 GIF2IFP(sc) = if_alloc(IFT_GIF); 143 GIF2IFP(sc)->if_softc = sc; 144 if_initname(GIF2IFP(sc), gifname, unit); 145 146 GIF2IFP(sc)->if_addrlen = 0; 147 GIF2IFP(sc)->if_mtu = GIF_MTU; 148 GIF2IFP(sc)->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 149 GIF2IFP(sc)->if_ioctl = gif_ioctl; 150 GIF2IFP(sc)->if_transmit = gif_transmit; 151 GIF2IFP(sc)->if_qflush = gif_qflush; 152 GIF2IFP(sc)->if_output = gif_output; 153 GIF2IFP(sc)->if_capabilities |= IFCAP_LINKSTATE; 154 GIF2IFP(sc)->if_capenable |= IFCAP_LINKSTATE; 155 if_attach(GIF2IFP(sc)); 156 bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t)); 157 if (ng_gif_attach_p != NULL) 158 (*ng_gif_attach_p)(GIF2IFP(sc)); 159 160 return (0); 161 } 162 163 static void 164 gif_clone_destroy(struct ifnet *ifp) 165 { 166 struct gif_softc *sc; 167 168 sx_xlock(&gif_ioctl_sx); 169 sc = ifp->if_softc; 170 gif_delete_tunnel(sc); 171 if (ng_gif_detach_p != NULL) 172 (*ng_gif_detach_p)(ifp); 173 bpfdetach(ifp); 174 if_detach(ifp); 175 ifp->if_softc = NULL; 176 sx_xunlock(&gif_ioctl_sx); 177 178 GIF_WAIT(); 179 if_free(ifp); 180 free(sc, M_GIF); 181 } 182 183 static void 184 vnet_gif_init(const void *unused __unused) 185 { 186 187 V_gif_cloner = if_clone_simple(gifname, gif_clone_create, 188 gif_clone_destroy, 0); 189 #ifdef INET 190 in_gif_init(); 191 #endif 192 #ifdef INET6 193 in6_gif_init(); 194 #endif 195 } 196 VNET_SYSINIT(vnet_gif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 197 vnet_gif_init, NULL); 198 199 static void 200 vnet_gif_uninit(const void *unused __unused) 201 { 202 203 if_clone_detach(V_gif_cloner); 204 #ifdef INET 205 in_gif_uninit(); 206 #endif 207 #ifdef INET6 208 in6_gif_uninit(); 209 #endif 210 } 211 VNET_SYSUNINIT(vnet_gif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 212 vnet_gif_uninit, NULL); 213 214 static int 215 gifmodevent(module_t mod, int type, void *data) 216 { 217 218 switch (type) { 219 case MOD_LOAD: 220 case MOD_UNLOAD: 221 break; 222 default: 223 return (EOPNOTSUPP); 224 } 225 return (0); 226 } 227 228 static moduledata_t gif_mod = { 229 "if_gif", 230 gifmodevent, 231 0 232 }; 233 234 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 235 MODULE_VERSION(if_gif, 1); 236 237 struct gif_list * 238 gif_hashinit(void) 239 { 240 struct gif_list *hash; 241 int i; 242 243 hash = malloc(sizeof(struct gif_list) * GIF_HASH_SIZE, 244 M_GIF, M_WAITOK); 245 for (i = 0; i < GIF_HASH_SIZE; i++) 246 CK_LIST_INIT(&hash[i]); 247 248 return (hash); 249 } 250 251 void 252 gif_hashdestroy(struct gif_list *hash) 253 { 254 255 free(hash, M_GIF); 256 } 257 258 #define MTAG_GIF 1080679712 259 static int 260 gif_transmit(struct ifnet *ifp, struct mbuf *m) 261 { 262 struct gif_softc *sc; 263 struct etherip_header *eth; 264 #ifdef INET 265 struct ip *ip; 266 #endif 267 #ifdef INET6 268 struct ip6_hdr *ip6; 269 uint32_t t; 270 #endif 271 uint32_t af; 272 uint8_t proto, ecn; 273 int error; 274 275 GIF_RLOCK(); 276 #ifdef MAC 277 error = mac_ifnet_check_transmit(ifp, m); 278 if (error) { 279 m_freem(m); 280 goto err; 281 } 282 #endif 283 error = ENETDOWN; 284 sc = ifp->if_softc; 285 if ((ifp->if_flags & IFF_MONITOR) != 0 || 286 (ifp->if_flags & IFF_UP) == 0 || 287 (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 288 sc->gif_family == 0 || 289 (error = if_tunnel_check_nesting(ifp, m, MTAG_GIF, 290 V_max_gif_nesting)) != 0) { 291 m_freem(m); 292 goto err; 293 } 294 /* Now pull back the af that we stashed in the csum_data. */ 295 if (ifp->if_bridge) 296 af = AF_LINK; 297 else 298 af = m->m_pkthdr.csum_data; 299 m->m_flags &= ~(M_BCAST|M_MCAST); 300 M_SETFIB(m, sc->gif_fibnum); 301 BPF_MTAP2(ifp, &af, sizeof(af), m); 302 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 303 if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 304 /* inner AF-specific encapsulation */ 305 ecn = 0; 306 switch (af) { 307 #ifdef INET 308 case AF_INET: 309 proto = IPPROTO_IPV4; 310 if (m->m_len < sizeof(struct ip)) 311 m = m_pullup(m, sizeof(struct ip)); 312 if (m == NULL) { 313 error = ENOBUFS; 314 goto err; 315 } 316 ip = mtod(m, struct ip *); 317 ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 318 ECN_NOCARE, &ecn, &ip->ip_tos); 319 break; 320 #endif 321 #ifdef INET6 322 case AF_INET6: 323 proto = IPPROTO_IPV6; 324 if (m->m_len < sizeof(struct ip6_hdr)) 325 m = m_pullup(m, sizeof(struct ip6_hdr)); 326 if (m == NULL) { 327 error = ENOBUFS; 328 goto err; 329 } 330 t = 0; 331 ip6 = mtod(m, struct ip6_hdr *); 332 ip6_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 333 ECN_NOCARE, &t, &ip6->ip6_flow); 334 ecn = (ntohl(t) >> 20) & 0xff; 335 break; 336 #endif 337 case AF_LINK: 338 proto = IPPROTO_ETHERIP; 339 M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT); 340 if (m == NULL) { 341 error = ENOBUFS; 342 goto err; 343 } 344 eth = mtod(m, struct etherip_header *); 345 eth->eip_resvh = 0; 346 eth->eip_ver = ETHERIP_VERSION; 347 eth->eip_resvl = 0; 348 break; 349 default: 350 error = EAFNOSUPPORT; 351 m_freem(m); 352 goto err; 353 } 354 /* XXX should we check if our outer source is legal? */ 355 /* dispatch to output logic based on outer AF */ 356 switch (sc->gif_family) { 357 #ifdef INET 358 case AF_INET: 359 error = in_gif_output(ifp, m, proto, ecn); 360 break; 361 #endif 362 #ifdef INET6 363 case AF_INET6: 364 error = in6_gif_output(ifp, m, proto, ecn); 365 break; 366 #endif 367 default: 368 m_freem(m); 369 } 370 err: 371 if (error) 372 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 373 GIF_RUNLOCK(); 374 return (error); 375 } 376 377 static void 378 gif_qflush(struct ifnet *ifp __unused) 379 { 380 381 } 382 383 384 int 385 gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 386 struct route *ro) 387 { 388 uint32_t af; 389 390 if (dst->sa_family == AF_UNSPEC) 391 bcopy(dst->sa_data, &af, sizeof(af)); 392 else 393 af = dst->sa_family; 394 /* 395 * Now save the af in the inbound pkt csum data, this is a cheat since 396 * we are using the inbound csum_data field to carry the af over to 397 * the gif_transmit() routine, avoiding using yet another mtag. 398 */ 399 m->m_pkthdr.csum_data = af; 400 return (ifp->if_transmit(ifp, m)); 401 } 402 403 void 404 gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn) 405 { 406 struct etherip_header *eip; 407 #ifdef INET 408 struct ip *ip; 409 #endif 410 #ifdef INET6 411 struct ip6_hdr *ip6; 412 uint32_t t; 413 #endif 414 struct ether_header *eh; 415 struct ifnet *oldifp; 416 int isr, n, af; 417 418 NET_EPOCH_ASSERT(); 419 420 if (ifp == NULL) { 421 /* just in case */ 422 m_freem(m); 423 return; 424 } 425 m->m_pkthdr.rcvif = ifp; 426 m_clrprotoflags(m); 427 switch (proto) { 428 #ifdef INET 429 case IPPROTO_IPV4: 430 af = AF_INET; 431 if (m->m_len < sizeof(struct ip)) 432 m = m_pullup(m, sizeof(struct ip)); 433 if (m == NULL) 434 goto drop; 435 ip = mtod(m, struct ip *); 436 if (ip_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 437 ECN_NOCARE, &ecn, &ip->ip_tos) == 0) { 438 m_freem(m); 439 goto drop; 440 } 441 break; 442 #endif 443 #ifdef INET6 444 case IPPROTO_IPV6: 445 af = AF_INET6; 446 if (m->m_len < sizeof(struct ip6_hdr)) 447 m = m_pullup(m, sizeof(struct ip6_hdr)); 448 if (m == NULL) 449 goto drop; 450 t = htonl((uint32_t)ecn << 20); 451 ip6 = mtod(m, struct ip6_hdr *); 452 if (ip6_ecn_egress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED: 453 ECN_NOCARE, &t, &ip6->ip6_flow) == 0) { 454 m_freem(m); 455 goto drop; 456 } 457 break; 458 #endif 459 case IPPROTO_ETHERIP: 460 af = AF_LINK; 461 break; 462 default: 463 m_freem(m); 464 goto drop; 465 } 466 467 #ifdef MAC 468 mac_ifnet_create_mbuf(ifp, m); 469 #endif 470 471 if (bpf_peers_present(ifp->if_bpf)) { 472 uint32_t af1 = af; 473 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m); 474 } 475 476 if ((ifp->if_flags & IFF_MONITOR) != 0) { 477 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 478 if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 479 m_freem(m); 480 return; 481 } 482 483 if (ng_gif_input_p != NULL) { 484 (*ng_gif_input_p)(ifp, &m, af); 485 if (m == NULL) 486 goto drop; 487 } 488 489 /* 490 * Put the packet to the network layer input queue according to the 491 * specified address family. 492 * Note: older versions of gif_input directly called network layer 493 * input functions, e.g. ip6_input, here. We changed the policy to 494 * prevent too many recursive calls of such input functions, which 495 * might cause kernel panic. But the change may introduce another 496 * problem; if the input queue is full, packets are discarded. 497 * The kernel stack overflow really happened, and we believed 498 * queue-full rarely occurs, so we changed the policy. 499 */ 500 switch (af) { 501 #ifdef INET 502 case AF_INET: 503 isr = NETISR_IP; 504 break; 505 #endif 506 #ifdef INET6 507 case AF_INET6: 508 isr = NETISR_IPV6; 509 break; 510 #endif 511 case AF_LINK: 512 n = sizeof(struct etherip_header) + 513 sizeof(struct ether_header); 514 if (n > m->m_len) 515 m = m_pullup(m, n); 516 if (m == NULL) 517 goto drop; 518 eip = mtod(m, struct etherip_header *); 519 if (eip->eip_ver != ETHERIP_VERSION) { 520 /* discard unknown versions */ 521 m_freem(m); 522 goto drop; 523 } 524 m_adj(m, sizeof(struct etherip_header)); 525 526 m->m_flags &= ~(M_BCAST|M_MCAST); 527 m->m_pkthdr.rcvif = ifp; 528 529 if (ifp->if_bridge) { 530 oldifp = ifp; 531 eh = mtod(m, struct ether_header *); 532 if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 533 if (ETHER_IS_BROADCAST(eh->ether_dhost)) 534 m->m_flags |= M_BCAST; 535 else 536 m->m_flags |= M_MCAST; 537 if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 538 } 539 BRIDGE_INPUT(ifp, m); 540 541 if (m != NULL && ifp != oldifp) { 542 /* 543 * The bridge gave us back itself or one of the 544 * members for which the frame is addressed. 545 */ 546 ether_demux(ifp, m); 547 return; 548 } 549 } 550 if (m != NULL) 551 m_freem(m); 552 return; 553 554 default: 555 if (ng_gif_input_orphan_p != NULL) 556 (*ng_gif_input_orphan_p)(ifp, m, af); 557 else 558 m_freem(m); 559 return; 560 } 561 562 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 563 if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 564 M_SETFIB(m, ifp->if_fib); 565 netisr_dispatch(isr, m); 566 return; 567 drop: 568 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 569 } 570 571 static int 572 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 573 { 574 struct ifreq *ifr = (struct ifreq*)data; 575 struct gif_softc *sc; 576 u_int options; 577 int error; 578 579 switch (cmd) { 580 case SIOCSIFADDR: 581 ifp->if_flags |= IFF_UP; 582 case SIOCADDMULTI: 583 case SIOCDELMULTI: 584 case SIOCGIFMTU: 585 case SIOCSIFFLAGS: 586 return (0); 587 case SIOCSIFMTU: 588 if (ifr->ifr_mtu < GIF_MTU_MIN || 589 ifr->ifr_mtu > GIF_MTU_MAX) 590 return (EINVAL); 591 else 592 ifp->if_mtu = ifr->ifr_mtu; 593 return (0); 594 } 595 sx_xlock(&gif_ioctl_sx); 596 sc = ifp->if_softc; 597 if (sc == NULL) { 598 error = ENXIO; 599 goto bad; 600 } 601 error = 0; 602 switch (cmd) { 603 case SIOCDIFPHYADDR: 604 if (sc->gif_family == 0) 605 break; 606 gif_delete_tunnel(sc); 607 break; 608 #ifdef INET 609 case SIOCSIFPHYADDR: 610 case SIOCGIFPSRCADDR: 611 case SIOCGIFPDSTADDR: 612 error = in_gif_ioctl(sc, cmd, data); 613 break; 614 #endif 615 #ifdef INET6 616 case SIOCSIFPHYADDR_IN6: 617 case SIOCGIFPSRCADDR_IN6: 618 case SIOCGIFPDSTADDR_IN6: 619 error = in6_gif_ioctl(sc, cmd, data); 620 break; 621 #endif 622 case SIOCGTUNFIB: 623 ifr->ifr_fib = sc->gif_fibnum; 624 break; 625 case SIOCSTUNFIB: 626 if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 627 break; 628 if (ifr->ifr_fib >= rt_numfibs) 629 error = EINVAL; 630 else 631 sc->gif_fibnum = ifr->ifr_fib; 632 break; 633 case GIFGOPTS: 634 options = sc->gif_options; 635 error = copyout(&options, ifr_data_get_ptr(ifr), 636 sizeof(options)); 637 break; 638 case GIFSOPTS: 639 if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0) 640 break; 641 error = copyin(ifr_data_get_ptr(ifr), &options, 642 sizeof(options)); 643 if (error) 644 break; 645 if (options & ~GIF_OPTMASK) { 646 error = EINVAL; 647 break; 648 } 649 if (sc->gif_options != options) { 650 switch (sc->gif_family) { 651 #ifdef INET 652 case AF_INET: 653 error = in_gif_setopts(sc, options); 654 break; 655 #endif 656 #ifdef INET6 657 case AF_INET6: 658 error = in6_gif_setopts(sc, options); 659 break; 660 #endif 661 default: 662 /* No need to invoke AF-handler */ 663 sc->gif_options = options; 664 } 665 } 666 break; 667 default: 668 error = EINVAL; 669 break; 670 } 671 if (error == 0 && sc->gif_family != 0) { 672 if ( 673 #ifdef INET 674 cmd == SIOCSIFPHYADDR || 675 #endif 676 #ifdef INET6 677 cmd == SIOCSIFPHYADDR_IN6 || 678 #endif 679 0) { 680 if_link_state_change(ifp, LINK_STATE_UP); 681 } 682 } 683 bad: 684 sx_xunlock(&gif_ioctl_sx); 685 return (error); 686 } 687 688 static void 689 gif_delete_tunnel(struct gif_softc *sc) 690 { 691 692 sx_assert(&gif_ioctl_sx, SA_XLOCKED); 693 if (sc->gif_family != 0) { 694 CK_LIST_REMOVE(sc, srchash); 695 CK_LIST_REMOVE(sc, chain); 696 /* Wait until it become safe to free gif_hdr */ 697 GIF_WAIT(); 698 free(sc->gif_hdr, M_GIF); 699 } 700 sc->gif_family = 0; 701 GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 702 if_link_state_change(GIF2IFP(sc), LINK_STATE_DOWN); 703 } 704 705