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