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