Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / net / if_etherip.c
blobcd95321228e1459854b9b7915f7882ac419d1c13
1 /* $NetBSD: if_etherip.c,v 1.26 2008/12/17 20:51:36 cegger Exp $ */
3 /*
4 * Copyright (c) 2006, Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
5 * All rights reserved.
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.
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.
32 * Copyright (c) 2003, 2004, 2008 The NetBSD Foundation.
33 * All rights reserved.
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.
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.
60 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
61 * All rights reserved.
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.
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.
88 #include <sys/cdefs.h>
89 __KERNEL_RCSID(0, "$NetBSD: if_etherip.c,v 1.26 2008/12/17 20:51:36 cegger Exp $");
91 #include "opt_inet.h"
92 #include "bpfilter.h"
94 #include <sys/param.h>
95 #include <sys/systm.h>
96 #include <sys/kernel.h>
97 #include <sys/malloc.h>
98 #include <sys/conf.h>
99 #include <sys/device.h>
100 #include <sys/errno.h>
101 #include <sys/time.h>
102 #include <sys/sysctl.h>
103 #include <sys/queue.h>
104 #include <sys/kauth.h>
105 #include <sys/socket.h>
106 #include <sys/socketvar.h>
107 #include <sys/intr.h>
109 #include <net/if.h>
110 #include <net/if_dl.h>
111 #include <net/if_ether.h>
112 #include <net/if_media.h>
113 #include <net/route.h>
114 #include <net/if_etherip.h>
115 #if NBPFILTER > 0
116 #include <net/bpf.h>
117 #endif
119 #include <netinet/in.h>
120 #include <netinet/in_systm.h>
121 #include <netinet/ip.h>
122 #ifdef INET
123 #include <netinet/in_var.h>
124 #endif /* INET */
125 #include <netinet/ip_etherip.h>
127 #ifdef INET6
128 #include <netinet6/ip6_etherip.h>
129 #ifndef INET
130 #include <netinet/in.h>
131 #endif
132 #include <netinet6/in6_var.h>
133 #include <netinet/ip6.h>
134 #include <netinet6/ip6_var.h>
135 #include <netinet6/in6_gif.h>
136 #include <netinet6/ip6protosw.h>
137 #endif /* INET6 */
139 #include <compat/sys/sockio.h>
141 static int etherip_node;
142 static int etherip_sysctl_handler(SYSCTLFN_PROTO);
143 SYSCTL_SETUP_PROTO(sysctl_etherip_setup);
145 void etheripattach(int);
147 static int etherip_match(device_t, cfdata_t, void *);
148 static void etherip_attach(device_t, device_t, void *);
149 static int etherip_detach(device_t, int);
151 CFATTACH_DECL_NEW(etherip, sizeof(struct etherip_softc),
152 etherip_match, etherip_attach, etherip_detach, NULL);
153 extern struct cfdriver etherip_cd;
155 static void etherip_start(struct ifnet *);
156 static void etherip_stop(struct ifnet *, int);
157 static int etherip_init(struct ifnet *);
158 static int etherip_ioctl(struct ifnet *, u_long, void *);
160 static int etherip_mediachange(struct ifnet *);
161 static void etherip_mediastatus(struct ifnet *, struct ifmediareq *);
163 static int etherip_clone_create(struct if_clone *, int);
164 static int etherip_clone_destroy(struct ifnet *);
166 static struct if_clone etherip_cloners = IF_CLONE_INITIALIZER(
167 "etherip", etherip_clone_create, etherip_clone_destroy);
169 static int etherip_set_tunnel(struct ifnet *,
170 struct sockaddr *, struct sockaddr *);
171 static void etherip_delete_tunnel(struct ifnet *);
172 static void etheripintr(void *);
174 void
175 etheripattach(int count)
177 int error;
179 error = config_cfattach_attach(etherip_cd.cd_name, &etherip_ca);
181 if (error) {
182 aprint_error("%s: unable to register cfattach\n",
183 etherip_cd.cd_name);
184 (void)config_cfdriver_detach(&etherip_cd);
185 return;
188 LIST_INIT(&etherip_softc_list);
189 if_clone_attach(&etherip_cloners);
192 /* Pretty much useless for a pseudo-device */
193 static int
194 etherip_match(device_t self, cfdata_t cfdata, void *arg)
196 return 1;
199 static void
200 etherip_attach(device_t parent, device_t self, void *aux)
202 struct etherip_softc *sc = device_private(self);
203 struct ifnet *ifp;
204 const struct sysctlnode *node;
205 uint8_t enaddr[ETHER_ADDR_LEN] =
206 { 0xf2, 0x0b, 0xa5, 0xff, 0xff, 0xff };
207 char enaddrstr[3 * ETHER_ADDR_LEN];
208 struct timeval tv;
209 uint32_t ui;
210 int error;
212 sc->sc_dev = self;
213 sc->sc_si = NULL;
214 sc->sc_src = NULL;
215 sc->sc_dst = NULL;
217 if (!pmf_device_register(self, NULL, NULL))
218 aprint_error_dev(self, "couldn't establish power handler\n");
221 * In order to obtain unique initial Ethernet address on a host,
222 * do some randomisation using the current uptime. It's not meant
223 * for anything but avoiding hard-coding an address.
225 getmicrouptime(&tv);
226 ui = (tv.tv_sec ^ tv.tv_usec) & 0xffffff;
227 memcpy(enaddr+3, (uint8_t *)&ui, 3);
229 aprint_verbose_dev(self, "Ethernet address %s\n",
230 ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr));
233 * Why 1000baseT? Why not? You can add more.
235 * Note that there are 3 steps: init, one or several additions to
236 * list of supported media, and in the end, the selection of one
237 * of them.
239 ifmedia_init(&sc->sc_im, 0, etherip_mediachange, etherip_mediastatus);
240 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T, 0, NULL);
241 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
242 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX, 0, NULL);
243 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
244 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T, 0, NULL);
245 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
246 ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_AUTO, 0, NULL);
247 ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_AUTO);
250 * One should note that an interface must do multicast in order
251 * to support IPv6.
253 ifp = &sc->sc_ec.ec_if;
254 strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
255 ifp->if_softc = sc;
256 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
257 ifp->if_ioctl = etherip_ioctl;
258 ifp->if_start = etherip_start;
259 ifp->if_stop = etherip_stop;
260 ifp->if_init = etherip_init;
261 IFQ_SET_READY(&ifp->if_snd);
263 sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU;
266 * Those steps are mandatory for an Ethernet driver, the first call
267 * being common to all network interface drivers.
269 if_attach(ifp);
270 ether_ifattach(ifp, enaddr);
273 * Add a sysctl node for that interface.
275 * The pointer transmitted is not a string, but instead a pointer to
276 * the softc structure, which we can use to build the string value on
277 * the fly in the helper function of the node. See the comments for
278 * etherip_sysctl_handler for details.
280 error = sysctl_createv(NULL, 0, NULL, &node, CTLFLAG_READWRITE,
281 CTLTYPE_STRING, device_xname(self), NULL,
282 etherip_sysctl_handler, 0, sc, 18, CTL_NET,
283 AF_LINK, etherip_node, device_unit(self),
284 CTL_EOL);
285 if (error)
286 aprint_error_dev(self, "sysctl_createv returned %d, ignoring\n",
287 error);
289 /* insert into etherip_softc_list */
290 LIST_INSERT_HEAD(&etherip_softc_list, sc, etherip_list);
294 * When detaching, we do the inverse of what is done in the attach
295 * routine, in reversed order.
297 static int
298 etherip_detach(device_t self, int flags)
300 struct etherip_softc *sc = device_private(self);
301 struct ifnet *ifp = &sc->sc_ec.ec_if;
302 int error, s;
304 s = splnet();
305 etherip_stop(ifp, 1);
306 if_down(ifp);
307 splx(s);
310 * Destroying a single leaf is a very straightforward operation using
311 * sysctl_destroyv. One should be sure to always end the path with
312 * CTL_EOL.
314 error = sysctl_destroyv(NULL, CTL_NET, AF_LINK, etherip_node,
315 device_unit(self), CTL_EOL);
316 if (error)
317 aprint_error_dev(self, "sysctl_destroyv returned %d, ignoring\n",
318 error);
320 LIST_REMOVE(sc, etherip_list);
321 etherip_delete_tunnel(ifp);
322 ether_ifdetach(ifp);
323 if_detach(ifp);
324 rtcache_free(&sc->sc_ro);
325 ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY);
327 pmf_device_deregister(self);
329 return 0;
333 * This function is called by the ifmedia layer to notify the driver
334 * that the user requested a media change. A real driver would
335 * reconfigure the hardware.
337 static int
338 etherip_mediachange(struct ifnet *ifp)
340 return 0;
344 * Here the user asks for the currently used media.
346 static void
347 etherip_mediastatus(struct ifnet *ifp, struct ifmediareq *imr)
349 struct etherip_softc *sc = ifp->if_softc;
351 imr->ifm_active = sc->sc_im.ifm_cur->ifm_media;
354 static void
355 etherip_start(struct ifnet *ifp)
357 struct etherip_softc *sc = ifp->if_softc;
359 if(sc->sc_si)
360 softint_schedule(sc->sc_si);
363 static void
364 etheripintr(void *arg)
366 struct etherip_softc *sc = (struct etherip_softc *)arg;
367 struct ifnet *ifp = &sc->sc_ec.ec_if;
368 struct mbuf *m;
369 int s, error;
371 mutex_enter(softnet_lock);
372 for (;;) {
373 s = splnet();
374 IFQ_DEQUEUE(&ifp->if_snd, m);
375 splx(s);
376 if (m == NULL)
377 break;
379 #if NBPFILTER > 0
380 if (ifp->if_bpf)
381 bpf_mtap(ifp->if_bpf, m);
382 #endif
384 ifp->if_opackets++;
385 if (sc->sc_src && sc->sc_dst) {
386 ifp->if_flags |= IFF_OACTIVE;
387 switch (sc->sc_src->sa_family) {
388 #ifdef INET
389 case AF_INET:
390 error = ip_etherip_output(ifp, m);
391 break;
392 #endif
393 #ifdef INET6
394 case AF_INET6:
395 error = ip6_etherip_output(ifp, m);
396 break;
397 #endif
398 default:
399 error = ENETDOWN;
401 ifp->if_flags &= ~IFF_OACTIVE;
402 } else m_freem(m);
404 mutex_exit(softnet_lock);
407 static int
408 etherip_ioctl(struct ifnet *ifp, u_long cmd, void *data)
410 struct etherip_softc *sc = ifp->if_softc;
411 struct ifreq *ifr = data;
412 struct sockaddr *src, *dst;
413 int s, error;
415 switch (cmd) {
416 case SIOCSLIFPHYADDR:
417 src = (struct sockaddr *)
418 &(((struct if_laddrreq *)data)->addr);
419 dst = (struct sockaddr *)
420 &(((struct if_laddrreq *)data)->dstaddr);
422 /* sa_family must be equal */
423 if (src->sa_family != dst->sa_family)
424 return EINVAL;
426 /* validate sa_len */
427 switch (src->sa_family) {
428 #ifdef INET
429 case AF_INET:
430 if (src->sa_len != sizeof(struct sockaddr_in) ||
431 dst->sa_len != sizeof(struct sockaddr_in))
432 return EINVAL;
433 break;
434 #endif
435 #ifdef INET6
436 case AF_INET6:
437 if (src->sa_len != sizeof(struct sockaddr_in6) ||
438 dst->sa_len != sizeof(struct sockaddr_in6))
439 return EINVAL;
440 break;
441 #endif
442 default:
443 return EAFNOSUPPORT;
446 error = etherip_set_tunnel(ifp, src, dst);
447 break;
449 case SIOCDIFPHYADDR:
450 etherip_delete_tunnel(ifp);
451 error = 0;
452 break;
454 case SIOCGLIFPHYADDR:
455 if (sc->sc_src == NULL || sc->sc_dst == NULL)
456 return EADDRNOTAVAIL;
458 /* copy src */
459 src = sc->sc_src;
460 dst = (struct sockaddr *)
461 &(((struct if_laddrreq *)data)->addr);
462 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->addr))
463 return EINVAL;
464 memcpy(dst, src, src->sa_len);
466 /* copy dst */
467 src = sc->sc_dst;
468 dst = (struct sockaddr *)
469 &(((struct if_laddrreq *)data)->dstaddr);
470 if (src->sa_len > sizeof(((struct if_laddrreq *)data)->dstaddr))
471 return EINVAL;
472 memcpy(dst, src, src->sa_len);
474 error = 0;
475 break;
477 #ifdef OSIOCSIFMEDIA
478 case OSIOCSIFMEDIA:
479 #endif
480 case SIOCSIFMEDIA:
481 case SIOCGIFMEDIA:
482 s = splnet();
483 error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd);
484 splx(s);
485 break;
487 default:
488 s = splnet();
489 error = ether_ioctl(ifp, cmd, data);
490 splx(s);
491 if (error == ENETRESET)
492 error = 0;
493 break;
496 return (error);
499 static int
500 etherip_set_tunnel(struct ifnet *ifp,
501 struct sockaddr *src,
502 struct sockaddr *dst)
504 struct etherip_softc *sc = ifp->if_softc;
505 struct etherip_softc *sc2;
506 struct sockaddr *osrc, *odst;
507 int s, error = 0;
509 s = splsoftnet();
511 LIST_FOREACH(sc2, &etherip_softc_list, etherip_list) {
512 if (sc2 == sc)
513 continue;
514 if (!sc2->sc_dst || !sc2->sc_src)
515 continue;
516 if (sc2->sc_dst->sa_family != dst->sa_family ||
517 sc2->sc_dst->sa_len != dst->sa_len ||
518 sc2->sc_src->sa_family != src->sa_family ||
519 sc2->sc_src->sa_len != src->sa_len)
520 continue;
521 /* can't configure same pair of address onto two tunnels */
522 if (memcmp(sc2->sc_dst, dst, dst->sa_len) == 0 &&
523 memcmp(sc2->sc_src, src, src->sa_len) == 0) {
524 error = EADDRNOTAVAIL;
525 goto out;
527 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
530 if (sc->sc_si) {
531 softint_disestablish(sc->sc_si);
532 sc->sc_si = NULL;
535 ifp->if_flags &= ~IFF_RUNNING;
537 osrc = sc->sc_src; sc->sc_src = NULL;
538 odst = sc->sc_dst; sc->sc_dst = NULL;
540 sc->sc_src = sockaddr_dup(src, M_WAITOK);
541 if (osrc)
542 sockaddr_free(osrc);
544 sc->sc_dst = sockaddr_dup(dst, M_WAITOK);
545 if (odst)
546 sockaddr_free(odst);
548 ifp->if_flags |= IFF_RUNNING;
550 sc->sc_si = softint_establish(SOFTINT_NET, etheripintr, sc);
551 if (sc->sc_si == NULL)
552 error = ENOMEM;
554 out:
555 splx(s);
557 return(error);
560 static void
561 etherip_delete_tunnel(struct ifnet *ifp)
563 struct etherip_softc *sc = ifp->if_softc;
564 int s;
566 s = splsoftnet();
568 if (sc->sc_si) {
569 softint_disestablish(sc->sc_si);
570 sc->sc_si = NULL;
573 if (sc->sc_src) {
574 sockaddr_free(sc->sc_src);
575 sc->sc_src = NULL;
577 if (sc->sc_dst) {
578 sockaddr_free(sc->sc_dst);
579 sc->sc_dst = NULL;
582 ifp->if_flags &= ~IFF_RUNNING;
583 splx(s);
586 static int
587 etherip_init(struct ifnet *ifp)
589 struct etherip_softc *sc = ifp->if_softc;
591 if (sc->sc_si == NULL)
592 sc->sc_si = softint_establish(SOFTINT_NET, etheripintr, sc);
594 if (sc->sc_si == NULL)
595 return(ENOMEM);
597 ifp->if_flags |= IFF_RUNNING;
598 etherip_start(ifp);
600 return 0;
603 static void
604 etherip_stop(struct ifnet *ifp, int disable)
606 ifp->if_flags &= ~IFF_RUNNING;
609 static int
610 etherip_clone_create(struct if_clone *ifc, int unit)
612 cfdata_t cf;
614 cf = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
615 cf->cf_name = etherip_cd.cd_name;
616 cf->cf_atname = etherip_ca.ca_name;
617 cf->cf_unit = unit;
618 cf->cf_fstate = FSTATE_STAR;
620 if (config_attach_pseudo(cf) == NULL) {
621 aprint_error("%s%d: unable to attach an instance\n",
622 etherip_cd.cd_name, unit);
623 return (ENXIO);
626 return 0;
629 static int
630 etherip_clone_destroy(struct ifnet *ifp)
632 struct etherip_softc *sc = ifp->if_softc;
633 cfdata_t cf = device_cfdata(sc->sc_dev);
634 int error;
636 if ((error = config_detach(sc->sc_dev, 0)) != 0)
637 aprint_error_dev(sc->sc_dev, "unable to detach instance\n");
638 free(cf, M_DEVBUF);
640 return error;
643 SYSCTL_SETUP(sysctl_etherip_setup, "sysctl net.link.etherip subtree setup")
645 const struct sysctlnode *node;
646 int error = 0;
648 error = sysctl_createv(clog, 0, NULL, NULL,
649 CTLFLAG_PERMANENT,
650 CTLTYPE_NODE, "net", NULL,
651 NULL, 0, NULL, 0,
652 CTL_NET, CTL_EOL);
653 if (error)
654 return;
656 error = sysctl_createv(clog, 0, NULL, NULL,
657 CTLFLAG_PERMANENT,
658 CTLTYPE_NODE, "link", NULL,
659 NULL, 0, NULL, 0,
660 CTL_NET, AF_LINK, CTL_EOL);
661 if (error)
662 return;
664 error = sysctl_createv(clog, 0, NULL, &node,
665 CTLFLAG_PERMANENT,
666 CTLTYPE_NODE, "etherip", NULL,
667 NULL, 0, NULL, 0,
668 CTL_NET, AF_LINK, CTL_CREATE, CTL_EOL);
669 if (error)
670 return;
672 etherip_node = node->sysctl_num;
675 static int
676 etherip_sysctl_handler(SYSCTLFN_ARGS)
678 struct sysctlnode node;
679 struct etherip_softc *sc;
680 struct ifnet *ifp;
681 int error;
682 size_t len;
683 char addr[3 * ETHER_ADDR_LEN];
684 char enaddr[ETHER_ADDR_LEN];
686 node = *rnode;
687 sc = node.sysctl_data;
688 ifp = &sc->sc_ec.ec_if;
689 (void)ether_snprintf(addr, sizeof(addr), CLLADDR(ifp->if_sadl));
690 node.sysctl_data = addr;
691 error = sysctl_lookup(SYSCTLFN_CALL(&node));
692 if (error || newp == NULL)
693 return error;
695 len = strlen(addr);
696 if (len < 11 || len > 17)
697 return EINVAL;
699 /* Commit change */
700 if (ether_nonstatic_aton(enaddr, addr) != 0)
701 return EINVAL;
703 if_set_sadl(ifp, enaddr, ETHER_ADDR_LEN, false);
704 return error;