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