summaryrefslogtreecommitdiff
path: root/accel-pppd/extra/ipv6pool.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/extra/ipv6pool.c')
-rw-r--r--accel-pppd/extra/ipv6pool.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c
index e9fb52d5..ba2a8ab1 100644
--- a/accel-pppd/extra/ipv6pool.c
+++ b/accel-pppd/extra/ipv6pool.c
@@ -22,11 +22,19 @@ struct ippool_item_t
struct ipv6db_item_t it;
};
+struct dppool_item_t
+{
+ struct list_head entry;
+ struct ipv6db_prefix_t it;
+};
+
+
static LIST_HEAD(ippool);
+static LIST_HEAD(dppool);
static spinlock_t pool_lock = SPINLOCK_INITIALIZER;
static struct ipdb_t ipdb;
-static void generate_pool(struct in6_addr *addr, int mask, int prefix_len)
+static void generate_ippool(struct in6_addr *addr, int mask, int prefix_len)
{
struct ippool_item_t *it;
uint64_t ip, endip, step;
@@ -49,7 +57,31 @@ static void generate_pool(struct in6_addr *addr, int mask, int prefix_len)
}
}
-static void add_prefix(const char *_val)
+static void generate_dppool(struct in6_addr *addr, int mask, int prefix_len)
+{
+ struct dppool_item_t *it;
+ uint64_t ip, endip, step;
+ struct ipv6db_addr_t *a;
+
+ ip = be64toh(*(uint64_t *)addr->s6_addr);
+ endip = ip | ((1llu << (64 - mask)) - 1);
+ step = 1 << (64 - prefix_len);
+
+ for (; ip <= endip; ip += step) {
+ it = malloc(sizeof(*it));
+ it->it.owner = &ipdb;
+ INIT_LIST_HEAD(&it->it.prefix_list);
+ a = malloc(sizeof(*a));
+ memset(a, 0, sizeof(*a));
+ *(uint64_t *)a->addr.s6_addr = htobe64(ip);
+ a->prefix_len = prefix_len;
+ list_add_tail(&a->entry, &it->it.prefix_list);
+ list_add_tail(&it->entry, &dppool);
+ }
+}
+
+
+static void add_prefix(int type, const char *_val)
{
char *val = _strdup(_val);
char *ptr1, *ptr2;
@@ -84,7 +116,10 @@ static void add_prefix(const char *_val)
if (prefix_len > 64 || prefix_len < mask)
goto err;
- generate_pool(&addr, mask, prefix_len);
+ if (type)
+ generate_dppool(&addr, mask, prefix_len);
+ else
+ generate_ippool(&addr, mask, prefix_len);
_free(val);
return;
@@ -120,9 +155,35 @@ static void put_ip(struct ppp_t *ppp, struct ipv6db_item_t *it)
spin_unlock(&pool_lock);
}
+static struct ipv6db_prefix_t *get_dp(struct ppp_t *ppp)
+{
+ struct dppool_item_t *it;
+
+ spin_lock(&pool_lock);
+ if (!list_empty(&dppool)) {
+ it = list_entry(dppool.next, typeof(*it), entry);
+ list_del(&it->entry);
+ } else
+ it = NULL;
+ spin_unlock(&pool_lock);
+
+ return it ? &it->it : NULL;
+}
+
+static void put_dp(struct ppp_t *ppp, struct ipv6db_prefix_t *it)
+{
+ struct dppool_item_t *pit = container_of(it, typeof(*pit), it);
+
+ spin_lock(&pool_lock);
+ list_add_tail(&pit->entry, &dppool);
+ spin_unlock(&pool_lock);
+}
+
static struct ipdb_t ipdb = {
.get_ipv6 = get_ip,
.put_ipv6 = put_ip,
+ .get_ipv6_prefix = get_dp,
+ .put_ipv6_prefix = put_dp,
};
static void ippool_init(void)
@@ -133,8 +194,12 @@ static void ippool_init(void)
if (!s)
return;
- list_for_each_entry(opt, &s->items, entry)
- add_prefix(opt->name);
+ list_for_each_entry(opt, &s->items, entry) {
+ if (!strcmp(opt->name, "delegate"))
+ add_prefix(1, opt->val);
+ else
+ add_prefix(0, opt->name);
+ }
ipdb_register(&ipdb);
}