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