summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2014-12-01 16:24:11 +0300
committerDmitry Kozlov <xeb@mail.ru>2014-12-01 16:39:35 +0300
commit3cc7fd0165e096be25761710b66b44fda9d09190 (patch)
treeb6eef91b863c78858be060902a515b26a7b2bf4b
parentebc0ec740280efd2ea7f22abbb84eda53ab06632 (diff)
downloadaccel-ppp-3cc7fd0165e096be25761710b66b44fda9d09190.tar.gz
accel-ppp-3cc7fd0165e096be25761710b66b44fda9d09190.zip
ipv6: if assigned prefix is <= 64 add it as address else add it as route
-rw-r--r--accel-pppd/ifcfg.c33
-rw-r--r--accel-pppd/ipdb.h5
-rw-r--r--accel-pppd/ipv6/dhcpv6.c17
-rw-r--r--accel-pppd/ipv6/nd.c57
-rw-r--r--accel-pppd/libnetlink/iputils.c116
-rw-r--r--accel-pppd/libnetlink/iputils.h1
6 files changed, 142 insertions, 87 deletions
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 26926fa1..685e1de1 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -25,7 +25,7 @@
struct in6_ifreq {
struct in6_addr ifr6_addr;
__u32 ifr6_prefixlen;
- int ifr6_ifindex;
+ int ifr6_ifindex;
};
static void devconf(struct ap_session *ses, const char *attr, const char *val)
@@ -65,7 +65,7 @@ void ap_session_ifup(struct ap_session *ses)
_free(ses->ifname_rename);
ses->ifname_rename = NULL;
}
-
+
triton_event_fire(EV_SES_ACCT_START, ses);
if (ses->stop_time)
@@ -119,17 +119,17 @@ void __export ap_session_accounting_started(struct ap_session *ses)
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ses->ipv4->addr;
memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
-
+
if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno));
-
+
/*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
addr.sin_addr.s_addr = 0xffffffff;
memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno));
}*/
-
+
addr.sin_addr.s_addr = ses->ipv4->peer_addr;
/*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
@@ -142,7 +142,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
log_ppp_error("failed to add route: %s\n", strerror(errno));
} else*/ {
memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr));
-
+
if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno));
}
@@ -154,7 +154,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
devconf(ses, "forwarding", "1");
memset(&ifr6, 0, sizeof(ifr6));
-
+
if (ses->ctrl->ppp) {
ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
*(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
@@ -164,17 +164,18 @@ void __export ap_session_accounting_started(struct ap_session *ses)
if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
}
-
+
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
+ a->installed = 0;
/*if (a->prefix_len < 128) {
build_addr(a, ses->ipv6->intf_id, &ifr6.ifr6_addr);
ifr6.ifr6_prefixlen = a->prefix_len;
if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
log_ppp_error("failed to add IPv6 address: %s\n", strerror(errno));
- } else*/
+ } else
if (ip6route_add(ses->ifindex, &a->addr, a->prefix_len, 0))
- log_ppp_error("failed to add IPv6 route: %s\n", strerror(errno));
+ log_ppp_error("failed to add IPv6 route: %s\n", strerror(errno));*/
}
}
@@ -195,7 +196,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
log_ppp_error("failed to set NP (IPv4) mode: %s\n", strerror(errno));
}
-
+
if (ses->ipv6) {
np.protocol = PPP_IPV6;
np.mode = NPMODE_PASS;
@@ -208,7 +209,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
}
#endif
}
-
+
ses->ctrl->started(ses);
triton_event_fire(EV_SES_STARTED, ses);
@@ -244,7 +245,7 @@ void __export ap_session_ifdown(struct ap_session *ses)
ifr6.ifr6_ifindex = ses->ifindex;
ioctl(sock6_fd, SIOCDIFADDR, &ifr6);
-
+
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
if (a->prefix_len == 128)
continue;
@@ -263,7 +264,7 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l
if (len == -1)
len = strlen(ifname);
-
+
if (len >= IFNAMSIZ - 1) {
log_ppp_warn("cannot rename interface (name is too long)\n");
return -1;
@@ -272,7 +273,7 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l
strcpy(ifr.ifr_name, ses->ifname);
memcpy(ifr.ifr_newname, ifname, len);
ifr.ifr_newname[len] = 0;
-
+
if (ioctl(sock_fd, SIOCSIFNAME, &ifr)) {
if (!ses->ifname_rename)
ses->ifname_rename = _strdup(ifr.ifr_newname);
@@ -281,7 +282,7 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l
return -1;
}
} else {
- log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
+ log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
memcpy(ses->ifname, ifname, len);
ses->ifname[len] = 0;
}
diff --git a/accel-pppd/ipdb.h b/accel-pppd/ipdb.h
index 7f61b43b..d461c88d 100644
--- a/accel-pppd/ipdb.h
+++ b/accel-pppd/ipdb.h
@@ -1,8 +1,6 @@
#ifndef IPDB_H
#define IPDB_H
-#include <netinet/in.h>
-
#include "ppp.h"
#include "list.h"
@@ -20,6 +18,7 @@ struct ipv6db_addr_t
struct in6_addr addr;
int prefix_len;
int flag_auto:1;
+ int installed:1;
};
struct ipv6db_item_t
@@ -40,7 +39,7 @@ struct ipv6db_prefix_t
struct ipdb_t
{
struct list_head entry;
-
+
struct ipv4db_item_t *(*get_ipv4)(struct ap_session *ses);
void (*put_ipv4)(struct ap_session *ses, struct ipv4db_item_t *);
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index 62f20bb0..3f9df71d 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -21,11 +21,12 @@
#include "ppp.h"
#include "ipdb.h"
#include "events.h"
-
-#include "memdebug.h"
+#include "iputils.h"
#include "dhcpv6.h"
+#include "memdebug.h"
+
#define BUF_SIZE 65536
#define MAX_DNS_COUNT 3
@@ -295,6 +296,18 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
ia_addr->pref_lifetime = htonl(conf_pref_lifetime);
ia_addr->valid_lifetime = htonl(conf_valid_lifetime);
+
+ if (a->installed) {
+ if (a->prefix_len > 64)
+ ip6route_add(ses->ifindex, &a->addr, a->prefix_len, 0);
+ else {
+ struct in6_addr addr;
+ memcpy(addr.s6_addr, &a->addr, 8);
+ memcpy(addr.s6_addr + 8, &ses->ipv6->intf_id, 8);
+ ip6addr_add(ses->ifindex, &addr, a->prefix_len);
+ }
+ a->installed = 1;
+ }
}
list_for_each_entry(opt2, &opt->opt_list, entry) {
diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c
index 12413801..19a3d7d3 100644
--- a/accel-pppd/ipv6/nd.c
+++ b/accel-pppd/ipv6/nd.c
@@ -17,6 +17,7 @@
#include "events.h"
#include "mempool.h"
#include "ipdb.h"
+#include "iputils.h"
#include "memdebug.h"
@@ -104,12 +105,12 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
//struct nd_opt_mtu *mtu;
struct ipv6db_addr_t *a;
int i;
-
+
if (!buf) {
log_emerg("out of memory\n");
return;
}
-
+
if (!h->ses->ipv6) {
triton_timer_del(&h->timer);
return;
@@ -119,12 +120,12 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
adv->nd_ra_type = ND_ROUTER_ADVERT;
adv->nd_ra_curhoplimit = conf_AdvCurHopLimit;
adv->nd_ra_router_lifetime = htons(conf_AdvDefaultLifetime);
- adv->nd_ra_flags_reserved =
+ adv->nd_ra_flags_reserved =
(conf_AdvManagedFlag ? ND_RA_FLAG_MANAGED : 0) |
(conf_AdvOtherConfigFlag ? ND_RA_FLAG_OTHER : 0);
adv->nd_ra_reachable = htonl(conf_AdvReachableTime);
adv->nd_ra_retransmit = htonl(conf_AdvRetransTimer);
-
+
pinfo = (struct nd_opt_prefix_info *)(adv + 1);
list_for_each_entry(a, &h->ses->ipv6->addr_list, entry) {
memset(pinfo, 0, sizeof(*pinfo));
@@ -137,8 +138,16 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
pinfo->nd_opt_pi_preferred_time = htonl(conf_AdvPrefixPreferredLifetime);
memcpy(&pinfo->nd_opt_pi_prefix, &a->addr, 8);
pinfo++;
+
+ if (!a->installed) {
+ struct in6_addr addr;
+ memcpy(addr.s6_addr, &a->addr, 8);
+ memcpy(addr.s6_addr + 8, &h->ses->ipv6->intf_id, 8);
+ ip6addr_add(h->ses->ifindex, &addr, a->prefix_len);
+ a->installed = 1;
+ }
}
-
+
/*rinfo = (struct nd_opt_route_info_local *)pinfo;
list_for_each_entry(a, &h->ses->ipv6->route_list, entry) {
memset(rinfo, 0, sizeof(*rinfo));
@@ -163,7 +172,7 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
}
} else
rdnss_addr = (struct in6_addr *)pinfo;
-
+
if (conf_dnssl) {
dnsslinfo = (struct nd_opt_dnssl_info_local *)rdnss_addr;
memset(dnsslinfo, 0, sizeof(*dnsslinfo));
@@ -190,7 +199,7 @@ static void send_ra_timer(struct triton_timer_t *t)
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr32[0] = htonl(0xff020000);
addr.sin6_addr.s6_addr32[3] = htonl(0x1);
- addr.sin6_scope_id = h->ses->ifindex;
+ addr.sin6_scope_id = h->ses->ifindex;
if (h->ra_sent == conf_init_ra) {
h->timer.period = conf_MaxRtrAdvInterval * 1000;
@@ -261,7 +270,7 @@ static int ipv6_nd_start(struct ap_session *ses)
struct ipv6_nd_handler_t *h;
sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-
+
if (sock < 0) {
log_ppp_error("socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6): %s\n", strerror(errno));
return -1;
@@ -283,7 +292,7 @@ static int ipv6_nd_start(struct ap_session *ses)
log_ppp_error("ipv6_nd: setsockopt(IPV6_UNICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
-
+
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
goto out_err;
@@ -372,14 +381,14 @@ static void ev_ses_finishing(struct ap_session *ses)
if (!h)
return;
-
+
if (h->timer.tpd)
triton_timer_del(&h->timer);
triton_md_unregister_handler(&h->hnd, 1);
list_del(&h->pd.entry);
-
+
_free(h);
}
@@ -393,19 +402,19 @@ static void add_dnssl(const char *val)
n++;
else
n += 2;
-
+
if (n > 255) {
log_error("dnsv6: dnssl '%s' is too long\n", val);
return;
}
-
+
if (!conf_dnssl)
conf_dnssl = _malloc(n);
else
conf_dnssl = _realloc(conf_dnssl, conf_dnssl_size + n);
-
+
buf = conf_dnssl + conf_dnssl_size;
-
+
while (1) {
ptr = strchr(val, '.');
if (!ptr)
@@ -423,7 +432,7 @@ static void add_dnssl(const char *val)
break;
}
}
-
+
conf_dnssl_size += n;
}
@@ -431,12 +440,12 @@ static void load_dns(void)
{
struct conf_sect_t *s = conf_get_section("ipv6-dns");
struct conf_option_t *opt;
-
+
if (!s)
return;
-
+
conf_dns_count = 0;
-
+
if (conf_dnssl)
_free(conf_dnssl);
conf_dnssl = NULL;
@@ -447,7 +456,7 @@ static void load_dns(void)
add_dnssl(opt->val);
continue;
}
-
+
if (!strcmp(opt->name, "lifetime")) {
conf_rdnss_lifetime = atoi(opt->val);
continue;
@@ -473,10 +482,10 @@ static void load_config(void)
opt = conf_get_opt("ipv6-nd", "MaxRtrAdvInterval");
if (opt)
conf_MaxRtrAdvInterval = atoi(opt);
-
+
conf_MinRtrAdvInterval = 0.33 * conf_MaxRtrAdvInterval;
conf_AdvDefaultLifetime = 3 * conf_MaxRtrAdvInterval;
-
+
conf_AdvManagedFlag = triton_module_loaded("ipv6_dhcp");
conf_AdvOtherConfigFlag = triton_module_loaded("ipv6_dhcp");
conf_AdvPrefixAutonomousFlag = !conf_AdvManagedFlag;
@@ -532,7 +541,7 @@ static void load_config(void)
opt = conf_get_opt("ipv6-nd", "AdvAutonomousFlag");
if (opt)
conf_AdvPrefixAutonomousFlag = atoi(opt);
-
+
load_dns();
}
@@ -541,7 +550,7 @@ static void init(void)
buf_pool = mempool_create(BUF_SIZE);
load_config();
-
+
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ses_started);
triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ev_ses_finishing);
diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c
index fb85973b..480f028f 100644
--- a/accel-pppd/libnetlink/iputils.c
+++ b/accel-pppd/libnetlink/iputils.c
@@ -39,7 +39,7 @@ static void open_rth(void)
if (!rth)
return;
-
+
memset(rth, 0, sizeof(*rth));
if (rtnl_open(rth, 0)) {
@@ -78,7 +78,7 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *
if (tb[IFLA_IFNAME] == NULL)
return 0;
-
+
//printf("%i %s\n", ifi->ifi_index, RTA_DATA(tb[IFLA_IFNAME]));
return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), a->arg);
@@ -127,12 +127,12 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.n.nlmsg_type = RTM_GETLINK;
@@ -158,10 +158,10 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
memcpy(stats, RTA_DATA(tb[IFLA_STATS]), sizeof(*stats));
else
return -1;
-
+
return 0;
}
-
+
int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
{
struct iplink_req {
@@ -173,20 +173,20 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
req.n.nlmsg_type = RTM_NEWLINK;
req.i.ifi_family = AF_UNSPEC;
-
+
addattr_l(&req.n, 4096, IFLA_LINK, &ifindex, 4);
addattr_l(&req.n, 4096, IFLA_IFNAME, ifname, strlen(ifname));
-
+
linkinfo = NLMSG_TAIL(&req.n);
addattr_l(&req.n, 4096, IFLA_LINKINFO, NULL, 0);
addattr_l(&req.n, 4096, IFLA_INFO_KIND, "vlan", 4);
@@ -195,12 +195,12 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
addattr_l(&req.n, 4096, IFLA_INFO_DATA, NULL, 0);
addattr_l(&req.n, 4096, IFLA_VLAN_ID, &vid, 2);
data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
-
+
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -215,18 +215,18 @@ int __export iplink_vlan_del(int ifindex)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.n.nlmsg_type = RTM_DELLINK;
req.i.ifi_family = AF_UNSPEC;
req.i.ifi_index = ifindex;
-
+
linkinfo = NLMSG_TAIL(&req.n);
addattr_l(&req.n, 4096, IFLA_LINKINFO, NULL, 0);
addattr_l(&req.n, 4096, IFLA_INFO_KIND, "vlan", 4);
@@ -234,12 +234,12 @@ int __export iplink_vlan_del(int ifindex)
/*data = NLMSG_TAIL(&req.n);
addattr_l(&req.n, 4096, IFLA_VLAN_ID, &vid, 2);
data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;*/
-
+
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -253,12 +253,12 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWADDR;
@@ -270,7 +270,7 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -284,12 +284,12 @@ int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_DELADDR;
@@ -301,7 +301,7 @@ int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -315,12 +315,12 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
@@ -341,7 +341,7 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -355,12 +355,12 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.n.nlmsg_type = RTM_DELROUTE;
@@ -376,7 +376,7 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto)
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -390,12 +390,12 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
req.n.nlmsg_type = RTM_NEWROUTE;
@@ -411,11 +411,43 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
+int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
+{
+ struct ipaddr_req {
+ struct nlmsghdr n;
+ struct ifaddrmsg i;
+ char buf[4096];
+ } req;
+
+ if (!rth)
+ open_rth();
+
+ if (!rth)
+ return -1;
+
+ memset(&req, 0, sizeof(req) - 4096);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+ req.n.nlmsg_type = RTM_NEWADDR;
+ req.i.ifa_family = AF_INET6;
+ req.i.ifa_index = ifindex;
+ req.i.ifa_prefixlen = prefix_len;
+ req.i.ifa_flags = IFA_F_NODAD;
+
+ addattr_l(&req.n, sizeof(req), IFA_ADDRESS, addr, 16);
+
+ if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
{
struct ipaddr_req {
@@ -433,12 +465,12 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_GETROUTE;
@@ -460,7 +492,7 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
r = NLMSG_DATA(&req.n);
len = req.n.nlmsg_len;
-
+
if (req.n.nlmsg_type != RTM_NEWROUTE) {
log_error("failed to detect route to server (wrong netlink message type)");
goto out;
@@ -473,7 +505,7 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
}
parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
-
+
if (tb[RTA_PREFSRC])
res = *(uint32_t *)RTA_DATA(tb[RTA_PREFSRC]);
@@ -494,12 +526,12 @@ int __export iprule_add(uint32_t addr, int table)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_NEWRULE;
@@ -516,7 +548,7 @@ int __export iprule_add(uint32_t addr, int table)
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
@@ -530,12 +562,12 @@ int __export iprule_del(uint32_t addr, int table)
if (!rth)
open_rth();
-
+
if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
-
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_DELRULE;
@@ -552,7 +584,7 @@ int __export iprule_del(uint32_t addr, int table)
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
return -1;
-
+
return 0;
}
diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h
index b9a6488c..60976277 100644
--- a/accel-pppd/libnetlink/iputils.h
+++ b/accel-pppd/libnetlink/iputils.h
@@ -19,6 +19,7 @@ int iproute_del(int ifindex, in_addr_t dst, int proto);
in_addr_t iproute_get(in_addr_t dst, in_addr_t *gw);
int ip6route_add(int ifindex, struct in6_addr *dst, int prefix_len, int proto);
+int ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len);
int iprule_add(uint32_t addr, int table);
int iprule_del(uint32_t addr, int table);