36#include <sys/socket.h>
37#include <sys/socketvar.h>
38#include <sys/sockio.h>
41#include <sys/kernel.h>
42#include <sys/sysctl.h>
43#include <sys/malloc.h>
47#include <net/if_var.h>
50#include <netinet/in.h>
52#include <net/ethernet.h>
53#include <netinet/ip.h>
55#include <netinet/in_pcb.h>
56#include <netinet/ip_encap.h>
57#include <netinet/ip_var.h>
58#include <netinet/ip6.h>
59#include <netinet/udp.h>
60#include <netinet/udp_var.h>
64#include <net/if_gre.h>
67#define V_ip6_gre_hlim VNET(ip6_gre_hlim)
70SYSCTL_INT(_net_inet6_ip6, OID_AUTO, grehlim, CTLFLAG_VNET | CTLFLAG_RW,
71 &VNET_NAME(ip6_gre_hlim), 0,
"Default hop limit for encapsulated packets");
80#define V_ipv6_sockets VNET(ipv6_sockets)
81#define V_ipv6_hashtbl VNET(ipv6_hashtbl)
82#define V_ipv6_srchashtbl VNET(ipv6_srchashtbl)
83#define GRE_HASH(src, dst) (V_ipv6_hashtbl[\
84 in6_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)])
85#define GRE_SRCHASH(src) (V_ipv6_srchashtbl[\
86 fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
87#define GRE_SOCKHASH(src) (V_ipv6_sockets[\
88 fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
89#define GRE_HASH_SC(sc) GRE_HASH(&(sc)->gre_oip6.ip6_src,\
90 &(sc)->gre_oip6.ip6_dst)
97 ret = fnv_32_buf(src,
sizeof(*src), FNV1_32_INIT);
98 return (fnv_32_buf(dst,
sizeof(*dst), ret));
101static struct gre_socket*
104 struct gre_socket *gs;
117 const struct in6_addr *dst, uint32_t opts)
119 struct gre_list *head;
120 struct gre_softc *tmp;
121 struct gre_socket *gs;
123 if (sc->gre_family == AF_INET6 &&
126 (sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP))
129 if (opts & GRE_UDPENCAP) {
137 CK_LIST_FOREACH(tmp, head, chain) {
142 return (EADDRNOTAVAIL);
150 const struct ip6_hdr *ip6;
151 struct gre_softc *sc;
157 ip6 = mtod(m,
const struct ip6_hdr *);
158 CK_LIST_FOREACH(sc, &
GRE_HASH(&ip6->ip6_dst, &ip6->ip6_src), chain) {
167 if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
170 return (ENCAP_DRV_LOOKUP);
184 GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
186 GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
199 struct gre_softc *sc;
217 const struct sockaddr *sa,
void *ctx)
219 struct gre_socket *gs;
220 struct gre_softc *sc;
225 gs = (
struct gre_socket *)ctx;
231 CK_LIST_FOREACH(sc, &gs->list, chain) {
235 if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){
236 gre_input(m, off +
sizeof(
struct udphdr), IPPROTO_UDP, sc);
248 struct gre_socket *gs;
263 if (CK_LIST_EMPTY(&gs->list)) {
264 CK_LIST_REMOVE(gs, chain);
266 NET_EPOCH_CALL(gre_sofree, &gs->epoch_ctx);
268 gs = sc->gre_so = NULL;
279 s = malloc(
sizeof(*s), M_GRE, M_WAITOK | M_ZERO);
280 s->
addr = sc->gre_oip6.ip6_src;
283 error = socreate(sc->gre_family, &gs->so,
284 SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred,
287 if_printf(GRE2IFP(sc),
288 "cannot create socket: %d\n", error);
293 error = udp_set_kernel_tunneling(gs->so,
296 if_printf(GRE2IFP(sc),
297 "cannot set UDP tunneling: %d\n", error);
301 memset(&sopt, 0,
sizeof(sopt));
302 sopt.sopt_dir = SOPT_SET;
303 sopt.sopt_level = IPPROTO_IPV6;
305 sopt.sopt_val = &value;
306 sopt.sopt_valsize =
sizeof(value);
308 error = sosetopt(gs->so, &sopt);
310 if_printf(GRE2IFP(sc),
311 "cannot set IPV6_BINDANY opt: %d\n",
323 if_printf(GRE2IFP(sc),
324 "cannot determine scope zone id: %d\n",
328 error = sobind(gs->so, (
struct sockaddr *)&
sin6,
331 if_printf(GRE2IFP(sc),
332 "cannot bind socket: %d\n", error);
342 CK_LIST_INSERT_HEAD(&gs->list, sc, chain);
357 if (sc->gre_options & GRE_UDPENCAP) {
358 sc->gre_csumflags = CSUM_UDP_IPV6;
359 sc->gre_hlen =
sizeof(
struct greudp6);
360 sc->gre_oip6.ip6_nxt = IPPROTO_UDP;
361 gh = &sc->gre_udp6hdr->gi6_gre;
362 gre_update_udphdr(sc, &sc->gre_udp6,
365 sc->gre_hlen =
sizeof(
struct greip6);
366 sc->gre_oip6.ip6_nxt = IPPROTO_GRE;
367 gh = &sc->gre_ip6hdr->gi6_gre;
369 sc->gre_oip6.ip6_vfc = IPV6_VERSION;
370 gre_update_hdr(sc, gh);
376 if (sc->gre_options & GRE_UDPENCAP) {
382 CK_LIST_INSERT_HEAD(&
GRE_SRCHASH(&sc->gre_oip6.ip6_src), sc, srchash);
395 MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT);
396 MPASS(sc->gre_family == AF_INET6);
403 if (cmd == GRESOPTS &&
404 (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) &&
406 &sc->gre_oip6.ip6_dst, value) == EADDRNOTAVAIL)
409 CK_LIST_REMOVE(sc, chain);
410 CK_LIST_REMOVE(sc, srchash);
417 sc->gre_options = value;
420 sc->gre_port = value;
426 free(sc->gre_hdr, M_GRE);
454 error = EADDRNOTAVAIL;
473 if (error == EADDRNOTAVAIL)
475 if (error == EEXIST) {
480 ip6 = malloc(
sizeof(
struct greudp6) + 3 *
sizeof(uint32_t),
481 M_GRE, M_WAITOK | M_ZERO);
484 if (sc->gre_family != 0) {
486 CK_LIST_REMOVE(sc, chain);
487 CK_LIST_REMOVE(sc, srchash);
489 free(sc->gre_hdr, M_GRE);
492 sc->gre_family = AF_INET6;
495 sc->gre_iseq = UINT32_MAX;
499 free(sc->gre_hdr, M_GRE);
504 if (sc->gre_family != AF_INET6) {
505 error = EADDRNOTAVAIL;
509 memset(src, 0,
sizeof(*src));
513 sc->gre_oip6.ip6_src: sc->gre_oip6.ip6_dst;
514 error = prison_if(curthread->td_ucred, (
struct sockaddr *)src);
518 memset(src, 0,
sizeof(*src));
530 gi6 = mtod(m,
struct greip6 *);
532 gi6->gi6_ip6.ip6_flow |= flowid & IPV6_FLOWLABEL_MASK;
539 .proto = IPPROTO_GRE,
540 .min_length =
sizeof(
struct greip6) +
544 sizeof(struct ip6_hdr),
546 .exact_match = ENCAP_DRV_LOOKUP,
555 if (!IS_DEFAULT_VNET(curvnet))
566 if (IS_DEFAULT_VNET(curvnet)) {
int in6_localip(struct in6_addr *in6)
int in6_cksum_pseudo(struct ip6_hdr *, uint32_t, uint8_t, uint16_t)
#define IN6_IS_ADDR_UNSPECIFIED(a)
#define IN6_ARE_ADDR_EQUAL(a, b)
#define SIOCGIFPDSTADDR_IN6
#define SIOCGIFPSRCADDR_IN6
#define SIOCSIFPHYADDR_IN6
int in6_gre_ioctl(struct gre_softc *sc, u_long cmd, caddr_t data)
int in6_gre_setopts(struct gre_softc *sc, u_long cmd, uint32_t value)
static void in6_gre_set_running(struct gre_softc *sc)
SYSCTL_DECL(_net_inet6_ip6)
int in6_gre_output(struct mbuf *m, int af __unused, int hlen __unused, uint32_t flowid)
VNET_DEFINE(int, ip6_gre_hlim)
static const struct srcaddrtab * ipv6_srcaddrtab
VNET_DEFINE_STATIC(struct gre_sockets *, ipv6_sockets)
static int in6_gre_lookup(const struct mbuf *m, int off, int proto, void **arg)
void in6_gre_uninit(void)
#define GRE_SOCKHASH(src)
static struct gre_socket * in6_gre_lookup_socket(const struct in6_addr *addr)
static const struct encap_config ipv6_encap_cfg
SYSCTL_INT(_net_inet6_ip6, OID_AUTO, grehlim, CTLFLAG_VNET|CTLFLAG_RW, &VNET_NAME(ip6_gre_hlim), 0, "Default hop limit for encapsulated packets")
static void in6_gre_srcaddr(void *arg __unused, const struct sockaddr *sa, int event __unused)
#define V_ipv6_srchashtbl
static int in6_gre_attach(struct gre_softc *sc)
#define GRE_HASH(src, dst)
static uint32_t in6_gre_hashval(const struct in6_addr *src, const struct in6_addr *dst)
static const struct encaptab * ecookie
static int in6_gre_setup_socket(struct gre_softc *sc)
static int in6_gre_checkdup(const struct gre_softc *sc, const struct in6_addr *src, const struct in6_addr *dst, uint32_t opts)
static void in6_gre_udp_input(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa, void *ctx)
static struct sockaddr_in6 sin6
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)
int sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok)
int sa6_recoverscope(struct sockaddr_in6 *sin6)
struct in6_addr sin6_addr