summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2011-08-29 00:17:53 +0400
committerKozlov Dmitry <xeb@mail.ru>2011-08-29 00:17:53 +0400
commitf53638854c99e4b6b4b1c167c44fbb6dbfd0c6e7 (patch)
treecee88728fb81d74c1aec712cba785ee383829652
parent059b8b24df39591b96ef10dba735e9c2ad7e118c (diff)
downloadaccel-ppp-f53638854c99e4b6b4b1c167c44fbb6dbfd0c6e7.tar.gz
accel-ppp-f53638854c99e4b6b4b1c167c44fbb6dbfd0c6e7.zip
ipv6_dhcp: add routes to delegated prefixes
-rw-r--r--accel-pppd/ipv6/dhcpv6.c47
-rw-r--r--accel-pppd/ppp/ipv6cp_opt_intfid.c6
-rw-r--r--accel-pppd/ppp/ppp.c5
-rw-r--r--accel-pppd/ppp/ppp.h1
-rw-r--r--accel-pppd/ppp/ppp_ipv6cp.c3
5 files changed, 56 insertions, 6 deletions
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index 0bb72bc7..16d96751 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -10,6 +10,9 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/route.h>
+#include <linux/ipv6_route.h>
#include "triton.h"
#include "mempool.h"
@@ -41,6 +44,7 @@ struct dhcpv6_pd
uint32_t addr_iaid;
uint32_t dp_iaid;
struct ipv6db_prefix_t *ipv6_dp;
+ int dp_active:1;
};
static struct triton_md_handler_t dhcpv6_hnd;
@@ -150,6 +154,44 @@ static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_add
*(uint64_t *)(addr->s6_addr + 8) |= intf_id & ((1 << (128 - a->prefix_len)) - 1);
}
+static void insert_dp_routes(struct ppp_t *ppp, struct dhcpv6_pd *pd)
+{
+ struct ipv6db_addr_t *a;
+ struct ipv6db_addr_t *p;
+ struct in6_rtmsg rt6;
+ char str1[INET6_ADDRSTRLEN];
+ char str2[INET6_ADDRSTRLEN];
+ int err;
+
+ memset(&rt6, 0, sizeof(rt6));
+ rt6.rtmsg_ifindex = ppp->ifindex;
+ rt6.rtmsg_flags = RTF_UP | RTF_GATEWAY;
+
+ list_for_each_entry(p, &pd->ipv6_dp->prefix_list, entry) {
+ memcpy(&rt6.rtmsg_dst, &p->addr, sizeof(p->addr));
+ rt6.rtmsg_dst_len = p->prefix_len;
+ rt6.rtmsg_metric = 0;
+ //rt6.rtmsg_flags = RTF_UP;
+ list_for_each_entry(a, &ppp->ipv6->addr_list, entry) {
+ build_addr(a, ppp->ipv6->peer_intf_id, &rt6.rtmsg_gateway);
+ rt6.rtmsg_metric++;
+ if (ioctl(sock6_fd, SIOCADDRT, &rt6)) {
+ err = errno;
+ inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
+ inet_ntop(AF_INET6, &rt6.rtmsg_gateway, str2, sizeof(str2));
+ log_ppp_error("dhcpv6: add route %s/%i via %s: %s\n", str1, p->prefix_len, str2, strerror(err));
+ } else {
+ inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
+ inet_ntop(AF_INET6, &rt6.rtmsg_gateway, str2, sizeof(str2));
+ log_ppp_info2("dhcpv6: add route %s/%i via %s\n", str1, p->prefix_len, str2);
+
+ }
+ }
+ }
+
+ pd->dp_active = 1;
+}
+
static void insert_status(struct dhcpv6_packet *pkt, struct dhcpv6_option *opt, int code)
{
struct dhcpv6_option *opt1;
@@ -259,8 +301,11 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
insert_status(reply, opt1, D6_STATUS_NoPrefixAvail);
} else {
- if (req->hdr->type == D6_REQUEST)
+ if (req->hdr->type == D6_REQUEST) {
pd->dp_iaid = ia_na->iaid;
+ if (!pd->dp_active)
+ insert_dp_routes(req->ppp, pd);
+ }
f2 = 1;
diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c
index cc7ce364..389880a6 100644
--- a/accel-pppd/ppp/ipv6cp_opt_intfid.c
+++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c
@@ -37,7 +37,6 @@ struct in6_ifreq {
};
static int urandom_fd;
-static int sock6_fd;
static struct ipv6cp_option_t *ipaddr_init(struct ppp_ipv6cp_t *ipv6cp);
static void ipaddr_free(struct ppp_ipv6cp_t *ipv6cp, struct ipv6cp_option_t *opt);
@@ -372,11 +371,8 @@ static void load_config(void)
static void init()
{
- sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
- if (!sock6_fd) {
- log_warn("ppp:ipv6cp: kernel doesn't support ipv6\n");
+ if (sock6_fd < 0)
return;
- }
urandom_fd = open("/dev/urandom", O_RDONLY);
diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c
index a0f65f1d..e6d97887 100644
--- a/accel-pppd/ppp/ppp.c
+++ b/accel-pppd/ppp/ppp.c
@@ -32,6 +32,7 @@ pthread_rwlock_t __export ppp_lock = PTHREAD_RWLOCK_INITIALIZER;
__export LIST_HEAD(ppp_list);
int __export sock_fd;
+int __export sock6_fd;
int __export ppp_shutdown;
@@ -744,6 +745,10 @@ static void init(void)
_exit(EXIT_FAILURE);
}
+ sock6_fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock6_fd < 0)
+ log_warn("ppp: kernel doesn't support ipv6\n");
+
opt = conf_get_opt("ppp", "seq-file");
if (!opt)
opt = "/var/run/accel-ppp/seq";
diff --git a/accel-pppd/ppp/ppp.h b/accel-pppd/ppp/ppp.h
index 4d3fccd6..5246a3e0 100644
--- a/accel-pppd/ppp/ppp.h
+++ b/accel-pppd/ppp/ppp.h
@@ -200,4 +200,5 @@ extern struct list_head ppp_list;
extern struct ppp_stat_t ppp_stat;
extern int sock_fd; // internet socket for ioctls
+extern int sock6_fd; // internet socket for ioctls
#endif
diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c
index 816abc42..d60575a8 100644
--- a/accel-pppd/ppp/ppp_ipv6cp.c
+++ b/accel-pppd/ppp/ppp_ipv6cp.c
@@ -811,6 +811,9 @@ static void load_config(void)
static void ipv6cp_init(void)
{
+ if (sock6_fd < 0)
+ return;
+
load_config();
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);