1 /* $OpenBSD: if_etherip.c,v 1.29 2018/01/09 15:24:24 bluhm Exp $ */ 2 /* 3 * Copyright (c) 2015 Kazuya GODA <goda@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "bpfilter.h" 19 #include "pf.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/mbuf.h> 24 #include <sys/socket.h> 25 #include <sys/ioctl.h> 26 #include <sys/device.h> 27 #include <sys/sysctl.h> 28 29 #include <net/if.h> 30 #include <net/if_var.h> 31 #include <net/if_dl.h> 32 #include <net/if_media.h> 33 #include <net/rtable.h> 34 35 #include <netinet/in.h> 36 #include <netinet/ip.h> 37 #include <netinet/ip_var.h> 38 #include <netinet/if_ether.h> 39 #include <netinet/ip_ether.h> 40 41 #ifdef INET6 42 #include <netinet/ip6.h> 43 #include <netinet6/ip6_var.h> 44 #endif 45 46 #if NBPFILTER > 0 47 #include <net/bpf.h> 48 #endif 49 50 #if NPF > 0 51 #include <net/pfvar.h> 52 #endif 53 54 #include <net/if_etherip.h> 55 56 struct etherip_softc { 57 struct arpcom sc_ac; 58 struct ifmedia sc_media; 59 unsigned int sc_rdomain; 60 struct sockaddr_storage sc_src; 61 struct sockaddr_storage sc_dst; 62 LIST_ENTRY(etherip_softc) sc_entry; 63 }; 64 65 LIST_HEAD(, etherip_softc) etherip_softc_list; 66 67 /* 68 * We can control the acceptance of EtherIP packets by altering the sysctl 69 * net.inet.etherip.allow value. Zero means drop them, all else is acceptance. 70 */ 71 int etherip_allow = 0; 72 73 struct cpumem *etheripcounters; 74 75 void etheripattach(int); 76 int etherip_clone_create(struct if_clone *, int); 77 int etherip_clone_destroy(struct ifnet *); 78 int etherip_ioctl(struct ifnet *, u_long, caddr_t); 79 void etherip_start(struct ifnet *); 80 int etherip_media_change(struct ifnet *); 81 void etherip_media_status(struct ifnet *, struct ifmediareq *); 82 int etherip_set_tunnel_addr(struct ifnet *, struct sockaddr_storage *, 83 struct sockaddr_storage *); 84 85 struct if_clone etherip_cloner = IF_CLONE_INITIALIZER("etherip", 86 etherip_clone_create, etherip_clone_destroy); 87 88 89 void 90 etheripattach(int count) 91 { 92 if_clone_attach(ðerip_cloner); 93 etheripcounters = counters_alloc(etherips_ncounters); 94 } 95 96 int 97 etherip_clone_create(struct if_clone *ifc, int unit) 98 { 99 struct ifnet *ifp; 100 struct etherip_softc *sc; 101 102 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 103 ifp = &sc->sc_ac.ac_if; 104 snprintf(ifp->if_xname, sizeof ifp->if_xname, "etherip%d", unit); 105 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 106 ether_fakeaddr(ifp); 107 108 ifp->if_softc = sc; 109 ifp->if_ioctl = etherip_ioctl; 110 ifp->if_start = etherip_start; 111 ifp->if_xflags = IFXF_CLONED; 112 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 113 114 ifp->if_capabilities = IFCAP_VLAN_MTU; 115 116 ifmedia_init(&sc->sc_media, 0, etherip_media_change, 117 etherip_media_status); 118 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 119 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 120 121 if_attach(ifp); 122 ether_ifattach(ifp); 123 124 LIST_INSERT_HEAD(ðerip_softc_list, sc, sc_entry); 125 126 return 0; 127 } 128 129 int 130 etherip_clone_destroy(struct ifnet *ifp) 131 { 132 struct etherip_softc *sc = ifp->if_softc; 133 134 LIST_REMOVE(sc, sc_entry); 135 136 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 137 ether_ifdetach(ifp); 138 if_detach(ifp); 139 free(sc, M_DEVBUF, sizeof(*sc)); 140 141 return 0; 142 } 143 144 int 145 etherip_media_change(struct ifnet *ifp) 146 { 147 return 0; 148 } 149 150 void 151 etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr) 152 { 153 imr->ifm_active = IFM_ETHER | IFM_AUTO; 154 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 155 } 156 157 void 158 etherip_start(struct ifnet *ifp) 159 { 160 struct etherip_softc *sc = ifp->if_softc; 161 struct mbuf *m; 162 int error; 163 164 for (;;) { 165 IFQ_DEQUEUE(&ifp->if_snd, m); 166 if (m == NULL) 167 break; 168 169 #if NBPFILTER > 0 170 if (ifp->if_bpf) 171 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 172 #endif 173 if (sc->sc_src.ss_family == AF_UNSPEC || 174 sc->sc_dst.ss_family == AF_UNSPEC) { 175 m_freem(m); 176 continue; 177 } 178 179 switch (sc->sc_src.ss_family) { 180 case AF_INET: 181 error = ip_etherip_output(ifp, m); 182 break; 183 #ifdef INET6 184 case AF_INET6: 185 error = ip6_etherip_output(ifp, m); 186 break; 187 #endif 188 default: 189 unhandled_af(sc->sc_src.ss_family); 190 } 191 192 if (error) 193 ifp->if_oerrors++; 194 } 195 196 } 197 198 199 int 200 etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 201 { 202 struct etherip_softc *sc = ifp->if_softc; 203 struct if_laddrreq *lifr = (struct if_laddrreq *)data; 204 struct ifreq *ifr = (struct ifreq *)data; 205 struct sockaddr_storage *src, *dst; 206 struct proc *p = curproc; 207 int error = 0; 208 209 switch (cmd) { 210 case SIOCSIFADDR: 211 ifp->if_flags |= IFF_UP; 212 /* FALLTHROUGH */ 213 214 case SIOCSIFFLAGS: 215 if (ifp->if_flags & IFF_UP) 216 ifp->if_flags |= IFF_RUNNING; 217 else 218 ifp->if_flags &= ~IFF_RUNNING; 219 220 break; 221 222 case SIOCSLIFPHYRTABLE: 223 if ((error = suser(p, 0)) != 0) 224 break; 225 226 if (ifr->ifr_rdomainid < 0 || 227 ifr->ifr_rdomainid > RT_TABLEID_MAX || 228 !rtable_exists(ifr->ifr_rdomainid)) { 229 error = EINVAL; 230 break; 231 } 232 sc->sc_rdomain = ifr->ifr_rdomainid; 233 break; 234 235 case SIOCGLIFPHYRTABLE: 236 ifr->ifr_rdomainid = sc->sc_rdomain; 237 break; 238 239 case SIOCSLIFPHYADDR: 240 if ((error = suser(p, 0)) != 0) 241 break; 242 243 src = &lifr->addr; 244 dst = &lifr->dstaddr; 245 if (src->ss_family == AF_UNSPEC || dst->ss_family == AF_UNSPEC) 246 return EADDRNOTAVAIL; 247 248 switch (src->ss_family) { 249 case AF_INET: 250 if (src->ss_len != sizeof(struct sockaddr_in) || 251 dst->ss_len != sizeof(struct sockaddr_in)) 252 return EINVAL; 253 break; 254 #ifdef INET6 255 case AF_INET6: 256 if (src->ss_len != sizeof(struct sockaddr_in6) || 257 dst->ss_len != sizeof(struct sockaddr_in6)) 258 return EINVAL; 259 break; 260 #endif 261 default: 262 return EAFNOSUPPORT; 263 } 264 265 error = etherip_set_tunnel_addr(ifp, src, dst); 266 break; 267 268 case SIOCDIFPHYADDR: 269 if ((error = suser(p, 0)) != 0) 270 break; 271 272 ifp->if_flags &= ~IFF_RUNNING; 273 memset(&sc->sc_src, 0, sizeof(sc->sc_src)); 274 memset(&sc->sc_dst, 0, sizeof(sc->sc_dst)); 275 break; 276 277 case SIOCGLIFPHYADDR: 278 if (sc->sc_dst.ss_family == AF_UNSPEC) 279 return EADDRNOTAVAIL; 280 281 memset(&lifr->addr, 0, sizeof(lifr->addr)); 282 memset(&lifr->dstaddr, 0, sizeof(lifr->dstaddr)); 283 memcpy(&lifr->addr, &sc->sc_src, sc->sc_src.ss_len); 284 memcpy(&lifr->dstaddr, &sc->sc_dst, sc->sc_dst.ss_len); 285 286 break; 287 288 case SIOCSIFMEDIA: 289 case SIOCGIFMEDIA: 290 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 291 break; 292 293 default: 294 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 295 break; 296 } 297 298 return error; 299 } 300 301 int 302 etherip_set_tunnel_addr(struct ifnet *ifp, struct sockaddr_storage *src, 303 struct sockaddr_storage *dst) 304 { 305 struct etherip_softc *sc, *tsc; 306 int error = 0; 307 308 sc = ifp->if_softc; 309 310 LIST_FOREACH(tsc, ðerip_softc_list, sc_entry) { 311 if (tsc == sc) 312 continue; 313 314 if (tsc->sc_src.ss_family != src->ss_family || 315 tsc->sc_dst.ss_family != dst->ss_family || 316 tsc->sc_src.ss_len != src->ss_len || 317 tsc->sc_dst.ss_len != dst->ss_len) 318 continue; 319 320 if (tsc->sc_rdomain == sc->sc_rdomain && 321 memcmp(&tsc->sc_dst, dst, dst->ss_len) == 0 && 322 memcmp(&tsc->sc_src, src, src->ss_len) == 0) { 323 error = EADDRNOTAVAIL; 324 goto out; 325 } 326 } 327 328 memcpy(&sc->sc_src, src, src->ss_len); 329 memcpy(&sc->sc_dst, dst, dst->ss_len); 330 out: 331 return error; 332 } 333 334 int 335 ip_etherip_output(struct ifnet *ifp, struct mbuf *m) 336 { 337 struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc; 338 struct sockaddr_in *src, *dst; 339 struct etherip_header *eip; 340 struct ip *ip; 341 342 src = (struct sockaddr_in *)&sc->sc_src; 343 dst = (struct sockaddr_in *)&sc->sc_dst; 344 345 if (src == NULL || dst == NULL || 346 src->sin_family != AF_INET || dst->sin_family != AF_INET) { 347 m_freem(m); 348 return EAFNOSUPPORT; 349 } 350 if (dst->sin_addr.s_addr == INADDR_ANY) { 351 m_freem(m); 352 return ENETUNREACH; 353 } 354 355 /* 356 * Remove multicast and broadcast flags or encapsulated packet 357 * ends up as multicast or broadcast packet. 358 */ 359 m->m_flags &= ~(M_BCAST|M_MCAST); 360 361 M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT); 362 if (m == NULL) { 363 etheripstat_inc(etherips_adrops); 364 return ENOBUFS; 365 } 366 eip = mtod(m, struct etherip_header *); 367 eip->eip_ver = ETHERIP_VERSION; 368 eip->eip_res = 0; 369 eip->eip_pad = 0; 370 371 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 372 if (m == NULL) { 373 etheripstat_inc(etherips_adrops); 374 return ENOBUFS; 375 } 376 ip = mtod(m, struct ip *); 377 memset(ip, 0, sizeof(struct ip)); 378 379 ip->ip_v = IPVERSION; 380 ip->ip_hl = sizeof(struct ip) >> 2; 381 ip->ip_id = htons(ip_randomid()); 382 ip->ip_tos = IPTOS_LOWDELAY; 383 ip->ip_p = IPPROTO_ETHERIP; 384 ip->ip_len = htons(m->m_pkthdr.len); 385 ip->ip_ttl = IPDEFTTL; 386 ip->ip_src = src->sin_addr; 387 ip->ip_dst = dst->sin_addr; 388 389 m->m_pkthdr.ph_rtableid = sc->sc_rdomain; 390 391 #if NPF > 0 392 pf_pkt_addr_changed(m); 393 #endif 394 etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len - 395 (sizeof(struct ip) + sizeof(struct etherip_header))); 396 397 return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0); 398 } 399 400 int 401 ip_etherip_input(struct mbuf **mp, int *offp, int proto, int af) 402 { 403 struct mbuf *m = *mp; 404 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 405 struct etherip_softc *sc; 406 const struct ip *ip; 407 struct etherip_header *eip; 408 struct sockaddr_in *src, *dst; 409 struct ifnet *ifp = NULL; 410 411 ip = mtod(m, struct ip *); 412 413 if (ip->ip_p != IPPROTO_ETHERIP) { 414 m_freem(m); 415 ipstat_inc(ips_noproto); 416 return IPPROTO_DONE; 417 } 418 419 if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) { 420 m_freem(m); 421 etheripstat_inc(etherips_pdrops); 422 return IPPROTO_DONE; 423 } 424 425 NET_ASSERT_LOCKED(); 426 LIST_FOREACH(sc, ðerip_softc_list, sc_entry) { 427 if (sc->sc_src.ss_family != AF_INET || 428 sc->sc_dst.ss_family != AF_INET) 429 continue; 430 431 src = (struct sockaddr_in *)&sc->sc_src; 432 dst = (struct sockaddr_in *)&sc->sc_dst; 433 434 if (sc->sc_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid) || 435 src->sin_addr.s_addr != ip->ip_dst.s_addr || 436 dst->sin_addr.s_addr != ip->ip_src.s_addr) 437 continue; 438 439 ifp = &sc->sc_ac.ac_if; 440 break; 441 } 442 443 if (ifp == NULL) { 444 etheripstat_inc(etherips_noifdrops); 445 m_freem(m); 446 return IPPROTO_DONE; 447 } 448 449 m_adj(m, *offp); 450 m = *mp = m_pullup(m, sizeof(struct etherip_header)); 451 if (m == NULL) { 452 etheripstat_inc(etherips_adrops); 453 return IPPROTO_DONE; 454 } 455 456 eip = mtod(m, struct etherip_header *); 457 if (eip->eip_ver != ETHERIP_VERSION || eip->eip_pad) { 458 etheripstat_inc(etherips_adrops); 459 m_freem(m); 460 return IPPROTO_DONE; 461 } 462 463 etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len - 464 sizeof(struct etherip_header)); 465 466 m_adj(m, sizeof(struct etherip_header)); 467 m = *mp = m_pullup(m, sizeof(struct ether_header)); 468 if (m == NULL) { 469 etheripstat_inc(etherips_adrops); 470 return IPPROTO_DONE; 471 } 472 m->m_flags &= ~(M_BCAST|M_MCAST); 473 474 #if NPF > 0 475 pf_pkt_addr_changed(m); 476 #endif 477 478 ml_enqueue(&ml, m); 479 if_input(ifp, &ml); 480 return IPPROTO_DONE; 481 } 482 483 #ifdef INET6 484 int 485 ip6_etherip_output(struct ifnet *ifp, struct mbuf *m) 486 { 487 struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc; 488 struct sockaddr_in6 *src, *dst; 489 struct etherip_header *eip; 490 struct ip6_hdr *ip6; 491 int error; 492 493 src = (struct sockaddr_in6 *)&sc->sc_src; 494 dst = (struct sockaddr_in6 *)&sc->sc_dst; 495 496 if (src == NULL || dst == NULL || 497 src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6) { 498 error = EAFNOSUPPORT; 499 goto drop; 500 } 501 if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) { 502 error = ENETUNREACH; 503 goto drop; 504 } 505 506 /* 507 * Remove multicast and broadcast flags or encapsulated packet 508 * ends up as multicast or broadcast packet. 509 */ 510 m->m_flags &= ~(M_BCAST|M_MCAST); 511 512 M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT); 513 if (m == NULL) { 514 etheripstat_inc(etherips_adrops); 515 return ENOBUFS; 516 } 517 eip = mtod(m, struct etherip_header *); 518 eip->eip_ver = ETHERIP_VERSION; 519 eip->eip_res = 0; 520 eip->eip_pad = 0; 521 522 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 523 if (m == NULL) { 524 etheripstat_inc(etherips_adrops); 525 return ENOBUFS; 526 } 527 ip6 = mtod(m, struct ip6_hdr *); 528 ip6->ip6_flow = 0; 529 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 530 ip6->ip6_vfc |= IPV6_VERSION; 531 ip6->ip6_nxt = IPPROTO_ETHERIP; 532 ip6->ip6_hlim = ip6_defhlim; 533 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 534 error = in6_embedscope(&ip6->ip6_src, src, NULL); 535 if (error != 0) 536 goto drop; 537 error = in6_embedscope(&ip6->ip6_dst, dst, NULL); 538 if (error != 0) 539 goto drop; 540 541 m->m_pkthdr.ph_rtableid = sc->sc_rdomain; 542 543 #if NPF > 0 544 pf_pkt_addr_changed(m); 545 #endif 546 etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len - 547 (sizeof(struct ip6_hdr) + sizeof(struct etherip_header))); 548 549 return ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL); 550 551 drop: 552 m_freem(m); 553 return (error); 554 } 555 556 int 557 ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af) 558 { 559 struct mbuf *m = *mp; 560 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 561 struct etherip_softc *sc; 562 const struct ip6_hdr *ip6; 563 struct etherip_header *eip; 564 struct sockaddr_in6 ipsrc, ipdst; 565 struct sockaddr_in6 *src6, *dst6; 566 struct ifnet *ifp = NULL; 567 568 569 if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) { 570 m_freem(m); 571 etheripstat_inc(etherips_pdrops); 572 return IPPROTO_NONE; 573 } 574 575 ip6 = mtod(m, const struct ip6_hdr *); 576 in6_recoverscope(&ipsrc, &ip6->ip6_src); 577 in6_recoverscope(&ipdst, &ip6->ip6_dst); 578 579 NET_ASSERT_LOCKED(); 580 LIST_FOREACH(sc, ðerip_softc_list, sc_entry) { 581 if (sc->sc_src.ss_family != AF_INET6 || 582 sc->sc_dst.ss_family != AF_INET6) 583 continue; 584 585 src6 = (struct sockaddr_in6 *)&sc->sc_src; 586 dst6 = (struct sockaddr_in6 *)&sc->sc_dst; 587 588 if (IN6_ARE_ADDR_EQUAL(&src6->sin6_addr, &ipdst.sin6_addr) && 589 src6->sin6_scope_id == ipdst.sin6_scope_id && 590 IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ipsrc.sin6_addr) && 591 dst6->sin6_scope_id == ipsrc.sin6_scope_id) { 592 ifp = &sc->sc_ac.ac_if; 593 break; 594 } 595 } 596 597 if (ifp == NULL) { 598 etheripstat_inc(etherips_noifdrops); 599 m_freem(m); 600 return IPPROTO_DONE; 601 } 602 603 m_adj(m, *offp); 604 m = *mp = m_pullup(m, sizeof(struct etherip_header)); 605 if (m == NULL) { 606 etheripstat_inc(etherips_adrops); 607 return IPPROTO_DONE; 608 } 609 610 eip = mtod(m, struct etherip_header *); 611 if ((eip->eip_ver != ETHERIP_VERSION) || eip->eip_pad) { 612 etheripstat_inc(etherips_adrops); 613 m_freem(m); 614 return IPPROTO_DONE; 615 } 616 etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len - 617 sizeof(struct etherip_header)); 618 619 m_adj(m, sizeof(struct etherip_header)); 620 m = *mp = m_pullup(m, sizeof(struct ether_header)); 621 if (m == NULL) { 622 etheripstat_inc(etherips_adrops); 623 return IPPROTO_DONE; 624 } 625 626 m->m_flags &= ~(M_BCAST|M_MCAST); 627 628 #if NPF > 0 629 pf_pkt_addr_changed(m); 630 #endif 631 632 ml_enqueue(&ml, m); 633 if_input(ifp, &ml); 634 return IPPROTO_DONE; 635 } 636 #endif /* INET6 */ 637 638 int 639 etherip_sysctl_etheripstat(void *oldp, size_t *oldlenp, void *newp) 640 { 641 struct etheripstat etheripstat; 642 643 CTASSERT(sizeof(etheripstat) == (etherips_ncounters * 644 sizeof(uint64_t))); 645 memset(ðeripstat, 0, sizeof etheripstat); 646 counters_read(etheripcounters, (uint64_t *)ðeripstat, 647 etherips_ncounters); 648 return (sysctl_rdstruct(oldp, oldlenp, newp, ðeripstat, 649 sizeof(etheripstat))); 650 } 651 652 int 653 etherip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 654 void *newp, size_t newlen) 655 { 656 int error; 657 658 /* All sysctl names at this level are terminal. */ 659 if (namelen != 1) 660 return ENOTDIR; 661 662 switch (name[0]) { 663 case ETHERIPCTL_ALLOW: 664 NET_LOCK(); 665 error = sysctl_int(oldp, oldlenp, newp, newlen, ðerip_allow); 666 NET_UNLOCK(); 667 return (error); 668 case ETHERIPCTL_STATS: 669 return (etherip_sysctl_etheripstat(oldp, oldlenp, newp)); 670 default: 671 break; 672 } 673 674 return ENOPROTOOPT; 675 } 676