Line data Source code
1 : /* $OpenBSD: if_gif.c,v 1.116 2018/04/18 13:24:07 bluhm Exp $ */
2 : /* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : #include <sys/param.h>
34 : #include <sys/systm.h>
35 : #include <sys/mbuf.h>
36 : #include <sys/socket.h>
37 : #include <sys/sockio.h>
38 : #include <sys/syslog.h>
39 : #include <sys/queue.h>
40 :
41 : #include <net/if.h>
42 : #include <net/if_var.h>
43 : #include <net/if_types.h>
44 : #include <net/route.h>
45 :
46 : #include <netinet/in.h>
47 : #include <netinet/in_var.h>
48 : #include <netinet/ip.h>
49 : #include <netinet/ip_ether.h>
50 : #include <netinet/ip_var.h>
51 : #include <netinet/ip_ipip.h>
52 : #include <netinet/ip_ecn.h>
53 :
54 : #ifdef INET6
55 : #include <netinet6/in6_var.h>
56 : #include <netinet/ip6.h>
57 : #include <netinet6/ip6_var.h>
58 : #endif /* INET6 */
59 :
60 : #include <net/if_gif.h>
61 :
62 : #include "bpfilter.h"
63 : #if NBPFILTER > 0
64 : #include <net/bpf.h>
65 : #endif
66 :
67 : #ifdef MPLS
68 : #include <netmpls/mpls.h>
69 : #endif
70 :
71 : #include "pf.h"
72 : #if NPF > 0
73 : #include <net/pfvar.h>
74 : #endif
75 :
76 : #define GIF_MTU (1280) /* Default MTU */
77 : #define GIF_MTU_MIN (1280) /* Minimum MTU */
78 : #define GIF_MTU_MAX (8192) /* Maximum MTU */
79 :
80 : union gif_addr {
81 : struct in6_addr in6;
82 : struct in_addr in4;
83 : };
84 :
85 : struct gif_tunnel {
86 : TAILQ_ENTRY(gif_tunnel) t_entry;
87 :
88 : union gif_addr t_src;
89 : #define t_src4 t_src.in4
90 : #define t_src6 t_src.in6
91 : union gif_addr t_dst;
92 : #define t_dst4 t_dst.in4
93 : #define t_dst6 t_dst.in6
94 : u_int t_rtableid;
95 :
96 : sa_family_t t_af;
97 : };
98 :
99 : TAILQ_HEAD(gif_list, gif_tunnel);
100 :
101 : static inline int gif_cmp(const struct gif_tunnel *,
102 : const struct gif_tunnel *);
103 :
104 : struct gif_softc {
105 : struct gif_tunnel sc_tunnel; /* must be first */
106 : struct ifnet sc_if;
107 : uint16_t sc_df;
108 : int sc_ttl;
109 : };
110 :
111 : struct gif_list gif_list = TAILQ_HEAD_INITIALIZER(gif_list);
112 :
113 : void gifattach(int);
114 : int gif_clone_create(struct if_clone *, int);
115 : int gif_clone_destroy(struct ifnet *);
116 :
117 : void gif_start(struct ifnet *);
118 : int gif_ioctl(struct ifnet *, u_long, caddr_t);
119 : int gif_output(struct ifnet *, struct mbuf *, struct sockaddr *,
120 : struct rtentry *);
121 : int gif_send(struct gif_softc *, struct mbuf *, uint8_t, uint8_t, uint8_t);
122 :
123 : int gif_up(struct gif_softc *);
124 : int gif_down(struct gif_softc *);
125 : int gif_set_tunnel(struct gif_softc *, struct if_laddrreq *);
126 : int gif_get_tunnel(struct gif_softc *, struct if_laddrreq *);
127 : int gif_del_tunnel(struct gif_softc *);
128 : int in_gif_output(struct ifnet *, int, struct mbuf **);
129 : int in6_gif_output(struct ifnet *, int, struct mbuf **);
130 : int gif_input(struct gif_tunnel *, struct mbuf **, int *, int, int,
131 : uint8_t, uint8_t);
132 :
133 : /*
134 : * gif global variable definitions
135 : */
136 : struct if_clone gif_cloner =
137 : IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
138 :
139 : void
140 0 : gifattach(int count)
141 : {
142 0 : if_clone_attach(&gif_cloner);
143 0 : }
144 :
145 : int
146 0 : gif_clone_create(struct if_clone *ifc, int unit)
147 : {
148 : struct gif_softc *sc;
149 : struct ifnet *ifp;
150 :
151 0 : sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
152 0 : ifp = &sc->sc_if;
153 :
154 0 : sc->sc_df = htons(0);
155 0 : sc->sc_ttl = ip_defttl;
156 :
157 0 : snprintf(ifp->if_xname, sizeof(ifp->if_xname),
158 0 : "%s%d", ifc->ifc_name, unit);
159 :
160 0 : ifp->if_mtu = GIF_MTU;
161 0 : ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
162 0 : ifp->if_xflags = IFXF_CLONED;
163 0 : ifp->if_ioctl = gif_ioctl;
164 0 : ifp->if_start = gif_start;
165 0 : ifp->if_output = gif_output;
166 0 : ifp->if_rtrequest = p2p_rtrequest;
167 0 : ifp->if_type = IFT_GIF;
168 0 : IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
169 0 : ifp->if_softc = sc;
170 :
171 0 : if_attach(ifp);
172 0 : if_alloc_sadl(ifp);
173 :
174 : #if NBPFILTER > 0
175 0 : bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
176 : #endif
177 :
178 0 : NET_LOCK();
179 0 : TAILQ_INSERT_TAIL(&gif_list, &sc->sc_tunnel, t_entry);
180 0 : NET_UNLOCK();
181 :
182 0 : return (0);
183 : }
184 :
185 : int
186 0 : gif_clone_destroy(struct ifnet *ifp)
187 : {
188 0 : struct gif_softc *sc = ifp->if_softc;
189 :
190 0 : NET_LOCK();
191 0 : if (ISSET(ifp->if_flags, IFF_RUNNING))
192 0 : gif_down(sc);
193 :
194 0 : TAILQ_REMOVE(&gif_list, &sc->sc_tunnel, t_entry);
195 0 : NET_UNLOCK();
196 :
197 0 : if_detach(ifp);
198 :
199 0 : free(sc, M_DEVBUF, sizeof(*sc));
200 :
201 0 : return (0);
202 : }
203 :
204 : void
205 0 : gif_start(struct ifnet *ifp)
206 : {
207 0 : struct gif_softc *sc = ifp->if_softc;
208 : struct mbuf *m;
209 : #if NBPFILTER > 0
210 : caddr_t if_bpf;
211 : #endif
212 : uint8_t proto, ttl, tos;
213 : int ttloff, tttl;
214 :
215 0 : tttl = sc->sc_ttl;
216 :
217 0 : while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
218 : #if NBPFILTER > 0
219 0 : if_bpf = ifp->if_bpf;
220 0 : if (if_bpf) {
221 0 : bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, m,
222 : BPF_DIRECTION_OUT);
223 0 : }
224 : #endif
225 :
226 0 : switch (m->m_pkthdr.ph_family) {
227 : case AF_INET: {
228 : struct ip *ip;
229 :
230 0 : m = m_pullup(m, sizeof(*ip));
231 0 : if (m == NULL)
232 0 : continue;
233 :
234 0 : ip = mtod(m, struct ip *);
235 0 : tos = ip->ip_tos;
236 :
237 : ttloff = offsetof(struct ip, ip_ttl);
238 : proto = IPPROTO_IPV4;
239 0 : break;
240 : }
241 : #ifdef INET6
242 : case AF_INET6: {
243 : struct ip6_hdr *ip6;
244 :
245 0 : m = m_pullup(m, sizeof(*ip6));
246 0 : if (m == NULL)
247 0 : continue;
248 :
249 0 : ip6 = mtod(m, struct ip6_hdr *);
250 0 : tos = ntohl(ip6->ip6_flow >> 20);
251 :
252 : ttloff = offsetof(struct ip6_hdr, ip6_hlim);
253 : proto = IPPROTO_IPV6;
254 0 : break;
255 : }
256 : #endif
257 : #ifdef MPLS
258 : case AF_MPLS:
259 : ttloff = 3;
260 : tos = 0;
261 :
262 : proto = IPPROTO_MPLS;
263 0 : break;
264 : #endif
265 : default:
266 0 : unhandled_af(m->m_pkthdr.ph_family);
267 : }
268 :
269 0 : if (tttl == -1) {
270 0 : m = m_pullup(m, ttloff + 1);
271 0 : if (m == NULL)
272 0 : continue;
273 :
274 0 : ttl = *(m->m_data + ttloff);
275 0 : } else
276 0 : ttl = tttl;
277 :
278 0 : gif_send(sc, m, proto, ttl, tos);
279 : }
280 0 : }
281 :
282 : int
283 0 : gif_send(struct gif_softc *sc, struct mbuf *m,
284 : uint8_t proto, uint8_t ttl, uint8_t otos)
285 : {
286 0 : uint8_t itos = 0;
287 :
288 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
289 0 : m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
290 :
291 : #if NPF > 0
292 0 : pf_pkt_addr_changed(m);
293 : #endif
294 :
295 0 : ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
296 :
297 0 : switch (sc->sc_tunnel.t_af) {
298 : case AF_INET: {
299 : struct ip *ip;
300 :
301 0 : if (in_nullhost(sc->sc_tunnel.t_dst4))
302 0 : goto drop;
303 :
304 0 : m = m_prepend(m, sizeof(*ip), M_DONTWAIT);
305 0 : if (m == NULL)
306 0 : return (-1);
307 :
308 0 : ip = mtod(m, struct ip *);
309 0 : ip->ip_off = sc->sc_df;
310 0 : ip->ip_tos = otos;
311 0 : ip->ip_len = htons(m->m_pkthdr.len);
312 0 : ip->ip_ttl = ttl;
313 0 : ip->ip_p = proto;
314 0 : ip->ip_src = sc->sc_tunnel.t_src4;
315 0 : ip->ip_dst = sc->sc_tunnel.t_dst4;
316 :
317 0 : ip_send(m);
318 0 : break;
319 : }
320 : #ifdef INET6
321 : case AF_INET6: {
322 : struct ip6_hdr *ip6;
323 0 : int len = m->m_pkthdr.len;
324 : uint32_t flow;
325 :
326 0 : if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6))
327 0 : goto drop;
328 :
329 0 : m = m_prepend(m, sizeof(*ip6), M_DONTWAIT);
330 0 : if (m == NULL)
331 0 : return (-1);
332 :
333 0 : flow = otos << 20;
334 0 : if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID))
335 0 : flow |= m->m_pkthdr.ph_flowid & M_FLOWID_MASK;
336 :
337 0 : ip6 = mtod(m, struct ip6_hdr *);
338 0 : ip6->ip6_flow = htonl(flow);
339 0 : ip6->ip6_vfc |= IPV6_VERSION;
340 0 : ip6->ip6_plen = htons(len);
341 0 : ip6->ip6_nxt = proto;
342 0 : ip6->ip6_hlim = ttl;
343 0 : ip6->ip6_src = sc->sc_tunnel.t_src6;
344 0 : ip6->ip6_dst = sc->sc_tunnel.t_dst6;
345 :
346 0 : if (sc->sc_df)
347 0 : SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
348 :
349 0 : ip6_send(m);
350 0 : break;
351 : }
352 : #endif
353 : default:
354 0 : m_freem(m);
355 0 : break;
356 : }
357 :
358 0 : return (0);
359 :
360 : drop:
361 0 : m_freem(m);
362 0 : return (0);
363 0 : }
364 :
365 : int
366 0 : gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
367 : struct rtentry *rt)
368 : {
369 : struct m_tag *mtag;
370 : int error = 0;
371 :
372 0 : if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
373 : error = ENETDOWN;
374 0 : goto drop;
375 : }
376 :
377 0 : switch (dst->sa_family) {
378 : case AF_INET:
379 : #ifdef INET6
380 : case AF_INET6:
381 : #endif
382 : #ifdef MPLS
383 : case AF_MPLS:
384 : #endif
385 : break;
386 : default:
387 : error = EAFNOSUPPORT;
388 0 : goto drop;
389 : }
390 :
391 : /* Try to limit infinite recursion through misconfiguration. */
392 0 : for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
393 0 : mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
394 0 : if (memcmp((caddr_t)(mtag + 1), &ifp->if_index,
395 0 : sizeof(ifp->if_index)) == 0) {
396 : error = EIO;
397 0 : goto drop;
398 : }
399 : }
400 :
401 0 : mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
402 0 : if (mtag == NULL) {
403 : error = ENOBUFS;
404 0 : goto drop;
405 : }
406 0 : memcpy((caddr_t)(mtag + 1), &ifp->if_index, sizeof(ifp->if_index));
407 0 : m_tag_prepend(m, mtag);
408 :
409 0 : m->m_pkthdr.ph_family = dst->sa_family;
410 :
411 0 : error = if_enqueue(ifp, m);
412 :
413 0 : if (error)
414 0 : ifp->if_oerrors++;
415 0 : return (error);
416 :
417 : drop:
418 0 : m_freem(m);
419 0 : return (error);
420 0 : }
421 :
422 : int
423 0 : gif_up(struct gif_softc *sc)
424 : {
425 0 : NET_ASSERT_LOCKED();
426 :
427 0 : SET(sc->sc_if.if_flags, IFF_RUNNING);
428 :
429 0 : return (0);
430 : }
431 :
432 : int
433 0 : gif_down(struct gif_softc *sc)
434 : {
435 0 : NET_ASSERT_LOCKED();
436 :
437 0 : CLR(sc->sc_if.if_flags, IFF_RUNNING);
438 :
439 : /* barrier? */
440 :
441 0 : return (0);
442 : }
443 :
444 : int
445 0 : gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
446 : {
447 0 : struct gif_softc *sc = ifp->if_softc;
448 0 : struct ifreq *ifr = (struct ifreq *)data;
449 : int error = 0;
450 :
451 0 : switch (cmd) {
452 : case SIOCSIFADDR:
453 0 : SET(ifp->if_flags, IFF_UP);
454 : /* FALLTHROUGH */
455 : case SIOCSIFFLAGS:
456 0 : if (ISSET(ifp->if_flags, IFF_UP)) {
457 0 : if (!ISSET(ifp->if_flags, IFF_RUNNING))
458 0 : error = gif_up(sc);
459 : else
460 : error = 0;
461 : } else {
462 0 : if (ISSET(ifp->if_flags, IFF_RUNNING))
463 0 : error = gif_down(sc);
464 : }
465 : break;
466 :
467 : case SIOCADDMULTI:
468 : case SIOCDELMULTI:
469 : break;
470 :
471 : case SIOCSLIFPHYADDR:
472 0 : error = gif_set_tunnel(sc, (struct if_laddrreq *)data);
473 0 : break;
474 : case SIOCGLIFPHYADDR:
475 0 : error = gif_get_tunnel(sc, (struct if_laddrreq *)data);
476 0 : break;
477 : case SIOCDIFPHYADDR:
478 0 : error = gif_del_tunnel(sc);
479 0 : break;
480 :
481 : case SIOCSIFMTU:
482 0 : if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) {
483 : error = EINVAL;
484 0 : break;
485 : }
486 :
487 0 : ifp->if_mtu = ifr->ifr_mtu;
488 0 : break;
489 :
490 : case SIOCSLIFPHYRTABLE:
491 0 : if (ifr->ifr_rdomainid < 0 ||
492 0 : ifr->ifr_rdomainid > RT_TABLEID_MAX ||
493 0 : !rtable_exists(ifr->ifr_rdomainid)) {
494 : error = EINVAL;
495 0 : break;
496 : }
497 0 : sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
498 0 : break;
499 : case SIOCGLIFPHYRTABLE:
500 0 : ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
501 0 : break;
502 :
503 : case SIOCSLIFPHYTTL:
504 0 : if (ifr->ifr_ttl != -1 &&
505 0 : (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) {
506 : error = EINVAL;
507 0 : break;
508 : }
509 :
510 : /* commit */
511 0 : sc->sc_ttl = ifr->ifr_ttl;
512 0 : break;
513 : case SIOCGLIFPHYTTL:
514 0 : ifr->ifr_ttl = sc->sc_ttl;
515 0 : break;
516 :
517 : case SIOCSLIFPHYDF:
518 : /* commit */
519 0 : sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
520 0 : break;
521 : case SIOCGLIFPHYDF:
522 0 : ifr->ifr_df = sc->sc_df ? 1 : 0;
523 0 : break;
524 :
525 : default:
526 : error = ENOTTY;
527 0 : break;
528 : }
529 :
530 0 : return (error);
531 : }
532 :
533 : int
534 0 : gif_get_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
535 : {
536 0 : struct gif_tunnel *tunnel = &sc->sc_tunnel;
537 0 : struct sockaddr *src = (struct sockaddr *)&req->addr;
538 0 : struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
539 : struct sockaddr_in *sin;
540 : #ifdef INET6 /* ifconfig already embeds the scopeid */
541 : struct sockaddr_in6 *sin6;
542 : #endif
543 :
544 0 : switch (tunnel->t_af) {
545 : case AF_UNSPEC:
546 0 : return (EADDRNOTAVAIL);
547 : case AF_INET:
548 0 : sin = (struct sockaddr_in *)src;
549 0 : memset(sin, 0, sizeof(*sin));
550 0 : sin->sin_family = AF_INET;
551 0 : sin->sin_len = sizeof(*sin);
552 0 : sin->sin_addr = tunnel->t_src4;
553 :
554 0 : sin = (struct sockaddr_in *)dst;
555 0 : memset(sin, 0, sizeof(*sin));
556 0 : sin->sin_family = AF_INET;
557 0 : sin->sin_len = sizeof(*sin);
558 0 : sin->sin_addr = tunnel->t_dst4;
559 :
560 0 : break;
561 :
562 : #ifdef INET6
563 : case AF_INET6:
564 0 : sin6 = (struct sockaddr_in6 *)src;
565 0 : memset(sin6, 0, sizeof(*sin6));
566 0 : sin6->sin6_family = AF_INET6;
567 0 : sin6->sin6_len = sizeof(*sin6);
568 0 : in6_recoverscope(sin6, &tunnel->t_src6);
569 :
570 0 : sin6 = (struct sockaddr_in6 *)dst;
571 0 : memset(sin6, 0, sizeof(*sin6));
572 0 : sin6->sin6_family = AF_INET6;
573 0 : sin6->sin6_len = sizeof(*sin6);
574 0 : in6_recoverscope(sin6, &tunnel->t_dst6);
575 :
576 0 : break;
577 : #endif
578 : default:
579 0 : return (EAFNOSUPPORT);
580 : }
581 :
582 0 : return (0);
583 0 : }
584 :
585 : int
586 0 : gif_set_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
587 : {
588 0 : struct gif_tunnel *tunnel = &sc->sc_tunnel;
589 0 : struct sockaddr *src = (struct sockaddr *)&req->addr;
590 0 : struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
591 : struct sockaddr_in *src4, *dst4;
592 : #ifdef INET6
593 : struct sockaddr_in6 *src6, *dst6;
594 : int error;
595 : #endif
596 :
597 : /* sa_family and sa_len must be equal */
598 0 : if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
599 0 : return (EINVAL);
600 :
601 : /* validate */
602 0 : switch (dst->sa_family) {
603 : case AF_INET:
604 0 : if (dst->sa_len != sizeof(*dst4))
605 0 : return (EINVAL);
606 :
607 0 : src4 = (struct sockaddr_in *)src;
608 0 : if (in_nullhost(src4->sin_addr) ||
609 0 : IN_MULTICAST(src4->sin_addr.s_addr))
610 0 : return (EINVAL);
611 :
612 0 : dst4 = (struct sockaddr_in *)dst;
613 : /* dst4 can be 0.0.0.0 */
614 0 : if (IN_MULTICAST(dst4->sin_addr.s_addr))
615 0 : return (EINVAL);
616 :
617 0 : tunnel->t_src4 = src4->sin_addr;
618 0 : tunnel->t_dst4 = dst4->sin_addr;
619 :
620 0 : break;
621 : #ifdef INET6
622 : case AF_INET6:
623 0 : if (dst->sa_len != sizeof(*dst6))
624 0 : return (EINVAL);
625 :
626 0 : src6 = (struct sockaddr_in6 *)src;
627 0 : if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) ||
628 0 : IN6_IS_ADDR_MULTICAST(&src6->sin6_addr))
629 0 : return (EINVAL);
630 :
631 0 : dst6 = (struct sockaddr_in6 *)dst;
632 0 : if (IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
633 0 : return (EINVAL);
634 :
635 0 : error = in6_embedscope(&tunnel->t_src6, src6, NULL);
636 0 : if (error != 0)
637 0 : return (error);
638 :
639 0 : error = in6_embedscope(&tunnel->t_dst6, dst6, NULL);
640 0 : if (error != 0)
641 0 : return (error);
642 :
643 : break;
644 : #endif
645 : default:
646 0 : return (EAFNOSUPPORT);
647 : }
648 :
649 : /* commit */
650 0 : tunnel->t_af = dst->sa_family;
651 :
652 0 : return (0);
653 0 : }
654 :
655 : int
656 0 : gif_del_tunnel(struct gif_softc *sc)
657 : {
658 : /* commit */
659 0 : sc->sc_tunnel.t_af = AF_UNSPEC;
660 :
661 0 : return (0);
662 : }
663 :
664 : int
665 0 : in_gif_input(struct mbuf **mp, int *offp, int proto, int af)
666 : {
667 0 : struct mbuf *m = *mp;
668 0 : struct gif_tunnel key;
669 : struct ip *ip;
670 : int rv;
671 :
672 0 : ip = mtod(m, struct ip *);
673 :
674 0 : key.t_af = AF_INET;
675 0 : key.t_src4 = ip->ip_dst;
676 0 : key.t_dst4 = ip->ip_src;
677 :
678 0 : rv = gif_input(&key, mp, offp, proto, af, ip->ip_ttl, ip->ip_tos);
679 0 : if (rv == -1)
680 0 : rv = ipip_input(mp, offp, proto, af);
681 :
682 0 : return (rv);
683 0 : }
684 :
685 : #ifdef INET6
686 : int
687 0 : in6_gif_input(struct mbuf **mp, int *offp, int proto, int af)
688 : {
689 0 : struct mbuf *m = *mp;
690 0 : struct gif_tunnel key;
691 : struct ip6_hdr *ip6;
692 : uint32_t flow;
693 : int rv;
694 :
695 0 : ip6 = mtod(m, struct ip6_hdr *);
696 :
697 0 : key.t_af = AF_INET6;
698 0 : key.t_src6 = ip6->ip6_dst;
699 0 : key.t_dst6 = ip6->ip6_src;
700 :
701 0 : flow = ntohl(ip6->ip6_flow);
702 :
703 0 : rv = gif_input(&key, mp, offp, proto, af, ip6->ip6_hlim,
704 0 : flow >> 20);
705 0 : if (rv == -1)
706 0 : rv = ipip_input(mp, offp, proto, af);
707 :
708 0 : return (rv);
709 0 : }
710 : #endif /* INET6 */
711 :
712 : struct gif_softc *
713 0 : gif_find(const struct gif_tunnel *key)
714 : {
715 : struct gif_tunnel *t;
716 : struct gif_softc *sc;
717 :
718 0 : TAILQ_FOREACH(t, &gif_list, t_entry) {
719 0 : if (gif_cmp(key, t) != 0)
720 : continue;
721 :
722 0 : sc = (struct gif_softc *)t;
723 0 : if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING))
724 : continue;
725 :
726 0 : return (sc);
727 : }
728 :
729 0 : return (NULL);
730 0 : }
731 :
732 : int
733 0 : gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto,
734 : int af, uint8_t ttl, uint8_t otos)
735 : {
736 0 : struct mbuf *m = *mp;
737 : struct gif_softc *sc;
738 : struct ifnet *ifp;
739 : void (*input)(struct ifnet *, struct mbuf *);
740 : int ttloff;
741 0 : uint8_t itos;
742 :
743 : /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */
744 0 : if (m->m_flags & M_TUNNEL) {
745 0 : m->m_flags &= ~M_TUNNEL;
746 0 : return (-1);
747 : }
748 :
749 0 : key->t_rtableid = m->m_pkthdr.ph_rtableid;
750 :
751 0 : sc = gif_find(key);
752 0 : if (sc == NULL) {
753 0 : memset(&key->t_dst, 0, sizeof(key->t_dst));
754 0 : sc = gif_find(key);
755 0 : if (sc == NULL)
756 0 : return (-1);
757 : }
758 :
759 0 : switch (proto) {
760 : case IPPROTO_IPV4: {
761 : struct ip *ip;
762 :
763 0 : m = *mp = m_pullup(m, sizeof(*ip));
764 0 : if (m == NULL)
765 0 : return (IPPROTO_DONE);
766 :
767 0 : ip = mtod(m, struct ip *);
768 :
769 0 : itos = ip->ip_tos;
770 0 : if (ip_ecn_egress(ECN_ALLOWED, &otos, &itos) == 0)
771 0 : goto drop;
772 :
773 0 : ip->ip_tos = itos;
774 :
775 0 : m->m_pkthdr.ph_family = AF_INET;
776 : input = ipv4_input;
777 : ttloff = offsetof(struct ip, ip_ttl);
778 0 : break;
779 : }
780 : #ifdef INET6
781 : case IPPROTO_IPV6: {
782 : struct ip6_hdr *ip6;
783 :
784 0 : m = *mp = m_pullup(m, sizeof(*ip6));
785 0 : if (m == NULL)
786 0 : return (IPPROTO_DONE);
787 :
788 0 : ip6 = mtod(m, struct ip6_hdr *);
789 :
790 0 : itos = ntohl(ip6->ip6_flow) >> 20;
791 0 : if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos))
792 0 : goto drop;
793 :
794 0 : CLR(ip6->ip6_flow, htonl(0xff << 20));
795 0 : SET(ip6->ip6_flow, htonl(itos << 20));
796 :
797 0 : m->m_pkthdr.ph_family = AF_INET6;
798 : input = ipv6_input;
799 : ttloff = offsetof(struct ip6_hdr, ip6_hlim);
800 0 : break;
801 : }
802 : #endif /* INET6 */
803 : #ifdef MPLS
804 : case IPPROTO_MPLS:
805 0 : m->m_pkthdr.ph_family = AF_MPLS;
806 : input = mpls_input;
807 : ttloff = 3;
808 0 : break;
809 : #endif /* MPLS */
810 : default:
811 0 : return (-1);
812 : }
813 :
814 0 : m_adj(m, *offp);
815 :
816 0 : if (sc->sc_ttl == -1) {
817 0 : m = *mp = m_pullup(m, ttloff + 1);
818 0 : if (m == NULL)
819 0 : return (IPPROTO_DONE);
820 :
821 0 : *(m->m_data + ttloff) = ttl;
822 0 : }
823 :
824 0 : ifp = &sc->sc_if;
825 :
826 0 : m->m_flags &= ~(M_MCAST|M_BCAST);
827 0 : m->m_pkthdr.ph_ifidx = ifp->if_index;
828 0 : m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
829 :
830 : #if NPF > 0
831 0 : pf_pkt_addr_changed(m);
832 : #endif
833 :
834 0 : ifp->if_ipackets++;
835 0 : ifp->if_ibytes += m->m_pkthdr.len;
836 :
837 : #if NBPFILTER > 0
838 : {
839 0 : caddr_t if_bpf = ifp->if_bpf;
840 0 : if (if_bpf) {
841 0 : bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family,
842 : m, BPF_DIRECTION_IN);
843 0 : }
844 : }
845 : #endif
846 :
847 0 : *mp = NULL;
848 0 : (*input)(ifp, m);
849 0 : return (IPPROTO_DONE);
850 :
851 : drop:
852 0 : m_freemp(mp);
853 0 : return (IPPROTO_DONE);
854 0 : }
855 :
856 : static inline int
857 0 : gif_ip_cmp(int af, const union gif_addr *a, const union gif_addr *b)
858 : {
859 0 : switch (af) {
860 : #ifdef INET6
861 : case AF_INET6:
862 0 : return (memcmp(&a->in6, &b->in6, sizeof(a->in6)));
863 : #endif /* INET6 */
864 : case AF_INET:
865 0 : return (memcmp(&a->in4, &b->in4, sizeof(a->in4)));
866 : default:
867 0 : panic("%s: unsupported af %d\n", __func__, af);
868 : }
869 :
870 : return (0);
871 0 : }
872 :
873 :
874 : static inline int
875 0 : gif_cmp(const struct gif_tunnel *a, const struct gif_tunnel *b)
876 : {
877 : int rv;
878 :
879 : /* sort by routing table */
880 0 : if (a->t_rtableid > b->t_rtableid)
881 0 : return (1);
882 0 : if (a->t_rtableid < b->t_rtableid)
883 0 : return (-1);
884 :
885 : /* sort by address */
886 0 : if (a->t_af > b->t_af)
887 0 : return (1);
888 0 : if (a->t_af < b->t_af)
889 0 : return (-1);
890 :
891 0 : rv = gif_ip_cmp(a->t_af, &a->t_dst, &b->t_dst);
892 0 : if (rv != 0)
893 0 : return (rv);
894 :
895 0 : rv = gif_ip_cmp(a->t_af, &a->t_src, &b->t_src);
896 0 : if (rv != 0)
897 0 : return (rv);
898 :
899 0 : return (0);
900 0 : }
|