Commit 4f22c981 authored by Martin Mareš's avatar Martin Mareš

Support for IPv6 sockets. How nice one doesn't have to ifdef around

ten years of API evolution :-)
parent dce26783
......@@ -88,6 +88,8 @@ ipv6_classify(ip_addr *a)
case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
}
}
if (!x && !a->addr[1] && !a->addr[2] && a->addr[3] == 1)
return IADDR_HOST | SCOPE_HOST; /* Loopback address */
return IADDR_INVALID;
}
......
......@@ -28,6 +28,10 @@
#include "lib/event.h"
#include "nest/iface.h"
#ifdef IPV6
#include <linux/in6.h> /* FIXMEv6: glibc variant? */
#endif
#include "lib/unix.h"
/*
......@@ -311,6 +315,37 @@ sk_new(pool *p)
#define ERR(x) do { err = x; goto bad; } while(0)
#ifdef IPV6
static inline void
set_inaddr(struct in6_addr *ia, ip_addr a)
{
ipa_hton(a);
memcpy(ia, &a, sizeof(a));
}
void
fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
{
sa->sin6_family = AF_INET6;
sa->sin6_port = htons(port);
sa->sin6_flowinfo = 0;
set_inaddr(&sa->sin6_addr, a);
}
void
get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
{
if (sa->sin6_family != AF_INET6)
bug("get_sockaddr called for wrong address family");
if (port)
*port = ntohs(sa->sin6_port);
memcpy(a, &sa->sin6_addr, sizeof(*a));
ipa_ntoh(*a);
}
#else
static inline void
set_inaddr(struct in_addr *ia, ip_addr a)
{
......@@ -319,7 +354,7 @@ set_inaddr(struct in_addr *ia, ip_addr a)
}
void
fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port)
fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
{
sa->sin_family = AF_INET;
sa->sin_port = htons(port);
......@@ -327,7 +362,7 @@ fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port)
}
void
get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port)
get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
{
if (sa->sin_family != AF_INET)
bug("get_sockaddr called for wrong address family");
......@@ -337,6 +372,8 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port)
ipa_ntoh(*a);
}
#endif
static char *
sk_setup(sock *s)
{
......@@ -346,6 +383,11 @@ sk_setup(sock *s)
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
ERR("fcntl(O_NONBLOCK)");
#ifdef IPV6
if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC &&
setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IPV6_UNICAST_HOPS");
#else
if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
ERR("IP_TOS");
if (s->ttl >= 0)
......@@ -355,13 +397,6 @@ sk_setup(sock *s)
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
ERR("SO_DONTROUTE");
}
#ifdef IP_PMTUDISC
if (s->type != SK_TCP_PASSIVE && s->type != SK_TCP_ACTIVE && s->type != SK_MAGIC)
{
int dont = IP_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
ERR("IP_PMTUDISC");
}
#endif
/* FIXME: Set send/receive buffers? */
/* FIXME: Set keepalive for TCP connections? */
......@@ -393,7 +428,7 @@ int
sk_open(sock *s)
{
int fd, e;
struct sockaddr_in sa;
sockaddr sa;
int zero = 0;
int one = 1;
int type = s->type;
......@@ -405,15 +440,15 @@ sk_open(sock *s)
{
case SK_TCP_ACTIVE:
case SK_TCP_PASSIVE:
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
break;
case SK_UDP:
case SK_UDP_MC:
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
break;
case SK_IP:
case SK_IP_MC:
fd = socket(PF_INET, SOCK_RAW, s->dport);
fd = socket(BIRD_PF, SOCK_RAW, s->dport);
break;
case SK_MAGIC:
fd = s->fd;
......@@ -432,12 +467,39 @@ sk_open(sock *s)
case SK_UDP:
case SK_IP:
if (s->iface) /* It's a broadcast socket */
#ifdef IPV6
bug("IPv6 has no broadcasts");
#else
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
ERR("SO_BROADCAST");
#endif
break;
case SK_UDP_MC:
case SK_IP_MC:
{
#ifdef IPV6
/* Fortunately, IPv6 socket interface is recent enough and therefore standardized */
ASSERT(s->iface && s->iface->addr);
if (has_dest)
{
int t = s->iface->index;
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IPV6_MULTICAST_HOPS");
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
ERR("IPV6_MULTICAST_LOOP");
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &t, sizeof(t)) < 0)
ERR("IPV6_MULTICAST_IF");
}
if (has_src)
{
struct ipv6_mreq mreq;
set_inaddr(&mreq.ipv6mr_multiaddr, s->daddr);
mreq.ipv6mr_ifindex = s->iface->index;
if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
ERR("IPV6_ADD_MEMBERSHIP");
}
#else
/* With IPv4 there are zillions of different socket interface variants. Ugh. */
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq;
#define mreq_add mreq
......@@ -484,6 +546,7 @@ sk_open(sock *s)
/* And this one sets interface for _receiving_ multicasts from */
if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0)
ERR("IP_ADD_MEMBERSHIP");
#endif
break;
}
}
......@@ -516,6 +579,26 @@ sk_open(sock *s)
if (listen(fd, 8))
ERR("listen");
break;
case SK_MAGIC:
break;
default:
#ifdef IPV6
#ifdef IPV6_MTU_DISCOVER
{
int dont = IPV6_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
ERR("IPV6_MTU_DISCOVER");
}
#endif
#else
#ifdef IP_PMTUDISC
{
int dont = IP_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
ERR("IP_PMTUDISC");
}
#endif
#endif
}
sk_alloc_bufs(s);
......@@ -560,7 +643,7 @@ sk_maybe_write(sock *s)
case SK_IP:
case SK_IP_MC:
{
struct sockaddr_in sa;
sockaddr sa;
if (s->tbuf == s->tpos)
return 1;
......@@ -611,7 +694,7 @@ sk_read(sock *s)
{
case SK_TCP_ACTIVE:
{
struct sockaddr_in sa;
sockaddr sa;
fill_in_sockaddr(&sa, s->daddr, s->dport);
if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
sk_tcp_connected(s);
......@@ -624,7 +707,7 @@ sk_read(sock *s)
}
case SK_TCP_PASSIVE:
{
struct sockaddr_in sa;
sockaddr sa;
int al = sizeof(sa);
int fd = accept(s->fd, (struct sockaddr *) &sa, &al);
if (fd >= 0)
......@@ -678,7 +761,7 @@ sk_read(sock *s)
return s->rx_hook(s, 0);
default:
{
struct sockaddr_in sa;
sockaddr sa;
int al = sizeof(sa);
int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al);
......
......@@ -21,10 +21,18 @@ volatile int async_config_flag;
volatile int async_dump_flag;
volatile int async_shutdown_flag;
#ifdef IPV6
#define BIRD_PF PF_INET6
typedef struct sockaddr_in6 sockaddr;
#else
#define BIRD_PF PF_INET
typedef struct sockaddr_in sockaddr;
#endif
void io_init(void);
void io_loop(void);
void fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port);
void get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port);
void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port);
void get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port);
/* krt.c bits */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment