xref: /openbsd-src/sys/net/if_etherip.c (revision 6c6408334dbede3a2c0dcd9ff9c489157df0c856)
1 /*	$OpenBSD: if_etherip.c,v 1.37 2018/02/19 00:29:29 dlg Exp $	*/
2 /*
3  * Copyright (c) 2015 Kazuya GODA <goda@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "bpfilter.h"
19 #include "pf.h"
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/mbuf.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <sys/device.h>
27 #include <sys/sysctl.h>
28 #include <sys/tree.h>
29 
30 #include <net/if.h>
31 #include <net/if_var.h>
32 #include <net/if_dl.h>
33 #include <net/if_media.h>
34 #include <net/rtable.h>
35 
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 #include <netinet/ip_var.h>
39 #include <netinet/if_ether.h>
40 #include <netinet/ip_ether.h>
41 
42 #ifdef INET6
43 #include <netinet/ip6.h>
44 #include <netinet6/ip6_var.h>
45 #endif
46 
47 #if NBPFILTER > 0
48 #include <net/bpf.h>
49 #endif
50 
51 #if NPF > 0
52 #include <net/pfvar.h>
53 #endif
54 
55 #include <net/if_etherip.h>
56 
57 union etherip_addr {
58 	struct in_addr	in4;
59 	struct in6_addr	in6;
60 };
61 
62 struct etherip_tunnel {
63 	union etherip_addr
64 			_t_src;
65 #define t_src4	_t_src.in4
66 #define t_src6	_t_src.in6
67 	union etherip_addr
68 			_t_dst;
69 #define t_dst4	_t_dst.in4
70 #define t_dst6	_t_dst.in6
71 
72 	unsigned int	t_rtableid;
73 	sa_family_t	t_af;
74 
75 	TAILQ_ENTRY(etherip_tunnel)
76 			t_entry;
77 };
78 
79 TAILQ_HEAD(etherip_list, etherip_tunnel);
80 
81 static inline int etherip_cmp(const struct etherip_tunnel *,
82     const struct etherip_tunnel *);
83 
84 struct etherip_softc {
85 	struct etherip_tunnel	sc_tunnel; /* must be first */
86 	struct arpcom		sc_ac;
87 	struct ifmedia		sc_media;
88 	uint16_t		sc_df;
89 	uint8_t			sc_ttl;
90 };
91 
92 /*
93  * We can control the acceptance of EtherIP packets by altering the sysctl
94  * net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
95  */
96 int etherip_allow = 0;
97 
98 struct cpumem *etheripcounters;
99 
100 void etheripattach(int);
101 int etherip_clone_create(struct if_clone *, int);
102 int etherip_clone_destroy(struct ifnet *);
103 int etherip_ioctl(struct ifnet *, u_long, caddr_t);
104 void etherip_start(struct ifnet *);
105 int etherip_media_change(struct ifnet *);
106 void etherip_media_status(struct ifnet *, struct ifmediareq *);
107 int etherip_set_tunnel(struct etherip_softc *, struct if_laddrreq *);
108 int etherip_get_tunnel(struct etherip_softc *, struct if_laddrreq *);
109 int etherip_del_tunnel(struct etherip_softc *);
110 int etherip_up(struct etherip_softc *);
111 int etherip_down(struct etherip_softc *);
112 struct etherip_softc *etherip_find(const struct etherip_tunnel *);
113 int etherip_input(struct etherip_tunnel *, struct mbuf *, int);
114 
115 struct if_clone	etherip_cloner = IF_CLONE_INITIALIZER("etherip",
116     etherip_clone_create, etherip_clone_destroy);
117 
118 struct etherip_list etherip_list = TAILQ_HEAD_INITIALIZER(etherip_list);
119 
120 void
121 etheripattach(int count)
122 {
123 	if_clone_attach(&etherip_cloner);
124 	etheripcounters = counters_alloc(etherips_ncounters);
125 }
126 
127 int
128 etherip_clone_create(struct if_clone *ifc, int unit)
129 {
130 	struct ifnet *ifp;
131 	struct etherip_softc *sc;
132 
133 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
134 	ifp = &sc->sc_ac.ac_if;
135 
136 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
137 	    ifc->ifc_name, unit);
138 
139 	sc->sc_ttl = ip_defttl;
140 	sc->sc_df = htons(0);
141 
142 	ifp->if_softc = sc;
143 	ifp->if_ioctl = etherip_ioctl;
144 	ifp->if_start = etherip_start;
145 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
146 	ifp->if_xflags = IFXF_CLONED;
147 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
148 	ifp->if_capabilities = IFCAP_VLAN_MTU;
149 	ether_fakeaddr(ifp);
150 
151 	ifmedia_init(&sc->sc_media, 0, etherip_media_change,
152 	    etherip_media_status);
153 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
154 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
155 
156 	if_attach(ifp);
157 	ether_ifattach(ifp);
158 
159 	NET_LOCK();
160 	TAILQ_INSERT_TAIL(&etherip_list, &sc->sc_tunnel, t_entry);
161 	NET_UNLOCK();
162 
163 	return (0);
164 }
165 
166 int
167 etherip_clone_destroy(struct ifnet *ifp)
168 {
169 	struct etherip_softc *sc = ifp->if_softc;
170 
171 	NET_LOCK();
172 	if (ISSET(ifp->if_flags, IFF_RUNNING))
173 		etherip_down(sc);
174 
175 	TAILQ_REMOVE(&etherip_list, &sc->sc_tunnel, t_entry);
176 	NET_UNLOCK();
177 
178 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
179 	ether_ifdetach(ifp);
180 	if_detach(ifp);
181 
182 	free(sc, M_DEVBUF, sizeof(*sc));
183 
184 	return (0);
185 }
186 
187 int
188 etherip_media_change(struct ifnet *ifp)
189 {
190 	return 0;
191 }
192 
193 void
194 etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr)
195 {
196 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
197 	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
198 }
199 
200 void
201 etherip_start(struct ifnet *ifp)
202 {
203 	struct etherip_softc *sc = ifp->if_softc;
204 	struct mbuf *m;
205 	int error;
206 #if NBPFILTER > 0
207 	caddr_t if_bpf;
208 #endif
209 
210 	while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
211 #if NBPFILTER > 0
212 		if_bpf = ifp->if_bpf;
213 		if (if_bpf)
214 			bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT);
215 #endif
216 
217 		switch (sc->sc_tunnel.t_af) {
218 		case AF_INET:
219 			error = ip_etherip_output(ifp, m);
220 			break;
221 #ifdef INET6
222 		case AF_INET6:
223 			error = ip6_etherip_output(ifp, m);
224 			break;
225 #endif
226 		default:
227 			/* unhandled_af(sc->sc_tunnel.t_af); */
228 			m_freem(m);
229 			continue;
230 		}
231 
232 		if (error)
233 			ifp->if_oerrors++;
234 	}
235 }
236 
237 int
238 etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
239 {
240 	struct etherip_softc *sc = ifp->if_softc;
241 	struct ifreq *ifr = (struct ifreq *)data;
242 	int error = 0;
243 
244 	switch (cmd) {
245 	case SIOCSIFADDR:
246 		ifp->if_flags |= IFF_UP;
247 		/* FALLTHROUGH */
248 
249 	case SIOCSIFFLAGS:
250 		if (ISSET(ifp->if_flags, IFF_UP)) {
251 			if (!ISSET(ifp->if_flags, IFF_RUNNING))
252 				error = etherip_up(sc);
253 			else
254 				error = 0;
255 		} else {
256 			if (ISSET(ifp->if_flags, IFF_RUNNING))
257 				error = etherip_down(sc);
258 		}
259 		break;
260 
261 	case SIOCSLIFPHYRTABLE:
262 		if (ifr->ifr_rdomainid < 0 ||
263 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
264 		    !rtable_exists(ifr->ifr_rdomainid)) {
265 			error = EINVAL;
266 			break;
267 		}
268 		sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
269 		break;
270 
271 	case SIOCGLIFPHYRTABLE:
272 		ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
273 		break;
274 
275 	case SIOCSLIFPHYADDR:
276 		error = etherip_set_tunnel(sc, (struct if_laddrreq *)data);
277 		break;
278 	case SIOCGLIFPHYADDR:
279 		error = etherip_get_tunnel(sc, (struct if_laddrreq *)data);
280 		break;
281 	case SIOCDIFPHYADDR:
282 		error = etherip_del_tunnel(sc);
283 		break;
284 
285 	case SIOCSLIFPHYTTL:
286 		if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) {
287 			error = EINVAL;
288 			break;
289 		}
290 
291 		/* commit */
292 		sc->sc_ttl = (uint8_t)ifr->ifr_ttl;
293 		break;
294 	case SIOCGLIFPHYTTL:
295 		ifr->ifr_ttl = (int)sc->sc_ttl;
296 		break;
297 
298 	case SIOCSLIFPHYDF:
299 		/* commit */
300 		sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
301 		break;
302 	case SIOCGLIFPHYDF:
303 		ifr->ifr_df = sc->sc_df ? 1 : 0;
304 		break;
305 
306 	case SIOCSIFMEDIA:
307 	case SIOCGIFMEDIA:
308 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
309 		break;
310 
311 	default:
312 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
313 		break;
314 	}
315 
316 	return (error);
317 }
318 
319 int
320 etherip_set_tunnel(struct etherip_softc *sc, struct if_laddrreq *req)
321 {
322 	struct sockaddr *src = (struct sockaddr *)&req->addr;
323 	struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
324 	struct sockaddr_in *src4, *dst4;
325 #ifdef INET6
326 	struct sockaddr_in6 *src6, *dst6;
327 	int error;
328 #endif
329 
330 	/* sa_family and sa_len must be equal */
331 	if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
332 		return (EINVAL);
333 
334 	/* validate */
335 	switch (dst->sa_family) {
336 	case AF_INET:
337 		if (dst->sa_len != sizeof(*dst4))
338 			return (EINVAL);
339 
340 		src4 = (struct sockaddr_in *)src;
341 		if (in_nullhost(src4->sin_addr) ||
342 		    IN_MULTICAST(src4->sin_addr.s_addr))
343 			return (EINVAL);
344 
345 		dst4 = (struct sockaddr_in *)dst;
346 		if (in_nullhost(dst4->sin_addr) ||
347 		    IN_MULTICAST(dst4->sin_addr.s_addr))
348 			return (EINVAL);
349 
350 		sc->sc_tunnel.t_src4 = src4->sin_addr;
351 		sc->sc_tunnel.t_dst4 = dst4->sin_addr;
352 		break;
353 #ifdef INET6
354 	case AF_INET6:
355 		if (dst->sa_len != sizeof(*dst6))
356 			return (EINVAL);
357 
358 		src6 = (struct sockaddr_in6 *)src;
359 		if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) ||
360 		    IN6_IS_ADDR_MULTICAST(&src6->sin6_addr))
361 			return (EINVAL);
362 
363 		dst6 = (struct sockaddr_in6 *)dst;
364 		if (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) ||
365 		    IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
366 			return (EINVAL);
367 
368 		error = in6_embedscope(&sc->sc_tunnel.t_src6, src6, NULL);
369 		if (error != 0)
370 			return (error);
371 
372 		error = in6_embedscope(&sc->sc_tunnel.t_dst6, dst6, NULL);
373 		if (error != 0)
374 			return (error);
375 
376 		break;
377 #endif
378 	default:
379 		return (EAFNOSUPPORT);
380 	}
381 
382 	/* commit */
383 	sc->sc_tunnel.t_af = dst->sa_family;
384 
385 	return (0);
386 }
387 
388 int
389 etherip_get_tunnel(struct etherip_softc *sc, struct if_laddrreq *req)
390 {
391 	struct sockaddr *src = (struct sockaddr *)&req->addr;
392 	struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
393 	struct sockaddr_in *sin;
394 #ifdef INET6 /* ifconfig already embeds the scopeid */
395 	struct sockaddr_in6 *sin6;
396 #endif
397 
398 	switch (sc->sc_tunnel.t_af) {
399 	case AF_UNSPEC:
400 		return (EADDRNOTAVAIL);
401 	case AF_INET:
402 		sin = (struct sockaddr_in *)src;
403 		memset(sin, 0, sizeof(*sin));
404 		sin->sin_family = AF_INET;
405 		sin->sin_len = sizeof(*sin);
406 		sin->sin_addr = sc->sc_tunnel.t_src4;
407 
408 		sin = (struct sockaddr_in *)dst;
409 		memset(sin, 0, sizeof(*sin));
410 		sin->sin_family = AF_INET;
411 		sin->sin_len = sizeof(*sin);
412 		sin->sin_addr = sc->sc_tunnel.t_dst4;
413 
414 		break;
415 #ifdef INET6
416 	case AF_INET6:
417 		sin6 = (struct sockaddr_in6 *)src;
418 		memset(sin6, 0, sizeof(*sin6));
419 		sin6->sin6_family = AF_INET6;
420 		sin6->sin6_len = sizeof(*sin6);
421 		in6_recoverscope(sin6, &sc->sc_tunnel.t_src6);
422 
423 		sin6 = (struct sockaddr_in6 *)dst;
424 		memset(sin6, 0, sizeof(*sin6));
425 		sin6->sin6_family = AF_INET6;
426 		sin6->sin6_len = sizeof(*sin6);
427 		in6_recoverscope(sin6, &sc->sc_tunnel.t_dst6);
428 
429 		break;
430 #endif
431 	default:
432 		return (EAFNOSUPPORT);
433 	}
434 
435 	return (0);
436 }
437 
438 int
439 etherip_del_tunnel(struct etherip_softc *sc)
440 {
441 	/* commit */
442 	sc->sc_tunnel.t_af = AF_UNSPEC;
443 
444 	return (0);
445 }
446 
447 int
448 etherip_up(struct etherip_softc *sc)
449 {
450 	struct ifnet *ifp = &sc->sc_ac.ac_if;
451 
452 	NET_ASSERT_LOCKED();
453 
454 	SET(ifp->if_flags, IFF_RUNNING);
455 
456 	return (0);
457 }
458 
459 int
460 etherip_down(struct etherip_softc *sc)
461 {
462 	struct ifnet *ifp = &sc->sc_ac.ac_if;
463 
464 	NET_ASSERT_LOCKED();
465 
466 	CLR(ifp->if_flags, IFF_RUNNING);
467 
468 	return (0);
469 }
470 
471 int
472 ip_etherip_output(struct ifnet *ifp, struct mbuf *m)
473 {
474 	struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
475 	struct etherip_header *eip;
476 	struct ip *ip;
477 
478 	M_PREPEND(m, sizeof(*ip) + sizeof(*eip), M_DONTWAIT);
479 	if (m == NULL) {
480 		etheripstat_inc(etherips_adrops);
481 		return ENOBUFS;
482 	}
483 
484 	ip = mtod(m, struct ip *);
485 	memset(ip, 0, sizeof(struct ip));
486 
487 	ip->ip_v = IPVERSION;
488 	ip->ip_hl = sizeof(*ip) >> 2;
489 	ip->ip_tos = IPTOS_LOWDELAY;
490 	ip->ip_len = htons(m->m_pkthdr.len);
491 	ip->ip_id = htons(ip_randomid());
492 	ip->ip_off = sc->sc_df;
493 	ip->ip_ttl = sc->sc_ttl;
494 	ip->ip_p = IPPROTO_ETHERIP;
495 	ip->ip_src = sc->sc_tunnel.t_src4;
496 	ip->ip_dst = sc->sc_tunnel.t_dst4;
497 
498 	eip = (struct etherip_header *)(ip + 1);
499 	eip->eip_ver = ETHERIP_VERSION;
500 	eip->eip_res = 0;
501 	eip->eip_pad = 0;
502 
503 	m->m_flags &= ~(M_BCAST|M_MCAST);
504 	m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
505 
506 #if NPF > 0
507 	pf_pkt_addr_changed(m);
508 #endif
509 	etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len -
510 	    (sizeof(struct ip) + sizeof(struct etherip_header)));
511 
512 	ip_send(m);
513 
514 	return (0);
515 }
516 
517 int
518 ip_etherip_input(struct mbuf **mp, int *offp, int type, int af)
519 {
520 	struct mbuf *m = *mp;
521 	struct etherip_tunnel key;
522 	struct ip *ip;
523 
524 	ip = mtod(m, struct ip *);
525 
526 	key.t_af = AF_INET;
527 	key.t_src4 = ip->ip_dst;
528 	key.t_dst4 = ip->ip_src;
529 
530 	return (etherip_input(&key, m, *offp));
531 }
532 
533 struct etherip_softc *
534 etherip_find(const struct etherip_tunnel *key)
535 {
536 	struct etherip_tunnel *t;
537 	struct etherip_softc *sc;
538 
539 	TAILQ_FOREACH(t, &etherip_list, t_entry) {
540 		if (etherip_cmp(key, t) != 0)
541 			continue;
542 
543 		sc = (struct etherip_softc *)t;
544 		if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING))
545 			continue;
546 
547 		return (sc);
548 	}
549 
550 	return (NULL);
551 }
552 
553 int
554 etherip_input(struct etherip_tunnel *key, struct mbuf *m, int hlen)
555 {
556 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
557 	struct etherip_softc *sc;
558 	struct ifnet *ifp;
559 	struct etherip_header *eip;
560 
561 	if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
562 		etheripstat_inc(etherips_pdrops);
563 		goto drop;
564 	}
565 
566 	key->t_rtableid = m->m_pkthdr.ph_rtableid;
567 
568 	NET_ASSERT_LOCKED();
569 	sc = etherip_find(key);
570 	if (sc == NULL) {
571 		etheripstat_inc(etherips_noifdrops);
572 		goto drop;
573 	}
574 
575 	m_adj(m, hlen);
576 	m = m_pullup(m, sizeof(*eip));
577 	if (m == NULL) {
578 		etheripstat_inc(etherips_adrops);
579 		return IPPROTO_DONE;
580 	}
581 
582 	eip = mtod(m, struct etherip_header *);
583 	if (eip->eip_ver != ETHERIP_VERSION || eip->eip_pad) {
584 		etheripstat_inc(etherips_adrops);
585 		goto drop;
586 	}
587 
588 	m_adj(m, sizeof(struct etherip_header));
589 
590 	etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len);
591 
592 	m = m_pullup(m, sizeof(struct ether_header));
593 	if (m == NULL) {
594 		etheripstat_inc(etherips_adrops);
595 		return IPPROTO_DONE;
596 	}
597 
598 	ifp = &sc->sc_ac.ac_if;
599 
600 	m->m_flags &= ~(M_BCAST|M_MCAST);
601 	m->m_pkthdr.ph_ifidx = ifp->if_index;
602 	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
603 
604 #if NPF > 0
605 	pf_pkt_addr_changed(m);
606 #endif
607 
608 	ml_enqueue(&ml, m);
609 	if_input(ifp, &ml);
610 	return IPPROTO_DONE;
611 
612 drop:
613 	m_freem(m);
614 	return (IPPROTO_DONE);
615 }
616 
617 #ifdef INET6
618 int
619 ip6_etherip_output(struct ifnet *ifp, struct mbuf *m)
620 {
621 	struct etherip_softc *sc = ifp->if_softc;
622 	struct ip6_hdr *ip6;
623 	struct etherip_header *eip;
624 	uint16_t len;
625 
626 	if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6)) {
627 		m_freem(m);
628 		return (ENETUNREACH);
629 	}
630 
631 	len = m->m_pkthdr.len;
632 
633 	M_PREPEND(m, sizeof(*ip6) + sizeof(*eip), M_DONTWAIT);
634 	if (m == NULL) {
635 		etheripstat_inc(etherips_adrops);
636 		return ENOBUFS;
637 	}
638 
639 	ip6 = mtod(m, struct ip6_hdr *);
640 	ip6->ip6_flow = 0;
641 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
642 	ip6->ip6_vfc |= IPV6_VERSION;
643 	ip6->ip6_nxt  = IPPROTO_ETHERIP;
644 	ip6->ip6_hlim = ip6_defhlim;
645 	ip6->ip6_plen = htons(len);
646 	memcpy(&ip6->ip6_src, &sc->sc_tunnel.t_src6, sizeof(ip6->ip6_src));
647 	memcpy(&ip6->ip6_dst, &sc->sc_tunnel.t_dst6, sizeof(ip6->ip6_dst));
648 
649 	eip = (struct etherip_header *)(ip6 + 1);
650 	eip->eip_ver = ETHERIP_VERSION;
651 	eip->eip_res = 0;
652 	eip->eip_pad = 0;
653 
654 	if (sc->sc_df)
655 		SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
656 
657 	m->m_flags &= ~(M_BCAST|M_MCAST);
658 	m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
659 
660 #if NPF > 0
661 	pf_pkt_addr_changed(m);
662 #endif
663 
664 	etheripstat_pkt(etherips_opackets, etherips_obytes, len);
665 
666 	ip6_send(m);
667 	return (0);
668 }
669 
670 int
671 ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af)
672 {
673 	struct mbuf *m = *mp;
674 	struct etherip_tunnel key;
675 	const struct ip6_hdr *ip6;
676 
677 	ip6 = mtod(m, const struct ip6_hdr *);
678 
679 	key.t_af = AF_INET6;
680 	key.t_src6 = ip6->ip6_dst;
681 	key.t_dst6 = ip6->ip6_src;
682 
683 	return (etherip_input(&key, m, *offp));
684 }
685 #endif /* INET6 */
686 
687 int
688 etherip_sysctl_etheripstat(void *oldp, size_t *oldlenp, void *newp)
689 {
690 	struct etheripstat etheripstat;
691 
692 	CTASSERT(sizeof(etheripstat) == (etherips_ncounters *
693 	    sizeof(uint64_t)));
694 	memset(&etheripstat, 0, sizeof etheripstat);
695 	counters_read(etheripcounters, (uint64_t *)&etheripstat,
696 	    etherips_ncounters);
697 	return (sysctl_rdstruct(oldp, oldlenp, newp, &etheripstat,
698 	    sizeof(etheripstat)));
699 }
700 
701 int
702 etherip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
703     void *newp, size_t newlen)
704 {
705 	int error;
706 
707 	/* All sysctl names at this level are terminal. */
708 	if (namelen != 1)
709 		return ENOTDIR;
710 
711 	switch (name[0]) {
712 	case ETHERIPCTL_ALLOW:
713 		NET_LOCK();
714 		error = sysctl_int(oldp, oldlenp, newp, newlen, &etherip_allow);
715 		NET_UNLOCK();
716 		return (error);
717 	case ETHERIPCTL_STATS:
718 		return (etherip_sysctl_etheripstat(oldp, oldlenp, newp));
719 	default:
720 		break;
721 	}
722 
723 	return ENOPROTOOPT;
724 }
725 
726 static inline int
727 etherip_ip_cmp(int af, const union etherip_addr *a, const union etherip_addr *b)
728 {
729 	switch (af) {
730 #ifdef INET6
731 	case AF_INET6:
732 		return (memcmp(&a->in6, &b->in6, sizeof(a->in6)));
733 		/* FALLTHROUGH */
734 #endif /* INET6 */
735 	case AF_INET:
736 		return (memcmp(&a->in4, &b->in4, sizeof(a->in4)));
737 		break;
738 	default:
739 		panic("%s: unsupported af %d\n", __func__, af);
740 	}
741 
742 	return (0);
743 }
744 
745 static inline int
746 etherip_cmp(const struct etherip_tunnel *a, const struct etherip_tunnel *b)
747 {
748 	int rv;
749 
750 	if (a->t_rtableid > b->t_rtableid)
751 		return (1);
752 	if (a->t_rtableid < b->t_rtableid)
753 		return (-1);
754 
755 	/* sort by address */
756 	if (a->t_af > b->t_af)
757 		return (1);
758 	if (a->t_af < b->t_af)
759 		return (-1);
760 
761 	rv = etherip_ip_cmp(a->t_af, &a->_t_dst, &b->_t_dst);
762 	if (rv != 0)
763 		return (rv);
764 
765 	rv = etherip_ip_cmp(a->t_af, &a->_t_src, &b->_t_src);
766 	if (rv != 0)
767 		return (rv);
768 
769 	return (0);
770 }
771