1/* $NetBSD: if_etherip.c,v 1.30 2010/05/19 20:41:59 christos Exp $ */ 2 3/* 4 * Copyright (c) 2006, Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Hans Rosenfeld nor the names of his 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * 32 * Copyright (c) 2003, 2004, 2008 The NetBSD Foundation. 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of The NetBSD Foundation nor the names of its 44 * contributors may be used to endorse or promote products derived 45 * from this software without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 48 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 49 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 51 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57 * POSSIBILITY OF SUCH DAMAGE. 58 * 59 * 60 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 61 * All rights reserved. 62 * 63 * Redistribution and use in source and binary forms, with or without 64 * modification, are permitted provided that the following conditions 65 * are met: 66 * 1. Redistributions of source code must retain the above copyright 67 * notice, this list of conditions and the following disclaimer. 68 * 2. Redistributions in binary form must reproduce the above copyright 69 * notice, this list of conditions and the following disclaimer in the 70 * documentation and/or other materials provided with the distribution. 71 * 3. Neither the name of the project nor the names of its contributors 72 * may be used to endorse or promote products derived from this software 73 * without specific prior written permission. 74 * 75 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 76 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 77 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 78 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 79 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 80 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 81 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 82 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 83 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 84 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 85 * SUCH DAMAGE. 86 */ 87 88#include <sys/cdefs.h> 89__KERNEL_RCSID(0, "$NetBSD: if_etherip.c,v 1.30 2010/05/19 20:41:59 christos Exp $"); 90 91#include "opt_inet.h" 92 93#include <sys/param.h> 94#include <sys/systm.h> 95#include <sys/kernel.h> 96#include <sys/malloc.h> 97#include <sys/conf.h> 98#include <sys/device.h> 99#include <sys/errno.h> 100#include <sys/time.h> 101#include <sys/sysctl.h> 102#include <sys/queue.h> 103#include <sys/socket.h> 104#include <sys/socketvar.h> 105#include <sys/intr.h> 106 107#include <net/if.h> 108#include <net/if_dl.h> 109#include <net/if_ether.h> 110#include <net/if_media.h> 111#include <net/route.h> 112#include <net/if_etherip.h> 113#include <net/bpf.h> 114 115#include <netinet/in.h> 116#include <netinet/in_systm.h> 117#include <netinet/ip.h> 118#ifdef INET 119#include <netinet/in_var.h> 120#endif /* INET */ 121#include <netinet/ip_etherip.h> 122 123#ifdef INET6 124#include <netinet6/ip6_etherip.h> 125#ifndef INET 126#include <netinet/in.h> 127#endif 128#include <netinet6/in6_var.h> 129#include <netinet/ip6.h> 130#include <netinet6/ip6_var.h> 131#include <netinet6/in6_gif.h> 132#include <netinet6/ip6protosw.h> 133#endif /* INET6 */ 134 135#include <compat/sys/sockio.h> 136 137static int etherip_node; 138static int etherip_sysctl_handler(SYSCTLFN_PROTO); 139SYSCTL_SETUP_PROTO(sysctl_etherip_setup); 140 141void etheripattach(int); 142 143static int etherip_match(device_t, cfdata_t, void *); 144static void etherip_attach(device_t, device_t, void *); 145static int etherip_detach(device_t, int); 146 147CFATTACH_DECL_NEW(etherip, sizeof(struct etherip_softc), 148 etherip_match, etherip_attach, etherip_detach, NULL); 149extern struct cfdriver etherip_cd; 150 151static void etherip_start(struct ifnet *); 152static void etherip_stop(struct ifnet *, int); 153static int etherip_init(struct ifnet *); 154static int etherip_ioctl(struct ifnet *, u_long, void *); 155 156static int etherip_mediachange(struct ifnet *); 157static void etherip_mediastatus(struct ifnet *, struct ifmediareq *); 158 159static int etherip_clone_create(struct if_clone *, int); 160static int etherip_clone_destroy(struct ifnet *); 161 162static struct if_clone etherip_cloners = IF_CLONE_INITIALIZER( 163 "etherip", etherip_clone_create, etherip_clone_destroy); 164 165static int etherip_set_tunnel(struct ifnet *, 166 struct sockaddr *, struct sockaddr *); 167static void etherip_delete_tunnel(struct ifnet *); 168static void etheripintr(void *); 169 170void 171etheripattach(int count) 172{ 173 int error; 174 175 error = config_cfattach_attach(etherip_cd.cd_name, ðerip_ca); 176 177 if (error) { 178 aprint_error("%s: unable to register cfattach\n", 179 etherip_cd.cd_name); 180 (void)config_cfdriver_detach(ðerip_cd); 181 return; 182 } 183 184 LIST_INIT(ðerip_softc_list); 185 if_clone_attach(ðerip_cloners); 186} 187 188/* Pretty much useless for a pseudo-device */ 189static int 190etherip_match(device_t self, cfdata_t cfdata, void *arg) 191{ 192 return 1; 193} 194 195static void 196etherip_attach(device_t parent, device_t self, void *aux) 197{ 198 struct etherip_softc *sc = device_private(self); 199 struct ifnet *ifp; 200 const struct sysctlnode *node; 201 uint8_t enaddr[ETHER_ADDR_LEN] = 202 { 0xf2, 0x0b, 0xa5, 0xff, 0xff, 0xff }; 203 char enaddrstr[3 * ETHER_ADDR_LEN]; 204 struct timeval tv; 205 uint32_t ui; 206 int error; 207 208 sc->sc_dev = self; 209 sc->sc_si = NULL; 210 sc->sc_src = NULL; 211 sc->sc_dst = NULL; 212 213 if (!pmf_device_register(self, NULL, NULL)) 214 aprint_error_dev(self, "couldn't establish power handler\n"); 215 216 /* 217 * In order to obtain unique initial Ethernet address on a host, 218 * do some randomisation using the current uptime. It's not meant 219 * for anything but avoiding hard-coding an address. 220 */ 221 getmicrouptime(&tv); 222 ui = (tv.tv_sec ^ tv.tv_usec) & 0xffffff; 223 memcpy(enaddr+3, (uint8_t *)&ui, 3); 224 225 aprint_verbose_dev(self, "Ethernet address %s\n", 226 ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr)); 227 228 /* 229 * Why 1000baseT? Why not? You can add more. 230 * 231 * Note that there are 3 steps: init, one or several additions to 232 * list of supported media, and in the end, the selection of one 233 * of them. 234 */ 235 ifmedia_init(&sc->sc_im, 0, etherip_mediachange, etherip_mediastatus); 236 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T, 0, NULL); 237 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL); 238 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX, 0, NULL); 239 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 240 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T, 0, NULL); 241 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 242 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_AUTO, 0, NULL); 243 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_AUTO); 244 245 /* 246 * One should note that an interface must do multicast in order 247 * to support IPv6. 248 */ 249 ifp = &sc->sc_ec.ec_if; 250 strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 251 ifp->if_softc = sc; 252 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 253 ifp->if_ioctl = etherip_ioctl; 254 ifp->if_start = etherip_start; 255 ifp->if_stop = etherip_stop; 256 ifp->if_init = etherip_init; 257 IFQ_SET_READY(&ifp->if_snd); 258 259 sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; 260 261 /* 262 * Those steps are mandatory for an Ethernet driver, the first call 263 * being common to all network interface drivers. 264 */ 265 if_attach(ifp); 266 ether_ifattach(ifp, enaddr); 267 268 /* 269 * Add a sysctl node for that interface. 270 * 271 * The pointer transmitted is not a string, but instead a pointer to 272 * the softc structure, which we can use to build the string value on 273 * the fly in the helper function of the node. See the comments for 274 * etherip_sysctl_handler for details. 275 */ 276 error = sysctl_createv(NULL, 0, NULL, &node, CTLFLAG_READWRITE, 277 CTLTYPE_STRING, device_xname(self), NULL, 278 etherip_sysctl_handler, 0, sc, 18, CTL_NET, 279 AF_LINK, etherip_node, device_unit(self), 280 CTL_EOL); 281 if (error) 282 aprint_error_dev(self, "sysctl_createv returned %d, ignoring\n", 283 error); 284 285 /* insert into etherip_softc_list */ 286 LIST_INSERT_HEAD(ðerip_softc_list, sc, etherip_list); 287} 288 289/* 290 * When detaching, we do the inverse of what is done in the attach 291 * routine, in reversed order. 292 */ 293static int 294etherip_detach(device_t self, int flags) 295{ 296 struct etherip_softc *sc = device_private(self); 297 struct ifnet *ifp = &sc->sc_ec.ec_if; 298 int error, s; 299 300 s = splnet(); 301 etherip_stop(ifp, 1); 302 if_down(ifp); 303 splx(s); 304 305 /* 306 * Destroying a single leaf is a very straightforward operation using 307 * sysctl_destroyv. One should be sure to always end the path with 308 * CTL_EOL. 309 */ 310 error = sysctl_destroyv(NULL, CTL_NET, AF_LINK, etherip_node, 311 device_unit(self), CTL_EOL); 312 if (error) 313 aprint_error_dev(self, "sysctl_destroyv returned %d, ignoring\n", 314 error); 315 316 LIST_REMOVE(sc, etherip_list); 317 etherip_delete_tunnel(ifp); 318 ether_ifdetach(ifp); 319 if_detach(ifp); 320 rtcache_free(&sc->sc_ro); 321 ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY); 322 323 pmf_device_deregister(self); 324 325 return 0; 326} 327 328/* 329 * This function is called by the ifmedia layer to notify the driver 330 * that the user requested a media change. A real driver would 331 * reconfigure the hardware. 332 */ 333static int 334etherip_mediachange(struct ifnet *ifp) 335{ 336 return 0; 337} 338 339/* 340 * Here the user asks for the currently used media. 341 */ 342static void 343etherip_mediastatus(struct ifnet *ifp, struct ifmediareq *imr) 344{ 345 struct etherip_softc *sc = ifp->if_softc; 346 347 imr->ifm_active = sc->sc_im.ifm_cur->ifm_media; 348} 349 350static void 351etherip_start(struct ifnet *ifp) 352{ 353 struct etherip_softc *sc = ifp->if_softc; 354 355 if(sc->sc_si) 356 softint_schedule(sc->sc_si); 357} 358 359static void 360etheripintr(void *arg) 361{ 362 struct etherip_softc *sc = (struct etherip_softc *)arg; 363 struct ifnet *ifp = &sc->sc_ec.ec_if; 364 struct mbuf *m; 365 int s, error; 366 367 mutex_enter(softnet_lock); 368 for (;;) { 369 s = splnet(); 370 IFQ_DEQUEUE(&ifp->if_snd, m); 371 splx(s); 372 if (m == NULL) 373 break; 374 375 bpf_mtap(ifp, m); 376 377 ifp->if_opackets++; 378 if (sc->sc_src && sc->sc_dst) { 379 ifp->if_flags |= IFF_OACTIVE; 380 switch (sc->sc_src->sa_family) { 381#ifdef INET 382 case AF_INET: 383 error = ip_etherip_output(ifp, m); 384 break; 385#endif 386#ifdef INET6 387 case AF_INET6: 388 error = ip6_etherip_output(ifp, m); 389 break; 390#endif 391 default: 392 error = ENETDOWN; 393 } 394 ifp->if_flags &= ~IFF_OACTIVE; 395 } else m_freem(m); 396 } 397 mutex_exit(softnet_lock); 398} 399 400static int 401etherip_ioctl(struct ifnet *ifp, u_long cmd, void *data) 402{ 403 struct etherip_softc *sc = ifp->if_softc; 404 struct ifreq *ifr = data; 405 struct sockaddr *src, *dst; 406 int s, error; 407 408 switch (cmd) { 409 case SIOCSLIFPHYADDR: 410 src = (struct sockaddr *) 411 &(((struct if_laddrreq *)data)->addr); 412 dst = (struct sockaddr *) 413 &(((struct if_laddrreq *)data)->dstaddr); 414 415 /* sa_family must be equal */ 416 if (src->sa_family != dst->sa_family) 417 return EINVAL; 418 419 /* validate sa_len */ 420 switch (src->sa_family) { 421#ifdef INET 422 case AF_INET: 423 if (src->sa_len != sizeof(struct sockaddr_in) || 424 dst->sa_len != sizeof(struct sockaddr_in)) 425 return EINVAL; 426 break; 427#endif 428#ifdef INET6 429 case AF_INET6: 430 if (src->sa_len != sizeof(struct sockaddr_in6) || 431 dst->sa_len != sizeof(struct sockaddr_in6)) 432 return EINVAL; 433 break; 434#endif 435 default: 436 return EAFNOSUPPORT; 437 } 438 439 error = etherip_set_tunnel(ifp, src, dst); 440 break; 441 442 case SIOCDIFPHYADDR: 443 etherip_delete_tunnel(ifp); 444 error = 0; 445 break; 446 447 case SIOCGLIFPHYADDR: 448 if (sc->sc_src == NULL || sc->sc_dst == NULL) 449 return EADDRNOTAVAIL; 450 451 /* copy src */ 452 src = sc->sc_src; 453 dst = (struct sockaddr *) 454 &(((struct if_laddrreq *)data)->addr); 455 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->addr)) 456 return EINVAL; 457 memcpy(dst, src, src->sa_len); 458 459 /* copy dst */ 460 src = sc->sc_dst; 461 dst = (struct sockaddr *) 462 &(((struct if_laddrreq *)data)->dstaddr); 463 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->dstaddr)) 464 return EINVAL; 465 memcpy(dst, src, src->sa_len); 466 467 error = 0; 468 break; 469 470#ifdef OSIOCSIFMEDIA 471 case OSIOCSIFMEDIA: 472#endif 473 case SIOCSIFMEDIA: 474 case SIOCGIFMEDIA: 475 s = splnet(); 476 error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd); 477 splx(s); 478 break; 479 480 default: 481 s = splnet(); 482 error = ether_ioctl(ifp, cmd, data); 483 splx(s); 484 if (error == ENETRESET) 485 error = 0; 486 break; 487 } 488 489 return (error); 490} 491 492static int 493etherip_set_tunnel(struct ifnet *ifp, 494 struct sockaddr *src, 495 struct sockaddr *dst) 496{ 497 struct etherip_softc *sc = ifp->if_softc; 498 struct etherip_softc *sc2; 499 struct sockaddr *osrc, *odst; 500 int s, error = 0; 501 502 s = splsoftnet(); 503 504 LIST_FOREACH(sc2, ðerip_softc_list, etherip_list) { 505 if (sc2 == sc) 506 continue; 507 if (!sc2->sc_dst || !sc2->sc_src) 508 continue; 509 if (sc2->sc_dst->sa_family != dst->sa_family || 510 sc2->sc_dst->sa_len != dst->sa_len || 511 sc2->sc_src->sa_family != src->sa_family || 512 sc2->sc_src->sa_len != src->sa_len) 513 continue; 514 /* can't configure same pair of address onto two tunnels */ 515 if (memcmp(sc2->sc_dst, dst, dst->sa_len) == 0 && 516 memcmp(sc2->sc_src, src, src->sa_len) == 0) { 517 error = EADDRNOTAVAIL; 518 goto out; 519 } 520 /* XXX both end must be valid? (I mean, not 0.0.0.0) */ 521 } 522 523 if (sc->sc_si) { 524 softint_disestablish(sc->sc_si); 525 sc->sc_si = NULL; 526 } 527 528 ifp->if_flags &= ~IFF_RUNNING; 529 530 osrc = sc->sc_src; sc->sc_src = NULL; 531 odst = sc->sc_dst; sc->sc_dst = NULL; 532 533 sc->sc_src = sockaddr_dup(src, M_WAITOK); 534 if (osrc) 535 sockaddr_free(osrc); 536 537 sc->sc_dst = sockaddr_dup(dst, M_WAITOK); 538 if (odst) 539 sockaddr_free(odst); 540 541 ifp->if_flags |= IFF_RUNNING; 542 543 sc->sc_si = softint_establish(SOFTINT_NET, etheripintr, sc); 544 if (sc->sc_si == NULL) 545 error = ENOMEM; 546 547out: 548 splx(s); 549 550 return(error); 551} 552 553static void 554etherip_delete_tunnel(struct ifnet *ifp) 555{ 556 struct etherip_softc *sc = ifp->if_softc; 557 int s; 558 559 s = splsoftnet(); 560 561 if (sc->sc_si) { 562 softint_disestablish(sc->sc_si); 563 sc->sc_si = NULL; 564 } 565 566 if (sc->sc_src) { 567 sockaddr_free(sc->sc_src); 568 sc->sc_src = NULL; 569 } 570 if (sc->sc_dst) { 571 sockaddr_free(sc->sc_dst); 572 sc->sc_dst = NULL; 573 } 574 575 ifp->if_flags &= ~IFF_RUNNING; 576 splx(s); 577} 578 579static int 580etherip_init(struct ifnet *ifp) 581{ 582 struct etherip_softc *sc = ifp->if_softc; 583 584 if (sc->sc_si == NULL) 585 sc->sc_si = softint_establish(SOFTINT_NET, etheripintr, sc); 586 587 if (sc->sc_si == NULL) 588 return(ENOMEM); 589 590 ifp->if_flags |= IFF_RUNNING; 591 etherip_start(ifp); 592 593 return 0; 594} 595 596static void 597etherip_stop(struct ifnet *ifp, int disable) 598{ 599 ifp->if_flags &= ~IFF_RUNNING; 600} 601 602static int 603etherip_clone_create(struct if_clone *ifc, int unit) 604{ 605 cfdata_t cf; 606 607 cf = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK); 608 cf->cf_name = etherip_cd.cd_name; 609 cf->cf_atname = etherip_ca.ca_name; 610 cf->cf_unit = unit; 611 cf->cf_fstate = FSTATE_STAR; 612 613 if (config_attach_pseudo(cf) == NULL) { 614 aprint_error("%s%d: unable to attach an instance\n", 615 etherip_cd.cd_name, unit); 616 return (ENXIO); 617 } 618 619 return 0; 620} 621 622static int 623etherip_clone_destroy(struct ifnet *ifp) 624{ 625 struct etherip_softc *sc = ifp->if_softc; 626 cfdata_t cf = device_cfdata(sc->sc_dev); 627 int error; 628 629 if ((error = config_detach(sc->sc_dev, 0)) != 0) 630 aprint_error_dev(sc->sc_dev, "unable to detach instance\n"); 631 free(cf, M_DEVBUF); 632 633 return error; 634} 635 636SYSCTL_SETUP(sysctl_etherip_setup, "sysctl net.link.etherip subtree setup") 637{ 638 const struct sysctlnode *node; 639 int error = 0; 640 641 error = sysctl_createv(clog, 0, NULL, NULL, 642 CTLFLAG_PERMANENT, 643 CTLTYPE_NODE, "net", NULL, 644 NULL, 0, NULL, 0, 645 CTL_NET, CTL_EOL); 646 if (error) 647 return; 648 649 error = sysctl_createv(clog, 0, NULL, NULL, 650 CTLFLAG_PERMANENT, 651 CTLTYPE_NODE, "link", NULL, 652 NULL, 0, NULL, 0, 653 CTL_NET, AF_LINK, CTL_EOL); 654 if (error) 655 return; 656 657 error = sysctl_createv(clog, 0, NULL, &node, 658 CTLFLAG_PERMANENT, 659 CTLTYPE_NODE, "etherip", NULL, 660 NULL, 0, NULL, 0, 661 CTL_NET, AF_LINK, CTL_CREATE, CTL_EOL); 662 if (error) 663 return; 664 665 etherip_node = node->sysctl_num; 666} 667 668static int 669etherip_sysctl_handler(SYSCTLFN_ARGS) 670{ 671 struct sysctlnode node; 672 struct etherip_softc *sc; 673 struct ifnet *ifp; 674 int error; 675 size_t len; 676 char addr[3 * ETHER_ADDR_LEN]; 677 char enaddr[ETHER_ADDR_LEN]; 678 679 node = *rnode; 680 sc = node.sysctl_data; 681 ifp = &sc->sc_ec.ec_if; 682 (void)ether_snprintf(addr, sizeof(addr), CLLADDR(ifp->if_sadl)); 683 node.sysctl_data = addr; 684 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 685 if (error || newp == NULL) 686 return error; 687 688 len = strlen(addr); 689 if (len < 11 || len > 17) 690 return EINVAL; 691 692 /* Commit change */ 693 if (ether_aton_r(enaddr, sizeof(enaddr), addr) != 0) 694 return EINVAL; 695 696 if_set_sadl(ifp, enaddr, ETHER_ADDR_LEN, false); 697 return error; 698} 699 700