diff options
Diffstat (limited to 'accel-pppd/extra/ipv6pool.c')
-rw-r--r-- | accel-pppd/extra/ipv6pool.c | 75 |
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); } |