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, &etherip_ca);
176
177	if (error) {
178		aprint_error("%s: unable to register cfattach\n",
179			     etherip_cd.cd_name);
180		(void)config_cfdriver_detach(&etherip_cd);
181		return;
182	}
183
184	LIST_INIT(&etherip_softc_list);
185	if_clone_attach(&etherip_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(&etherip_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, &etherip_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