44#include <sys/socket.h>
45#include <sys/sockio.h>
48#include <sys/kernel.h>
49#include <sys/syslog.h>
50#include <sys/sysctl.h>
51#include <sys/malloc.h>
54#include <net/ethernet.h>
56#include <net/if_var.h>
60#include <netinet/in.h>
61#include <netinet/in_systm.h>
63#include <netinet/ip.h>
64#include <netinet/ip_ecn.h>
66#include <netinet/ip_encap.h>
67#include <netinet/ip6.h>
74#include <net/if_gif.h>
78#define V_ip6_gif_hlim VNET(ip6_gif_hlim)
82 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0,
83 "Default hop limit for encapsulated packets");
92#define V_ipv6_hashtbl VNET(ipv6_hashtbl)
93#define V_ipv6_srchashtbl VNET(ipv6_srchashtbl)
94#define V_ipv6_list VNET(ipv6_list)
96#define GIF_HASH(src, dst) (V_ipv6_hashtbl[\
97 in6_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
98#define GIF_SRCHASH(src) (V_ipv6_srchashtbl[\
99 fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
100#define GIF_HASH_SC(sc) GIF_HASH(&(sc)->gif_ip6hdr->ip6_src,\
101 &(sc)->gif_ip6hdr->ip6_dst)
107 ret = fnv_32_buf(src,
sizeof(*src), FNV1_32_INIT);
108 return (fnv_32_buf(dst,
sizeof(*dst), ret));
115 struct gif_softc *tmp;
117 if (sc->gif_family == AF_INET6 &&
122 CK_LIST_FOREACH(tmp, &
GIF_HASH(src, dst), chain) {
127 return (EADDRNOTAVAIL);
140 GIF2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
142 GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
154 struct gif_softc *sc;
174 if (sc->gif_options & GIF_IGNORE_SOURCE)
179 CK_LIST_INSERT_HEAD(&
GIF_SRCHASH(&sc->gif_ip6hdr->ip6_src),
188 MPASS(sc->gif_family == AF_INET6);
189 MPASS(sc->gif_options != options);
191 if ((options & GIF_IGNORE_SOURCE) !=
192 (sc->gif_options & GIF_IGNORE_SOURCE)) {
193 CK_LIST_REMOVE(sc, srchash);
194 CK_LIST_REMOVE(sc, chain);
195 sc->gif_options = options;
224 error = EADDRNOTAVAIL;
242 if (error == EADDRNOTAVAIL)
244 if (error == EEXIST) {
249 ip6 = malloc(
sizeof(*ip6), M_GIF, M_WAITOK | M_ZERO);
252 ip6->ip6_vfc = IPV6_VERSION;
253 if (sc->gif_family != 0) {
255 CK_LIST_REMOVE(sc, srchash);
256 CK_LIST_REMOVE(sc, chain);
258 free(sc->gif_hdr, M_GIF);
261 sc->gif_family = AF_INET6;
262 sc->gif_ip6hdr = ip6;
268 if (sc->gif_family != AF_INET6) {
269 error = EADDRNOTAVAIL;
273 memset(src, 0,
sizeof(*src));
277 sc->gif_ip6hdr->ip6_src: sc->gif_ip6hdr->ip6_dst;
278 error = prison_if(curthread->td_ucred, (
struct sockaddr *)src);
282 memset(src, 0,
sizeof(*src));
291 struct gif_softc *sc = ifp->if_softc;
297 len =
sizeof(
struct ip6_hdr);
298#ifndef __NO_STRICT_ALIGNMENT
299 if (proto == IPPROTO_ETHERIP)
300 len += ETHERIP_ALIGN;
302 M_PREPEND(m, len, M_NOWAIT);
305#ifndef __NO_STRICT_ALIGNMENT
306 if (proto == IPPROTO_ETHERIP) {
307 len = mtod(m, vm_offset_t) & 3;
308 KASSERT(len == 0 || len == ETHERIP_ALIGN,
309 (
"in6_gif_output: unexpected misalignment"));
311 m->m_len -= ETHERIP_ALIGN;
315 ip6 = mtod(m,
struct ip6_hdr *);
316 MPASS(sc->gif_family == AF_INET6);
317 bcopy(sc->gif_ip6hdr, ip6,
sizeof(
struct ip6_hdr));
319 ip6->ip6_flow |= htonl((uint32_t)ecn << 20);
320 ip6->ip6_nxt = proto;
333 struct gif_softc *sc = arg;
342 return (IPPROTO_DONE);
345 if ((gifp->if_flags & IFF_UP) != 0) {
346 ip6 = mtod(m,
struct ip6_hdr *);
347 ecn = IPV6_TRAFFIC_CLASS(ip6);
349 gif_input(m, gifp, proto, ecn);
354 return (IPPROTO_DONE);
360 const struct ip6_hdr *ip6;
361 struct gif_softc *sc;
373 ip6 = mtod(m,
const struct ip6_hdr *);
375 CK_LIST_FOREACH(sc, &
GIF_HASH(&ip6->ip6_dst, &ip6->ip6_src), chain) {
384 ret = ENCAP_DRV_LOOKUP;
401 if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0)
404 if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) {
407 m->m_pkthdr.rcvif) == 0)
422 .proto = IPPROTO_IPV4,
423 .min_length =
sizeof(
struct ip6_hdr) +
425 .exact_match = ENCAP_DRV_LOOKUP,
433 .proto = IPPROTO_IPV6,
434 .min_length = 2 *
sizeof(
struct ip6_hdr),
435 .exact_match = ENCAP_DRV_LOOKUP,
442 .proto = IPPROTO_ETHERIP,
443 .min_length =
sizeof(
struct ip6_hdr) +
444 sizeof(struct etherip_header) +
445 sizeof(struct ether_header),
446 .exact_match = ENCAP_DRV_LOOKUP,
458 if (!IS_DEFAULT_VNET(curvnet))
473 if (IS_DEFAULT_VNET(curvnet)) {
int in6_localip(struct in6_addr *in6)
#define IN6_IS_ADDR_UNSPECIFIED(a)
#define IN6_ARE_ADDR_EQUAL(a, b)
int fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags, const struct ifnet *src_if)
static uint32_t in6_gif_hashval(const struct in6_addr *src, const struct in6_addr *dst)
VNET_DEFINE_STATIC(int, ip6_gif_hlim)
SYSCTL_DECL(_net_inet6_ip6)
int in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
int in6_gif_setopts(struct gif_softc *sc, u_int options)
static const struct srcaddrtab * ipv6_srcaddrtab
static void in6_gif_attach(struct gif_softc *sc)
static int in6_gif_checkdup(const struct gif_softc *sc, const struct in6_addr *src, const struct in6_addr *dst)
static void in6_gif_srcaddr(void *arg __unused, const struct sockaddr *sa, int event)
const struct encap_config encap
int in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
static int in6_gif_input(struct mbuf *m, int off, int proto, void *arg)
const struct encaptab * cookie
#define GIF_HASH(src, dst)
static struct @1 ipv6_encap_cfg[]
#define V_ipv6_srchashtbl
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_VNET|CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0, "Default hop limit for encapsulated packets")
static int in6_gif_lookup(const struct mbuf *m, int off, int proto, void **arg)
static void in6_gif_set_running(struct gif_softc *sc)
void in6_gif_uninit(void)
#define SIOCGIFPDSTADDR_IN6
#define SIOCGIFPSRCADDR_IN6
#define SIOCSIFPHYADDR_IN6
int ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro, int flags, struct ip6_moptions *im6o, struct ifnet **ifpp, struct inpcb *inp)
#define IP6STAT_INC(name)
uint16_t in6_getscope(const struct in6_addr *in6)
int sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
int sa6_recoverscope(struct sockaddr_in6 *sin6)
struct in6_addr sin6_addr