1 /* $NetBSD: if_etherip.c,v 1.26 2008/12/17 20:51:36 cegger Exp $ */
4 * Copyright (c) 2006, Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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
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
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
88 #include <sys/cdefs.h>
89 __KERNEL_RCSID(0, "$NetBSD: if_etherip.c,v 1.26 2008/12/17 20:51:36 cegger Exp $");
94 #include <sys/param.h>
95 #include <sys/systm.h>
96 #include <sys/kernel.h>
97 #include <sys/malloc.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>
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>
119 #include <netinet/in.h>
120 #include <netinet/in_systm.h>
121 #include <netinet/ip.h>
123 #include <netinet/in_var.h>
125 #include <netinet/ip_etherip.h>
128 #include <netinet6/ip6_etherip.h>
130 #include <netinet/in.h>
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>
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 *);
175 etheripattach(int count
)
179 error
= config_cfattach_attach(etherip_cd
.cd_name
, ðerip_ca
);
182 aprint_error("%s: unable to register cfattach\n",
184 (void)config_cfdriver_detach(ðerip_cd
);
188 LIST_INIT(ðerip_softc_list
);
189 if_clone_attach(ðerip_cloners
);
192 /* Pretty much useless for a pseudo-device */
194 etherip_match(device_t self
, cfdata_t cfdata
, void *arg
)
200 etherip_attach(device_t parent
, device_t self
, void *aux
)
202 struct etherip_softc
*sc
= device_private(self
);
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
];
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.
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
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
253 ifp
= &sc
->sc_ec
.ec_if
;
254 strlcpy(ifp
->if_xname
, device_xname(self
), IFNAMSIZ
);
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.
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
),
286 aprint_error_dev(self
, "sysctl_createv returned %d, ignoring\n",
289 /* insert into etherip_softc_list */
290 LIST_INSERT_HEAD(ðerip_softc_list
, sc
, etherip_list
);
294 * When detaching, we do the inverse of what is done in the attach
295 * routine, in reversed order.
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
;
305 etherip_stop(ifp
, 1);
310 * Destroying a single leaf is a very straightforward operation using
311 * sysctl_destroyv. One should be sure to always end the path with
314 error
= sysctl_destroyv(NULL
, CTL_NET
, AF_LINK
, etherip_node
,
315 device_unit(self
), CTL_EOL
);
317 aprint_error_dev(self
, "sysctl_destroyv returned %d, ignoring\n",
320 LIST_REMOVE(sc
, etherip_list
);
321 etherip_delete_tunnel(ifp
);
324 rtcache_free(&sc
->sc_ro
);
325 ifmedia_delete_instance(&sc
->sc_im
, IFM_INST_ANY
);
327 pmf_device_deregister(self
);
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.
338 etherip_mediachange(struct ifnet
*ifp
)
344 * Here the user asks for the currently used media.
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
;
355 etherip_start(struct ifnet
*ifp
)
357 struct etherip_softc
*sc
= ifp
->if_softc
;
360 softint_schedule(sc
->sc_si
);
364 etheripintr(void *arg
)
366 struct etherip_softc
*sc
= (struct etherip_softc
*)arg
;
367 struct ifnet
*ifp
= &sc
->sc_ec
.ec_if
;
371 mutex_enter(softnet_lock
);
374 IFQ_DEQUEUE(&ifp
->if_snd
, m
);
381 bpf_mtap(ifp
->if_bpf
, m
);
385 if (sc
->sc_src
&& sc
->sc_dst
) {
386 ifp
->if_flags
|= IFF_OACTIVE
;
387 switch (sc
->sc_src
->sa_family
) {
390 error
= ip_etherip_output(ifp
, m
);
395 error
= ip6_etherip_output(ifp
, m
);
401 ifp
->if_flags
&= ~IFF_OACTIVE
;
404 mutex_exit(softnet_lock
);
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
;
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
)
426 /* validate sa_len */
427 switch (src
->sa_family
) {
430 if (src
->sa_len
!= sizeof(struct sockaddr_in
) ||
431 dst
->sa_len
!= sizeof(struct sockaddr_in
))
437 if (src
->sa_len
!= sizeof(struct sockaddr_in6
) ||
438 dst
->sa_len
!= sizeof(struct sockaddr_in6
))
446 error
= etherip_set_tunnel(ifp
, src
, dst
);
450 etherip_delete_tunnel(ifp
);
454 case SIOCGLIFPHYADDR
:
455 if (sc
->sc_src
== NULL
|| sc
->sc_dst
== NULL
)
456 return EADDRNOTAVAIL
;
460 dst
= (struct sockaddr
*)
461 &(((struct if_laddrreq
*)data
)->addr
);
462 if (src
->sa_len
> sizeof(((struct if_laddrreq
*)data
)->addr
))
464 memcpy(dst
, src
, src
->sa_len
);
468 dst
= (struct sockaddr
*)
469 &(((struct if_laddrreq
*)data
)->dstaddr
);
470 if (src
->sa_len
> sizeof(((struct if_laddrreq
*)data
)->dstaddr
))
472 memcpy(dst
, src
, src
->sa_len
);
483 error
= ifmedia_ioctl(ifp
, ifr
, &sc
->sc_im
, cmd
);
489 error
= ether_ioctl(ifp
, cmd
, data
);
491 if (error
== ENETRESET
)
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
;
511 LIST_FOREACH(sc2
, ðerip_softc_list
, etherip_list
) {
514 if (!sc2
->sc_dst
|| !sc2
->sc_src
)
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
)
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
;
527 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
531 softint_disestablish(sc
->sc_si
);
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
);
544 sc
->sc_dst
= sockaddr_dup(dst
, M_WAITOK
);
548 ifp
->if_flags
|= IFF_RUNNING
;
550 sc
->sc_si
= softint_establish(SOFTINT_NET
, etheripintr
, sc
);
551 if (sc
->sc_si
== NULL
)
561 etherip_delete_tunnel(struct ifnet
*ifp
)
563 struct etherip_softc
*sc
= ifp
->if_softc
;
569 softint_disestablish(sc
->sc_si
);
574 sockaddr_free(sc
->sc_src
);
578 sockaddr_free(sc
->sc_dst
);
582 ifp
->if_flags
&= ~IFF_RUNNING
;
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
)
597 ifp
->if_flags
|= IFF_RUNNING
;
604 etherip_stop(struct ifnet
*ifp
, int disable
)
606 ifp
->if_flags
&= ~IFF_RUNNING
;
610 etherip_clone_create(struct if_clone
*ifc
, int unit
)
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
;
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
);
630 etherip_clone_destroy(struct ifnet
*ifp
)
632 struct etherip_softc
*sc
= ifp
->if_softc
;
633 cfdata_t cf
= device_cfdata(sc
->sc_dev
);
636 if ((error
= config_detach(sc
->sc_dev
, 0)) != 0)
637 aprint_error_dev(sc
->sc_dev
, "unable to detach instance\n");
643 SYSCTL_SETUP(sysctl_etherip_setup
, "sysctl net.link.etherip subtree setup")
645 const struct sysctlnode
*node
;
648 error
= sysctl_createv(clog
, 0, NULL
, NULL
,
650 CTLTYPE_NODE
, "net", NULL
,
656 error
= sysctl_createv(clog
, 0, NULL
, NULL
,
658 CTLTYPE_NODE
, "link", NULL
,
660 CTL_NET
, AF_LINK
, CTL_EOL
);
664 error
= sysctl_createv(clog
, 0, NULL
, &node
,
666 CTLTYPE_NODE
, "etherip", NULL
,
668 CTL_NET
, AF_LINK
, CTL_CREATE
, CTL_EOL
);
672 etherip_node
= node
->sysctl_num
;
676 etherip_sysctl_handler(SYSCTLFN_ARGS
)
678 struct sysctlnode node
;
679 struct etherip_softc
*sc
;
683 char addr
[3 * ETHER_ADDR_LEN
];
684 char enaddr
[ETHER_ADDR_LEN
];
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
)
696 if (len
< 11 || len
> 17)
700 if (ether_nonstatic_aton(enaddr
, addr
) != 0)
703 if_set_sadl(ifp
, enaddr
, ETHER_ADDR_LEN
, false);