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