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