1 /* $OpenBSD: if_etherip.c,v 1.37 2018/02/19 00:29:29 dlg 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 #include <sys/tree.h> 29 30 #include <net/if.h> 31 #include <net/if_var.h> 32 #include <net/if_dl.h> 33 #include <net/if_media.h> 34 #include <net/rtable.h> 35 36 #include <netinet/in.h> 37 #include <netinet/ip.h> 38 #include <netinet/ip_var.h> 39 #include <netinet/if_ether.h> 40 #include <netinet/ip_ether.h> 41 42 #ifdef INET6 43 #include <netinet/ip6.h> 44 #include <netinet6/ip6_var.h> 45 #endif 46 47 #if NBPFILTER > 0 48 #include <net/bpf.h> 49 #endif 50 51 #if NPF > 0 52 #include <net/pfvar.h> 53 #endif 54 55 #include <net/if_etherip.h> 56 57 union etherip_addr { 58 struct in_addr in4; 59 struct in6_addr in6; 60 }; 61 62 struct etherip_tunnel { 63 union etherip_addr 64 _t_src; 65 #define t_src4 _t_src.in4 66 #define t_src6 _t_src.in6 67 union etherip_addr 68 _t_dst; 69 #define t_dst4 _t_dst.in4 70 #define t_dst6 _t_dst.in6 71 72 unsigned int t_rtableid; 73 sa_family_t t_af; 74 75 TAILQ_ENTRY(etherip_tunnel) 76 t_entry; 77 }; 78 79 TAILQ_HEAD(etherip_list, etherip_tunnel); 80 81 static inline int etherip_cmp(const struct etherip_tunnel *, 82 const struct etherip_tunnel *); 83 84 struct etherip_softc { 85 struct etherip_tunnel sc_tunnel; /* must be first */ 86 struct arpcom sc_ac; 87 struct ifmedia sc_media; 88 uint16_t sc_df; 89 uint8_t sc_ttl; 90 }; 91 92 /* 93 * We can control the acceptance of EtherIP packets by altering the sysctl 94 * net.inet.etherip.allow value. Zero means drop them, all else is acceptance. 95 */ 96 int etherip_allow = 0; 97 98 struct cpumem *etheripcounters; 99 100 void etheripattach(int); 101 int etherip_clone_create(struct if_clone *, int); 102 int etherip_clone_destroy(struct ifnet *); 103 int etherip_ioctl(struct ifnet *, u_long, caddr_t); 104 void etherip_start(struct ifnet *); 105 int etherip_media_change(struct ifnet *); 106 void etherip_media_status(struct ifnet *, struct ifmediareq *); 107 int etherip_set_tunnel(struct etherip_softc *, struct if_laddrreq *); 108 int etherip_get_tunnel(struct etherip_softc *, struct if_laddrreq *); 109 int etherip_del_tunnel(struct etherip_softc *); 110 int etherip_up(struct etherip_softc *); 111 int etherip_down(struct etherip_softc *); 112 struct etherip_softc *etherip_find(const struct etherip_tunnel *); 113 int etherip_input(struct etherip_tunnel *, struct mbuf *, int); 114 115 struct if_clone etherip_cloner = IF_CLONE_INITIALIZER("etherip", 116 etherip_clone_create, etherip_clone_destroy); 117 118 struct etherip_list etherip_list = TAILQ_HEAD_INITIALIZER(etherip_list); 119 120 void 121 etheripattach(int count) 122 { 123 if_clone_attach(ðerip_cloner); 124 etheripcounters = counters_alloc(etherips_ncounters); 125 } 126 127 int 128 etherip_clone_create(struct if_clone *ifc, int unit) 129 { 130 struct ifnet *ifp; 131 struct etherip_softc *sc; 132 133 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 134 ifp = &sc->sc_ac.ac_if; 135 136 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 137 ifc->ifc_name, unit); 138 139 sc->sc_ttl = ip_defttl; 140 sc->sc_df = htons(0); 141 142 ifp->if_softc = sc; 143 ifp->if_ioctl = etherip_ioctl; 144 ifp->if_start = etherip_start; 145 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 146 ifp->if_xflags = IFXF_CLONED; 147 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 148 ifp->if_capabilities = IFCAP_VLAN_MTU; 149 ether_fakeaddr(ifp); 150 151 ifmedia_init(&sc->sc_media, 0, etherip_media_change, 152 etherip_media_status); 153 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 154 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 155 156 if_attach(ifp); 157 ether_ifattach(ifp); 158 159 NET_LOCK(); 160 TAILQ_INSERT_TAIL(ðerip_list, &sc->sc_tunnel, t_entry); 161 NET_UNLOCK(); 162 163 return (0); 164 } 165 166 int 167 etherip_clone_destroy(struct ifnet *ifp) 168 { 169 struct etherip_softc *sc = ifp->if_softc; 170 171 NET_LOCK(); 172 if (ISSET(ifp->if_flags, IFF_RUNNING)) 173 etherip_down(sc); 174 175 TAILQ_REMOVE(ðerip_list, &sc->sc_tunnel, t_entry); 176 NET_UNLOCK(); 177 178 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 179 ether_ifdetach(ifp); 180 if_detach(ifp); 181 182 free(sc, M_DEVBUF, sizeof(*sc)); 183 184 return (0); 185 } 186 187 int 188 etherip_media_change(struct ifnet *ifp) 189 { 190 return 0; 191 } 192 193 void 194 etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr) 195 { 196 imr->ifm_active = IFM_ETHER | IFM_AUTO; 197 imr->ifm_status = IFM_AVALID | IFM_ACTIVE; 198 } 199 200 void 201 etherip_start(struct ifnet *ifp) 202 { 203 struct etherip_softc *sc = ifp->if_softc; 204 struct mbuf *m; 205 int error; 206 #if NBPFILTER > 0 207 caddr_t if_bpf; 208 #endif 209 210 while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { 211 #if NBPFILTER > 0 212 if_bpf = ifp->if_bpf; 213 if (if_bpf) 214 bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT); 215 #endif 216 217 switch (sc->sc_tunnel.t_af) { 218 case AF_INET: 219 error = ip_etherip_output(ifp, m); 220 break; 221 #ifdef INET6 222 case AF_INET6: 223 error = ip6_etherip_output(ifp, m); 224 break; 225 #endif 226 default: 227 /* unhandled_af(sc->sc_tunnel.t_af); */ 228 m_freem(m); 229 continue; 230 } 231 232 if (error) 233 ifp->if_oerrors++; 234 } 235 } 236 237 int 238 etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 239 { 240 struct etherip_softc *sc = ifp->if_softc; 241 struct ifreq *ifr = (struct ifreq *)data; 242 int error = 0; 243 244 switch (cmd) { 245 case SIOCSIFADDR: 246 ifp->if_flags |= IFF_UP; 247 /* FALLTHROUGH */ 248 249 case SIOCSIFFLAGS: 250 if (ISSET(ifp->if_flags, IFF_UP)) { 251 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 252 error = etherip_up(sc); 253 else 254 error = 0; 255 } else { 256 if (ISSET(ifp->if_flags, IFF_RUNNING)) 257 error = etherip_down(sc); 258 } 259 break; 260 261 case SIOCSLIFPHYRTABLE: 262 if (ifr->ifr_rdomainid < 0 || 263 ifr->ifr_rdomainid > RT_TABLEID_MAX || 264 !rtable_exists(ifr->ifr_rdomainid)) { 265 error = EINVAL; 266 break; 267 } 268 sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid; 269 break; 270 271 case SIOCGLIFPHYRTABLE: 272 ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid; 273 break; 274 275 case SIOCSLIFPHYADDR: 276 error = etherip_set_tunnel(sc, (struct if_laddrreq *)data); 277 break; 278 case SIOCGLIFPHYADDR: 279 error = etherip_get_tunnel(sc, (struct if_laddrreq *)data); 280 break; 281 case SIOCDIFPHYADDR: 282 error = etherip_del_tunnel(sc); 283 break; 284 285 case SIOCSLIFPHYTTL: 286 if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) { 287 error = EINVAL; 288 break; 289 } 290 291 /* commit */ 292 sc->sc_ttl = (uint8_t)ifr->ifr_ttl; 293 break; 294 case SIOCGLIFPHYTTL: 295 ifr->ifr_ttl = (int)sc->sc_ttl; 296 break; 297 298 case SIOCSLIFPHYDF: 299 /* commit */ 300 sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0); 301 break; 302 case SIOCGLIFPHYDF: 303 ifr->ifr_df = sc->sc_df ? 1 : 0; 304 break; 305 306 case SIOCSIFMEDIA: 307 case SIOCGIFMEDIA: 308 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 309 break; 310 311 default: 312 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 313 break; 314 } 315 316 return (error); 317 } 318 319 int 320 etherip_set_tunnel(struct etherip_softc *sc, struct if_laddrreq *req) 321 { 322 struct sockaddr *src = (struct sockaddr *)&req->addr; 323 struct sockaddr *dst = (struct sockaddr *)&req->dstaddr; 324 struct sockaddr_in *src4, *dst4; 325 #ifdef INET6 326 struct sockaddr_in6 *src6, *dst6; 327 int error; 328 #endif 329 330 /* sa_family and sa_len must be equal */ 331 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len) 332 return (EINVAL); 333 334 /* validate */ 335 switch (dst->sa_family) { 336 case AF_INET: 337 if (dst->sa_len != sizeof(*dst4)) 338 return (EINVAL); 339 340 src4 = (struct sockaddr_in *)src; 341 if (in_nullhost(src4->sin_addr) || 342 IN_MULTICAST(src4->sin_addr.s_addr)) 343 return (EINVAL); 344 345 dst4 = (struct sockaddr_in *)dst; 346 if (in_nullhost(dst4->sin_addr) || 347 IN_MULTICAST(dst4->sin_addr.s_addr)) 348 return (EINVAL); 349 350 sc->sc_tunnel.t_src4 = src4->sin_addr; 351 sc->sc_tunnel.t_dst4 = dst4->sin_addr; 352 break; 353 #ifdef INET6 354 case AF_INET6: 355 if (dst->sa_len != sizeof(*dst6)) 356 return (EINVAL); 357 358 src6 = (struct sockaddr_in6 *)src; 359 if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) || 360 IN6_IS_ADDR_MULTICAST(&src6->sin6_addr)) 361 return (EINVAL); 362 363 dst6 = (struct sockaddr_in6 *)dst; 364 if (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) || 365 IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr)) 366 return (EINVAL); 367 368 error = in6_embedscope(&sc->sc_tunnel.t_src6, src6, NULL); 369 if (error != 0) 370 return (error); 371 372 error = in6_embedscope(&sc->sc_tunnel.t_dst6, dst6, NULL); 373 if (error != 0) 374 return (error); 375 376 break; 377 #endif 378 default: 379 return (EAFNOSUPPORT); 380 } 381 382 /* commit */ 383 sc->sc_tunnel.t_af = dst->sa_family; 384 385 return (0); 386 } 387 388 int 389 etherip_get_tunnel(struct etherip_softc *sc, struct if_laddrreq *req) 390 { 391 struct sockaddr *src = (struct sockaddr *)&req->addr; 392 struct sockaddr *dst = (struct sockaddr *)&req->dstaddr; 393 struct sockaddr_in *sin; 394 #ifdef INET6 /* ifconfig already embeds the scopeid */ 395 struct sockaddr_in6 *sin6; 396 #endif 397 398 switch (sc->sc_tunnel.t_af) { 399 case AF_UNSPEC: 400 return (EADDRNOTAVAIL); 401 case AF_INET: 402 sin = (struct sockaddr_in *)src; 403 memset(sin, 0, sizeof(*sin)); 404 sin->sin_family = AF_INET; 405 sin->sin_len = sizeof(*sin); 406 sin->sin_addr = sc->sc_tunnel.t_src4; 407 408 sin = (struct sockaddr_in *)dst; 409 memset(sin, 0, sizeof(*sin)); 410 sin->sin_family = AF_INET; 411 sin->sin_len = sizeof(*sin); 412 sin->sin_addr = sc->sc_tunnel.t_dst4; 413 414 break; 415 #ifdef INET6 416 case AF_INET6: 417 sin6 = (struct sockaddr_in6 *)src; 418 memset(sin6, 0, sizeof(*sin6)); 419 sin6->sin6_family = AF_INET6; 420 sin6->sin6_len = sizeof(*sin6); 421 in6_recoverscope(sin6, &sc->sc_tunnel.t_src6); 422 423 sin6 = (struct sockaddr_in6 *)dst; 424 memset(sin6, 0, sizeof(*sin6)); 425 sin6->sin6_family = AF_INET6; 426 sin6->sin6_len = sizeof(*sin6); 427 in6_recoverscope(sin6, &sc->sc_tunnel.t_dst6); 428 429 break; 430 #endif 431 default: 432 return (EAFNOSUPPORT); 433 } 434 435 return (0); 436 } 437 438 int 439 etherip_del_tunnel(struct etherip_softc *sc) 440 { 441 /* commit */ 442 sc->sc_tunnel.t_af = AF_UNSPEC; 443 444 return (0); 445 } 446 447 int 448 etherip_up(struct etherip_softc *sc) 449 { 450 struct ifnet *ifp = &sc->sc_ac.ac_if; 451 452 NET_ASSERT_LOCKED(); 453 454 SET(ifp->if_flags, IFF_RUNNING); 455 456 return (0); 457 } 458 459 int 460 etherip_down(struct etherip_softc *sc) 461 { 462 struct ifnet *ifp = &sc->sc_ac.ac_if; 463 464 NET_ASSERT_LOCKED(); 465 466 CLR(ifp->if_flags, IFF_RUNNING); 467 468 return (0); 469 } 470 471 int 472 ip_etherip_output(struct ifnet *ifp, struct mbuf *m) 473 { 474 struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc; 475 struct etherip_header *eip; 476 struct ip *ip; 477 478 M_PREPEND(m, sizeof(*ip) + sizeof(*eip), M_DONTWAIT); 479 if (m == NULL) { 480 etheripstat_inc(etherips_adrops); 481 return ENOBUFS; 482 } 483 484 ip = mtod(m, struct ip *); 485 memset(ip, 0, sizeof(struct ip)); 486 487 ip->ip_v = IPVERSION; 488 ip->ip_hl = sizeof(*ip) >> 2; 489 ip->ip_tos = IPTOS_LOWDELAY; 490 ip->ip_len = htons(m->m_pkthdr.len); 491 ip->ip_id = htons(ip_randomid()); 492 ip->ip_off = sc->sc_df; 493 ip->ip_ttl = sc->sc_ttl; 494 ip->ip_p = IPPROTO_ETHERIP; 495 ip->ip_src = sc->sc_tunnel.t_src4; 496 ip->ip_dst = sc->sc_tunnel.t_dst4; 497 498 eip = (struct etherip_header *)(ip + 1); 499 eip->eip_ver = ETHERIP_VERSION; 500 eip->eip_res = 0; 501 eip->eip_pad = 0; 502 503 m->m_flags &= ~(M_BCAST|M_MCAST); 504 m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid; 505 506 #if NPF > 0 507 pf_pkt_addr_changed(m); 508 #endif 509 etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len - 510 (sizeof(struct ip) + sizeof(struct etherip_header))); 511 512 ip_send(m); 513 514 return (0); 515 } 516 517 int 518 ip_etherip_input(struct mbuf **mp, int *offp, int type, int af) 519 { 520 struct mbuf *m = *mp; 521 struct etherip_tunnel key; 522 struct ip *ip; 523 524 ip = mtod(m, struct ip *); 525 526 key.t_af = AF_INET; 527 key.t_src4 = ip->ip_dst; 528 key.t_dst4 = ip->ip_src; 529 530 return (etherip_input(&key, m, *offp)); 531 } 532 533 struct etherip_softc * 534 etherip_find(const struct etherip_tunnel *key) 535 { 536 struct etherip_tunnel *t; 537 struct etherip_softc *sc; 538 539 TAILQ_FOREACH(t, ðerip_list, t_entry) { 540 if (etherip_cmp(key, t) != 0) 541 continue; 542 543 sc = (struct etherip_softc *)t; 544 if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING)) 545 continue; 546 547 return (sc); 548 } 549 550 return (NULL); 551 } 552 553 int 554 etherip_input(struct etherip_tunnel *key, struct mbuf *m, int hlen) 555 { 556 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 557 struct etherip_softc *sc; 558 struct ifnet *ifp; 559 struct etherip_header *eip; 560 561 if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) { 562 etheripstat_inc(etherips_pdrops); 563 goto drop; 564 } 565 566 key->t_rtableid = m->m_pkthdr.ph_rtableid; 567 568 NET_ASSERT_LOCKED(); 569 sc = etherip_find(key); 570 if (sc == NULL) { 571 etheripstat_inc(etherips_noifdrops); 572 goto drop; 573 } 574 575 m_adj(m, hlen); 576 m = m_pullup(m, sizeof(*eip)); 577 if (m == NULL) { 578 etheripstat_inc(etherips_adrops); 579 return IPPROTO_DONE; 580 } 581 582 eip = mtod(m, struct etherip_header *); 583 if (eip->eip_ver != ETHERIP_VERSION || eip->eip_pad) { 584 etheripstat_inc(etherips_adrops); 585 goto drop; 586 } 587 588 m_adj(m, sizeof(struct etherip_header)); 589 590 etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len); 591 592 m = m_pullup(m, sizeof(struct ether_header)); 593 if (m == NULL) { 594 etheripstat_inc(etherips_adrops); 595 return IPPROTO_DONE; 596 } 597 598 ifp = &sc->sc_ac.ac_if; 599 600 m->m_flags &= ~(M_BCAST|M_MCAST); 601 m->m_pkthdr.ph_ifidx = ifp->if_index; 602 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 603 604 #if NPF > 0 605 pf_pkt_addr_changed(m); 606 #endif 607 608 ml_enqueue(&ml, m); 609 if_input(ifp, &ml); 610 return IPPROTO_DONE; 611 612 drop: 613 m_freem(m); 614 return (IPPROTO_DONE); 615 } 616 617 #ifdef INET6 618 int 619 ip6_etherip_output(struct ifnet *ifp, struct mbuf *m) 620 { 621 struct etherip_softc *sc = ifp->if_softc; 622 struct ip6_hdr *ip6; 623 struct etherip_header *eip; 624 uint16_t len; 625 626 if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6)) { 627 m_freem(m); 628 return (ENETUNREACH); 629 } 630 631 len = m->m_pkthdr.len; 632 633 M_PREPEND(m, sizeof(*ip6) + sizeof(*eip), M_DONTWAIT); 634 if (m == NULL) { 635 etheripstat_inc(etherips_adrops); 636 return ENOBUFS; 637 } 638 639 ip6 = mtod(m, struct ip6_hdr *); 640 ip6->ip6_flow = 0; 641 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 642 ip6->ip6_vfc |= IPV6_VERSION; 643 ip6->ip6_nxt = IPPROTO_ETHERIP; 644 ip6->ip6_hlim = ip6_defhlim; 645 ip6->ip6_plen = htons(len); 646 memcpy(&ip6->ip6_src, &sc->sc_tunnel.t_src6, sizeof(ip6->ip6_src)); 647 memcpy(&ip6->ip6_dst, &sc->sc_tunnel.t_dst6, sizeof(ip6->ip6_dst)); 648 649 eip = (struct etherip_header *)(ip6 + 1); 650 eip->eip_ver = ETHERIP_VERSION; 651 eip->eip_res = 0; 652 eip->eip_pad = 0; 653 654 if (sc->sc_df) 655 SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT); 656 657 m->m_flags &= ~(M_BCAST|M_MCAST); 658 m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid; 659 660 #if NPF > 0 661 pf_pkt_addr_changed(m); 662 #endif 663 664 etheripstat_pkt(etherips_opackets, etherips_obytes, len); 665 666 ip6_send(m); 667 return (0); 668 } 669 670 int 671 ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af) 672 { 673 struct mbuf *m = *mp; 674 struct etherip_tunnel key; 675 const struct ip6_hdr *ip6; 676 677 ip6 = mtod(m, const struct ip6_hdr *); 678 679 key.t_af = AF_INET6; 680 key.t_src6 = ip6->ip6_dst; 681 key.t_dst6 = ip6->ip6_src; 682 683 return (etherip_input(&key, m, *offp)); 684 } 685 #endif /* INET6 */ 686 687 int 688 etherip_sysctl_etheripstat(void *oldp, size_t *oldlenp, void *newp) 689 { 690 struct etheripstat etheripstat; 691 692 CTASSERT(sizeof(etheripstat) == (etherips_ncounters * 693 sizeof(uint64_t))); 694 memset(ðeripstat, 0, sizeof etheripstat); 695 counters_read(etheripcounters, (uint64_t *)ðeripstat, 696 etherips_ncounters); 697 return (sysctl_rdstruct(oldp, oldlenp, newp, ðeripstat, 698 sizeof(etheripstat))); 699 } 700 701 int 702 etherip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 703 void *newp, size_t newlen) 704 { 705 int error; 706 707 /* All sysctl names at this level are terminal. */ 708 if (namelen != 1) 709 return ENOTDIR; 710 711 switch (name[0]) { 712 case ETHERIPCTL_ALLOW: 713 NET_LOCK(); 714 error = sysctl_int(oldp, oldlenp, newp, newlen, ðerip_allow); 715 NET_UNLOCK(); 716 return (error); 717 case ETHERIPCTL_STATS: 718 return (etherip_sysctl_etheripstat(oldp, oldlenp, newp)); 719 default: 720 break; 721 } 722 723 return ENOPROTOOPT; 724 } 725 726 static inline int 727 etherip_ip_cmp(int af, const union etherip_addr *a, const union etherip_addr *b) 728 { 729 switch (af) { 730 #ifdef INET6 731 case AF_INET6: 732 return (memcmp(&a->in6, &b->in6, sizeof(a->in6))); 733 /* FALLTHROUGH */ 734 #endif /* INET6 */ 735 case AF_INET: 736 return (memcmp(&a->in4, &b->in4, sizeof(a->in4))); 737 break; 738 default: 739 panic("%s: unsupported af %d\n", __func__, af); 740 } 741 742 return (0); 743 } 744 745 static inline int 746 etherip_cmp(const struct etherip_tunnel *a, const struct etherip_tunnel *b) 747 { 748 int rv; 749 750 if (a->t_rtableid > b->t_rtableid) 751 return (1); 752 if (a->t_rtableid < b->t_rtableid) 753 return (-1); 754 755 /* sort by address */ 756 if (a->t_af > b->t_af) 757 return (1); 758 if (a->t_af < b->t_af) 759 return (-1); 760 761 rv = etherip_ip_cmp(a->t_af, &a->_t_dst, &b->_t_dst); 762 if (rv != 0) 763 return (rv); 764 765 rv = etherip_ip_cmp(a->t_af, &a->_t_src, &b->_t_src); 766 if (rv != 0) 767 return (rv); 768 769 return (0); 770 } 771