xref: /openbsd-src/sys/net/if_etherip.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: if_etherip.c,v 1.29 2018/01/09 15:24:24 bluhm 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 
29 #include <net/if.h>
30 #include <net/if_var.h>
31 #include <net/if_dl.h>
32 #include <net/if_media.h>
33 #include <net/rtable.h>
34 
35 #include <netinet/in.h>
36 #include <netinet/ip.h>
37 #include <netinet/ip_var.h>
38 #include <netinet/if_ether.h>
39 #include <netinet/ip_ether.h>
40 
41 #ifdef INET6
42 #include <netinet/ip6.h>
43 #include <netinet6/ip6_var.h>
44 #endif
45 
46 #if NBPFILTER > 0
47 #include <net/bpf.h>
48 #endif
49 
50 #if NPF > 0
51 #include <net/pfvar.h>
52 #endif
53 
54 #include <net/if_etherip.h>
55 
56 struct etherip_softc {
57 	struct arpcom sc_ac;
58 	struct ifmedia sc_media;
59 	unsigned int sc_rdomain;
60 	struct sockaddr_storage sc_src;
61 	struct sockaddr_storage sc_dst;
62 	LIST_ENTRY(etherip_softc) sc_entry;
63 };
64 
65 LIST_HEAD(, etherip_softc) etherip_softc_list;
66 
67 /*
68  * We can control the acceptance of EtherIP packets by altering the sysctl
69  * net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
70  */
71 int etherip_allow = 0;
72 
73 struct cpumem *etheripcounters;
74 
75 void etheripattach(int);
76 int etherip_clone_create(struct if_clone *, int);
77 int etherip_clone_destroy(struct ifnet *);
78 int etherip_ioctl(struct ifnet *, u_long, caddr_t);
79 void etherip_start(struct ifnet *);
80 int etherip_media_change(struct ifnet *);
81 void etherip_media_status(struct ifnet *, struct ifmediareq *);
82 int etherip_set_tunnel_addr(struct ifnet *, struct sockaddr_storage *,
83    struct sockaddr_storage *);
84 
85 struct if_clone	etherip_cloner = IF_CLONE_INITIALIZER("etherip",
86     etherip_clone_create, etherip_clone_destroy);
87 
88 
89 void
90 etheripattach(int count)
91 {
92 	if_clone_attach(&etherip_cloner);
93 	etheripcounters = counters_alloc(etherips_ncounters);
94 }
95 
96 int
97 etherip_clone_create(struct if_clone *ifc, int unit)
98 {
99 	struct ifnet *ifp;
100 	struct etherip_softc *sc;
101 
102 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
103 	ifp = &sc->sc_ac.ac_if;
104 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "etherip%d", unit);
105 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
106 	ether_fakeaddr(ifp);
107 
108 	ifp->if_softc = sc;
109 	ifp->if_ioctl = etherip_ioctl;
110 	ifp->if_start = etherip_start;
111 	ifp->if_xflags = IFXF_CLONED;
112 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
113 
114 	ifp->if_capabilities = IFCAP_VLAN_MTU;
115 
116 	ifmedia_init(&sc->sc_media, 0, etherip_media_change,
117 	    etherip_media_status);
118 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
119 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
120 
121 	if_attach(ifp);
122 	ether_ifattach(ifp);
123 
124 	LIST_INSERT_HEAD(&etherip_softc_list, sc, sc_entry);
125 
126 	return 0;
127 }
128 
129 int
130 etherip_clone_destroy(struct ifnet *ifp)
131 {
132 	struct etherip_softc *sc = ifp->if_softc;
133 
134 	LIST_REMOVE(sc, sc_entry);
135 
136 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
137 	ether_ifdetach(ifp);
138 	if_detach(ifp);
139 	free(sc, M_DEVBUF, sizeof(*sc));
140 
141 	return 0;
142 }
143 
144 int
145 etherip_media_change(struct ifnet *ifp)
146 {
147 	return 0;
148 }
149 
150 void
151 etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr)
152 {
153 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
154 	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
155 }
156 
157 void
158 etherip_start(struct ifnet *ifp)
159 {
160 	struct etherip_softc *sc = ifp->if_softc;
161 	struct mbuf *m;
162 	int error;
163 
164 	for (;;) {
165 		IFQ_DEQUEUE(&ifp->if_snd, m);
166 		if (m == NULL)
167 			break;
168 
169 #if NBPFILTER > 0
170 		if (ifp->if_bpf)
171 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
172 #endif
173 		if (sc->sc_src.ss_family == AF_UNSPEC ||
174 		    sc->sc_dst.ss_family == AF_UNSPEC) {
175 			m_freem(m);
176 			continue;
177 		}
178 
179 		switch (sc->sc_src.ss_family) {
180 		case AF_INET:
181 			error = ip_etherip_output(ifp, m);
182 			break;
183 #ifdef INET6
184 		case AF_INET6:
185 			error = ip6_etherip_output(ifp, m);
186 			break;
187 #endif
188 		default:
189 			unhandled_af(sc->sc_src.ss_family);
190 		}
191 
192 		if (error)
193 			ifp->if_oerrors++;
194 	}
195 
196 }
197 
198 
199 int
200 etherip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
201 {
202 	struct etherip_softc *sc = ifp->if_softc;
203 	struct if_laddrreq *lifr = (struct if_laddrreq *)data;
204 	struct ifreq *ifr = (struct ifreq *)data;
205 	struct sockaddr_storage *src, *dst;
206 	struct proc *p = curproc;
207 	int error = 0;
208 
209 	switch (cmd) {
210 	case SIOCSIFADDR:
211 		ifp->if_flags |= IFF_UP;
212 		/* FALLTHROUGH */
213 
214 	case SIOCSIFFLAGS:
215 		if (ifp->if_flags & IFF_UP)
216 			ifp->if_flags |= IFF_RUNNING;
217 		else
218 			ifp->if_flags &= ~IFF_RUNNING;
219 
220 		break;
221 
222 	case SIOCSLIFPHYRTABLE:
223 		if ((error = suser(p, 0)) != 0)
224 			break;
225 
226 		if (ifr->ifr_rdomainid < 0 ||
227 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
228 		    !rtable_exists(ifr->ifr_rdomainid)) {
229 			error = EINVAL;
230 			break;
231 		}
232 		sc->sc_rdomain = ifr->ifr_rdomainid;
233 		break;
234 
235 	case SIOCGLIFPHYRTABLE:
236 		ifr->ifr_rdomainid = sc->sc_rdomain;
237 		break;
238 
239 	case SIOCSLIFPHYADDR:
240 		if ((error = suser(p, 0)) != 0)
241 			break;
242 
243 		src = &lifr->addr;
244 		dst = &lifr->dstaddr;
245 		if (src->ss_family == AF_UNSPEC || dst->ss_family == AF_UNSPEC)
246 			return EADDRNOTAVAIL;
247 
248 		switch (src->ss_family) {
249 		case AF_INET:
250 			if (src->ss_len != sizeof(struct sockaddr_in) ||
251 			    dst->ss_len != sizeof(struct sockaddr_in))
252 				return EINVAL;
253 			break;
254 #ifdef INET6
255 		case AF_INET6:
256 			if (src->ss_len != sizeof(struct sockaddr_in6) ||
257 			    dst->ss_len != sizeof(struct sockaddr_in6))
258 				return EINVAL;
259 			break;
260 #endif
261 		default:
262 			return EAFNOSUPPORT;
263 		}
264 
265 		error = etherip_set_tunnel_addr(ifp, src, dst);
266 		break;
267 
268 	case SIOCDIFPHYADDR:
269 		if ((error = suser(p, 0)) != 0)
270 			break;
271 
272 		ifp->if_flags &= ~IFF_RUNNING;
273 		memset(&sc->sc_src, 0, sizeof(sc->sc_src));
274 		memset(&sc->sc_dst, 0, sizeof(sc->sc_dst));
275 		break;
276 
277 	case SIOCGLIFPHYADDR:
278 		if (sc->sc_dst.ss_family == AF_UNSPEC)
279 			return EADDRNOTAVAIL;
280 
281 		memset(&lifr->addr, 0, sizeof(lifr->addr));
282 		memset(&lifr->dstaddr, 0, sizeof(lifr->dstaddr));
283 		memcpy(&lifr->addr, &sc->sc_src, sc->sc_src.ss_len);
284 		memcpy(&lifr->dstaddr, &sc->sc_dst, sc->sc_dst.ss_len);
285 
286 		break;
287 
288 	case SIOCSIFMEDIA:
289 	case SIOCGIFMEDIA:
290 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
291 		break;
292 
293 	default:
294 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
295 		break;
296 	}
297 
298 	return error;
299 }
300 
301 int
302 etherip_set_tunnel_addr(struct ifnet *ifp, struct sockaddr_storage *src,
303     struct sockaddr_storage *dst)
304 {
305 	struct etherip_softc *sc, *tsc;
306 	int error = 0;
307 
308 	sc  = ifp->if_softc;
309 
310 	LIST_FOREACH(tsc, &etherip_softc_list, sc_entry) {
311 		if (tsc == sc)
312 			continue;
313 
314 		if (tsc->sc_src.ss_family != src->ss_family ||
315 		    tsc->sc_dst.ss_family != dst->ss_family ||
316 		    tsc->sc_src.ss_len != src->ss_len ||
317 		    tsc->sc_dst.ss_len != dst->ss_len)
318 			continue;
319 
320 		if (tsc->sc_rdomain == sc->sc_rdomain &&
321 		    memcmp(&tsc->sc_dst, dst, dst->ss_len) == 0 &&
322 		    memcmp(&tsc->sc_src, src, src->ss_len) == 0) {
323 			error = EADDRNOTAVAIL;
324 			goto out;
325 		}
326 	}
327 
328 	memcpy(&sc->sc_src, src, src->ss_len);
329 	memcpy(&sc->sc_dst, dst, dst->ss_len);
330 out:
331 	return error;
332 }
333 
334 int
335 ip_etherip_output(struct ifnet *ifp, struct mbuf *m)
336 {
337 	struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
338 	struct sockaddr_in *src, *dst;
339 	struct etherip_header *eip;
340 	struct ip *ip;
341 
342 	src = (struct sockaddr_in *)&sc->sc_src;
343 	dst = (struct sockaddr_in *)&sc->sc_dst;
344 
345 	if (src == NULL || dst == NULL ||
346 	    src->sin_family != AF_INET || dst->sin_family != AF_INET) {
347 		m_freem(m);
348 		return EAFNOSUPPORT;
349 	}
350 	if (dst->sin_addr.s_addr == INADDR_ANY) {
351 		m_freem(m);
352 		return ENETUNREACH;
353 	}
354 
355 	/*
356 	 * Remove multicast and broadcast flags or encapsulated packet
357 	 * ends up as multicast or broadcast packet.
358 	 */
359 	m->m_flags &= ~(M_BCAST|M_MCAST);
360 
361 	M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
362 	if (m == NULL) {
363 		etheripstat_inc(etherips_adrops);
364 		return ENOBUFS;
365 	}
366 	eip = mtod(m, struct etherip_header *);
367 	eip->eip_ver = ETHERIP_VERSION;
368 	eip->eip_res = 0;
369 	eip->eip_pad = 0;
370 
371 	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
372 	if (m == NULL) {
373 		etheripstat_inc(etherips_adrops);
374 		return ENOBUFS;
375 	}
376 	ip = mtod(m, struct ip *);
377 	memset(ip, 0, sizeof(struct ip));
378 
379 	ip->ip_v = IPVERSION;
380 	ip->ip_hl = sizeof(struct ip) >> 2;
381 	ip->ip_id = htons(ip_randomid());
382 	ip->ip_tos = IPTOS_LOWDELAY;
383 	ip->ip_p = IPPROTO_ETHERIP;
384 	ip->ip_len = htons(m->m_pkthdr.len);
385 	ip->ip_ttl = IPDEFTTL;
386 	ip->ip_src = src->sin_addr;
387 	ip->ip_dst = dst->sin_addr;
388 
389 	m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
390 
391 #if NPF > 0
392 	pf_pkt_addr_changed(m);
393 #endif
394 	etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len -
395 	    (sizeof(struct ip) + sizeof(struct etherip_header)));
396 
397 	return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0);
398 }
399 
400 int
401 ip_etherip_input(struct mbuf **mp, int *offp, int proto, int af)
402 {
403 	struct mbuf *m = *mp;
404 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
405 	struct etherip_softc *sc;
406 	const struct ip *ip;
407 	struct etherip_header *eip;
408 	struct sockaddr_in *src, *dst;
409 	struct ifnet *ifp = NULL;
410 
411 	ip = mtod(m, struct ip *);
412 
413 	if (ip->ip_p != IPPROTO_ETHERIP) {
414 		m_freem(m);
415 		ipstat_inc(ips_noproto);
416 		return IPPROTO_DONE;
417 	}
418 
419 	if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
420 		m_freem(m);
421 		etheripstat_inc(etherips_pdrops);
422 		return IPPROTO_DONE;
423 	}
424 
425 	NET_ASSERT_LOCKED();
426 	LIST_FOREACH(sc, &etherip_softc_list, sc_entry) {
427 		if (sc->sc_src.ss_family != AF_INET ||
428 		    sc->sc_dst.ss_family != AF_INET)
429 			continue;
430 
431 		src = (struct sockaddr_in *)&sc->sc_src;
432 		dst = (struct sockaddr_in *)&sc->sc_dst;
433 
434 		if (sc->sc_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid) ||
435 		    src->sin_addr.s_addr != ip->ip_dst.s_addr ||
436 		    dst->sin_addr.s_addr != ip->ip_src.s_addr)
437 			continue;
438 
439 		ifp = &sc->sc_ac.ac_if;
440 		break;
441 	}
442 
443 	if (ifp == NULL) {
444 		etheripstat_inc(etherips_noifdrops);
445 		m_freem(m);
446 		return IPPROTO_DONE;
447 	}
448 
449 	m_adj(m, *offp);
450 	m = *mp = m_pullup(m, sizeof(struct etherip_header));
451 	if (m == NULL) {
452 		etheripstat_inc(etherips_adrops);
453 		return IPPROTO_DONE;
454 	}
455 
456 	eip = mtod(m, struct etherip_header *);
457 	if (eip->eip_ver != ETHERIP_VERSION || eip->eip_pad) {
458 		etheripstat_inc(etherips_adrops);
459 		m_freem(m);
460 		return IPPROTO_DONE;
461 	}
462 
463 	etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len -
464 	    sizeof(struct etherip_header));
465 
466 	m_adj(m, sizeof(struct etherip_header));
467 	m = *mp = m_pullup(m, sizeof(struct ether_header));
468 	if (m == NULL) {
469 		etheripstat_inc(etherips_adrops);
470 		return IPPROTO_DONE;
471 	}
472 	m->m_flags &= ~(M_BCAST|M_MCAST);
473 
474 #if NPF > 0
475 	pf_pkt_addr_changed(m);
476 #endif
477 
478 	ml_enqueue(&ml, m);
479 	if_input(ifp, &ml);
480 	return IPPROTO_DONE;
481 }
482 
483 #ifdef INET6
484 int
485 ip6_etherip_output(struct ifnet *ifp, struct mbuf *m)
486 {
487 	struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc;
488 	struct sockaddr_in6 *src, *dst;
489 	struct etherip_header *eip;
490 	struct ip6_hdr *ip6;
491 	int error;
492 
493 	src = (struct sockaddr_in6 *)&sc->sc_src;
494 	dst = (struct sockaddr_in6 *)&sc->sc_dst;
495 
496 	if (src == NULL || dst == NULL ||
497 	    src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6) {
498 		error = EAFNOSUPPORT;
499 		goto drop;
500 	}
501 	if (IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) {
502 		error = ENETUNREACH;
503 		goto drop;
504 	}
505 
506 	/*
507 	 * Remove multicast and broadcast flags or encapsulated packet
508 	 * ends up as multicast or broadcast packet.
509 	 */
510 	m->m_flags &= ~(M_BCAST|M_MCAST);
511 
512 	M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
513 	if (m == NULL) {
514 		etheripstat_inc(etherips_adrops);
515 		return ENOBUFS;
516 	}
517 	eip = mtod(m, struct etherip_header *);
518 	eip->eip_ver = ETHERIP_VERSION;
519 	eip->eip_res = 0;
520 	eip->eip_pad = 0;
521 
522 	M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
523 	if (m == NULL) {
524 		etheripstat_inc(etherips_adrops);
525 		return ENOBUFS;
526 	}
527 	ip6 = mtod(m, struct ip6_hdr *);
528 	ip6->ip6_flow = 0;
529 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
530 	ip6->ip6_vfc |= IPV6_VERSION;
531 	ip6->ip6_nxt  = IPPROTO_ETHERIP;
532 	ip6->ip6_hlim = ip6_defhlim;
533 	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
534 	error = in6_embedscope(&ip6->ip6_src, src, NULL);
535 	if (error != 0)
536 		goto drop;
537 	error = in6_embedscope(&ip6->ip6_dst, dst, NULL);
538 	if (error != 0)
539 		goto drop;
540 
541 	m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
542 
543 #if NPF > 0
544 	pf_pkt_addr_changed(m);
545 #endif
546 	etheripstat_pkt(etherips_opackets, etherips_obytes, m->m_pkthdr.len -
547 	    (sizeof(struct ip6_hdr) + sizeof(struct etherip_header)));
548 
549 	return ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL);
550 
551 drop:
552 	m_freem(m);
553 	return (error);
554 }
555 
556 int
557 ip6_etherip_input(struct mbuf **mp, int *offp, int proto, int af)
558 {
559 	struct mbuf *m = *mp;
560 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
561 	struct etherip_softc *sc;
562 	const struct ip6_hdr *ip6;
563 	struct etherip_header *eip;
564 	struct sockaddr_in6 ipsrc, ipdst;
565 	struct sockaddr_in6 *src6, *dst6;
566 	struct ifnet *ifp = NULL;
567 
568 
569 	if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
570 		m_freem(m);
571 		etheripstat_inc(etherips_pdrops);
572 		return IPPROTO_NONE;
573 	}
574 
575 	ip6 = mtod(m, const struct ip6_hdr *);
576 	in6_recoverscope(&ipsrc, &ip6->ip6_src);
577 	in6_recoverscope(&ipdst, &ip6->ip6_dst);
578 
579 	NET_ASSERT_LOCKED();
580 	LIST_FOREACH(sc, &etherip_softc_list, sc_entry) {
581 		if (sc->sc_src.ss_family != AF_INET6 ||
582 		    sc->sc_dst.ss_family != AF_INET6)
583 			continue;
584 
585 		src6 = (struct sockaddr_in6 *)&sc->sc_src;
586 		dst6 = (struct sockaddr_in6 *)&sc->sc_dst;
587 
588 		if (IN6_ARE_ADDR_EQUAL(&src6->sin6_addr, &ipdst.sin6_addr) &&
589 		    src6->sin6_scope_id == ipdst.sin6_scope_id &&
590 		    IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ipsrc.sin6_addr) &&
591 		    dst6->sin6_scope_id == ipsrc.sin6_scope_id) {
592 			ifp = &sc->sc_ac.ac_if;
593 			break;
594 		}
595 	}
596 
597 	if (ifp == NULL) {
598 		etheripstat_inc(etherips_noifdrops);
599 		m_freem(m);
600 		return IPPROTO_DONE;
601 	}
602 
603 	m_adj(m, *offp);
604 	m = *mp = m_pullup(m, sizeof(struct etherip_header));
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 		m_freem(m);
614 		return IPPROTO_DONE;
615 	}
616 	etheripstat_pkt(etherips_ipackets, etherips_ibytes, m->m_pkthdr.len -
617 	    sizeof(struct etherip_header));
618 
619 	m_adj(m, sizeof(struct etherip_header));
620 	m = *mp = m_pullup(m, sizeof(struct ether_header));
621 	if (m == NULL) {
622 		etheripstat_inc(etherips_adrops);
623 		return IPPROTO_DONE;
624 	}
625 
626 	m->m_flags &= ~(M_BCAST|M_MCAST);
627 
628 #if NPF > 0
629 	pf_pkt_addr_changed(m);
630 #endif
631 
632 	ml_enqueue(&ml, m);
633 	if_input(ifp, &ml);
634 	return IPPROTO_DONE;
635 }
636 #endif /* INET6 */
637 
638 int
639 etherip_sysctl_etheripstat(void *oldp, size_t *oldlenp, void *newp)
640 {
641 	struct etheripstat etheripstat;
642 
643 	CTASSERT(sizeof(etheripstat) == (etherips_ncounters *
644 	    sizeof(uint64_t)));
645 	memset(&etheripstat, 0, sizeof etheripstat);
646 	counters_read(etheripcounters, (uint64_t *)&etheripstat,
647 	    etherips_ncounters);
648 	return (sysctl_rdstruct(oldp, oldlenp, newp, &etheripstat,
649 	    sizeof(etheripstat)));
650 }
651 
652 int
653 etherip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
654     void *newp, size_t newlen)
655 {
656 	int error;
657 
658 	/* All sysctl names at this level are terminal. */
659 	if (namelen != 1)
660 		return ENOTDIR;
661 
662 	switch (name[0]) {
663 	case ETHERIPCTL_ALLOW:
664 		NET_LOCK();
665 		error = sysctl_int(oldp, oldlenp, newp, newlen, &etherip_allow);
666 		NET_UNLOCK();
667 		return (error);
668 	case ETHERIPCTL_STATS:
669 		return (etherip_sysctl_etheripstat(oldp, oldlenp, newp));
670 	default:
671 		break;
672 	}
673 
674 	return ENOPROTOOPT;
675 }
676