2004-12-30 16:39:11 +00:00
|
|
|
/*
|
2003-04-11 09:40:12 +00:00
|
|
|
* IP address pool functions.
|
2004-09-09 20:23:50 +00:00
|
|
|
* Copyright (C) 2003, 2004 Mondru AB.
|
2017-08-02 17:49:47 +00:00
|
|
|
* Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
|
2004-12-30 16:39:11 +00:00
|
|
|
*
|
2003-04-11 09:40:12 +00:00
|
|
|
* The contents of this file may be used under the terms of the GNU
|
|
|
|
* General Public License Version 2, provided that the above copyright
|
|
|
|
* notice and this permission notice is included in all copies or
|
|
|
|
* substantial portions of the software.
|
2017-10-13 12:32:24 +00:00
|
|
|
*
|
2003-04-11 09:40:12 +00:00
|
|
|
*/
|
|
|
|
|
2004-01-19 18:37:58 +00:00
|
|
|
#include <sys/types.h>
|
2011-11-02 12:06:18 +00:00
|
|
|
#include <netinet/in.h> /* in_addr */
|
|
|
|
#include <stdlib.h> /* calloc */
|
|
|
|
#include <stdio.h> /* sscanf */
|
2004-09-09 20:23:50 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <arpa/inet.h>
|
2017-08-02 17:49:47 +00:00
|
|
|
#include <netdb.h>
|
2004-09-09 20:23:50 +00:00
|
|
|
#include "syserr.h"
|
2003-04-11 09:40:12 +00:00
|
|
|
#include "ippool.h"
|
2004-12-30 16:39:11 +00:00
|
|
|
#include "lookup.h"
|
2003-04-11 09:40:12 +00:00
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
int ippool_printaddr(struct ippool_t *this)
|
|
|
|
{
|
|
|
|
unsigned int n;
|
|
|
|
printf("ippool_printaddr\n");
|
2018-10-21 11:27:58 +00:00
|
|
|
printf("Firstdyn %td\n", this->firstdyn - this->member);
|
|
|
|
printf("Lastdyn %td\n", this->lastdyn - this->member);
|
|
|
|
printf("Firststat %td\n", this->firststat - this->member);
|
|
|
|
printf("Laststat %td\n", this->laststat - this->member);
|
2018-11-22 07:19:28 +00:00
|
|
|
printf("Listsize %u\n", this->listsize);
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
for (n = 0; n < this->listsize; n++) {
|
2017-08-02 17:49:47 +00:00
|
|
|
char s[256];
|
|
|
|
in46a_ntop(&this->member[n].addr, s, sizeof(s));
|
2018-10-21 11:27:58 +00:00
|
|
|
printf("Unit %d inuse %d prev %td next %td addr %s\n",
|
2011-11-02 12:06:18 +00:00
|
|
|
n,
|
|
|
|
this->member[n].inuse,
|
|
|
|
this->member[n].prev - this->member,
|
|
|
|
this->member[n].next - this->member,
|
2017-08-02 17:49:47 +00:00
|
|
|
s);
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member)
|
|
|
|
{
|
|
|
|
uint32_t hash;
|
|
|
|
struct ippoolm_t *p;
|
|
|
|
struct ippoolm_t *p_prev = NULL;
|
|
|
|
|
|
|
|
/* Insert into hash table */
|
2017-08-02 17:49:47 +00:00
|
|
|
hash = ippool_hash(&member->addr) & this->hashmask;
|
2011-11-02 12:06:18 +00:00
|
|
|
for (p = this->hash[hash]; p; p = p->nexthash)
|
|
|
|
p_prev = p;
|
|
|
|
if (!p_prev)
|
|
|
|
this->hash[hash] = member;
|
|
|
|
else
|
|
|
|
p_prev->nexthash = member;
|
|
|
|
return 0; /* Always OK to insert */
|
2003-07-06 19:33:18 +00:00
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member)
|
|
|
|
{
|
|
|
|
uint32_t hash;
|
|
|
|
struct ippoolm_t *p;
|
|
|
|
struct ippoolm_t *p_prev = NULL;
|
|
|
|
|
|
|
|
/* Find in hash table */
|
2017-08-02 17:49:47 +00:00
|
|
|
hash = ippool_hash(&member->addr) & this->hashmask;
|
2011-11-02 12:06:18 +00:00
|
|
|
for (p = this->hash[hash]; p; p = p->nexthash) {
|
|
|
|
if (p == member) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p_prev = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p != member) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"ippool_hashdel: Tried to delete member not in hash table");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!p_prev)
|
|
|
|
this->hash[hash] = p->nexthash;
|
|
|
|
else
|
|
|
|
p_prev->nexthash = p->nexthash;
|
|
|
|
|
|
|
|
return 0;
|
2003-07-06 19:33:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
static unsigned long int ippool_hash4(struct in_addr *addr)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
|
|
|
return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0);
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 16:10:43 +00:00
|
|
|
static unsigned long int ippool_hash6(struct in6_addr *addr, unsigned int len)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
2017-08-02 17:49:47 +00:00
|
|
|
/* TODO: Review hash spread for IPv6 */
|
2017-08-08 16:10:43 +00:00
|
|
|
return lookup((unsigned char *)addr->s6_addr, len, 0);
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
unsigned long int ippool_hash(struct in46_addr *addr)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
2017-08-02 17:49:47 +00:00
|
|
|
if (addr->len == 4)
|
|
|
|
return ippool_hash4(&addr->v4);
|
|
|
|
else
|
2017-08-08 16:10:43 +00:00
|
|
|
return ippool_hash6(&addr->v6, addr->len);
|
2017-08-02 17:49:47 +00:00
|
|
|
}
|
2011-11-02 12:06:18 +00:00
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
/* Get IP address and mask */
|
|
|
|
int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool_in, int number)
|
|
|
|
{
|
|
|
|
struct addrinfo *ai;
|
|
|
|
struct addrinfo hints = {
|
|
|
|
.ai_family = AF_UNSPEC,
|
|
|
|
.ai_socktype = SOCK_DGRAM,
|
|
|
|
.ai_flags = 0,
|
|
|
|
.ai_protocol = 0
|
|
|
|
};
|
|
|
|
char pool[strlen(pool_in)+1];
|
|
|
|
|
|
|
|
strcpy(pool, pool_in);
|
|
|
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Find '/' and point to first char after it */
|
|
|
|
char *prefixlen_str = strchr(pool, '/');
|
|
|
|
if (prefixlen_str) {
|
|
|
|
*prefixlen_str = '\0';
|
|
|
|
prefixlen_str++;
|
|
|
|
if (*prefixlen_str == '\0') {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Empty prefix length specified");
|
|
|
|
return -1;
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
2017-08-02 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* convert address */
|
|
|
|
if ((err = getaddrinfo(pool, NULL, &hints, &ai))) {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Bad address");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy address, set lengths */
|
|
|
|
if (ai->ai_family == AF_INET) {
|
|
|
|
*prefixlen = 32;
|
|
|
|
addr->len = sizeof(struct in_addr);
|
|
|
|
addr->v4 = ((struct sockaddr_in*)ai->ai_addr)->sin_addr;
|
|
|
|
} else {
|
|
|
|
*prefixlen = 128;
|
|
|
|
addr->len = sizeof(struct in6_addr);
|
|
|
|
addr->v6 = ((struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
|
|
|
|
}
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
|
|
|
|
/* parse prefixlen */
|
|
|
|
if (prefixlen_str) {
|
|
|
|
char *e;
|
|
|
|
*prefixlen = strtol(prefixlen_str, &e, 10);
|
|
|
|
if (*e != '\0') {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Prefixlen is not an int");
|
|
|
|
return -1;
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
if (*prefixlen > (addr->len * 8)) {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Perfixlen too big");
|
2011-11-02 12:06:18 +00:00
|
|
|
return -1;
|
2017-08-02 17:49:47 +00:00
|
|
|
}
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
return 0;
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
/* Increase IPv4/IPv6 address by 1 */
|
|
|
|
void in46a_inc(struct in46_addr *addr)
|
|
|
|
{
|
|
|
|
size_t addrlen;
|
|
|
|
uint8_t *a = (uint8_t *)&addr->v6;
|
|
|
|
for (addrlen = addr->len; addrlen > 0; addrlen--) {
|
|
|
|
if (++a[addrlen-1])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ippool: Implement and use blacklist instead of blindly using IPPOOL_NOGATEWAY
Commit dda21ed7d4a897c9284c69175d0da598598eae40 modified previous calls
to ippool_new() removing the pass of flags to avoid allocating certain
problematic IPs from the pool to MS, such as the network, gateway and
broadcast IPs.
Today I did some unsucessful tests with osmo-ggsn with a pool "ip prefix
dynamic 176.16.222.0/24", and thus IP 176.16.222.0 was being assigned to
the MS. De-capsulated DNS packets were received in the tun interface,
but the Linux system in there was unable to correctly forward the
packets to the gateway interface connected to the Internet. However,
adding a second MS which got 176.16.222.1 had its packets forwarded
correctly.
However, previous implementation relies on flag IPPOOL_NOGATEWAY flag to
blindly blacklist first IP after the network ip (ie, .0 and .1 are
removed), which limits the IP reserved for the tun device to be .1. If a
different IP in the range is assigned, it may cause issues. As a result,
a blacklist is introduced in this commit to dynamically fetch the tun IP
address and exlucde it from the pool of available IPs.
Change-Id: I8e91f7280d60490c858a769dd578c1c8e54e9243
2017-10-16 12:52:25 +00:00
|
|
|
static bool addr_in_prefix_list(struct in46_addr *addr, struct in46_prefix *list, size_t list_size)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < list_size; i++) {
|
|
|
|
if (in46a_prefix_equal(addr, &list[i].addr))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-04-11 09:40:12 +00:00
|
|
|
/* Create new address pool */
|
2017-08-12 10:55:04 +00:00
|
|
|
int ippool_new(struct ippool_t **this, const struct in46_prefix *dyn, const struct in46_prefix *stat,
|
ippool: Implement and use blacklist instead of blindly using IPPOOL_NOGATEWAY
Commit dda21ed7d4a897c9284c69175d0da598598eae40 modified previous calls
to ippool_new() removing the pass of flags to avoid allocating certain
problematic IPs from the pool to MS, such as the network, gateway and
broadcast IPs.
Today I did some unsucessful tests with osmo-ggsn with a pool "ip prefix
dynamic 176.16.222.0/24", and thus IP 176.16.222.0 was being assigned to
the MS. De-capsulated DNS packets were received in the tun interface,
but the Linux system in there was unable to correctly forward the
packets to the gateway interface connected to the Internet. However,
adding a second MS which got 176.16.222.1 had its packets forwarded
correctly.
However, previous implementation relies on flag IPPOOL_NOGATEWAY flag to
blindly blacklist first IP after the network ip (ie, .0 and .1 are
removed), which limits the IP reserved for the tun device to be .1. If a
different IP in the range is assigned, it may cause issues. As a result,
a blacklist is introduced in this commit to dynamically fetch the tun IP
address and exlucde it from the pool of available IPs.
Change-Id: I8e91f7280d60490c858a769dd578c1c8e54e9243
2017-10-16 12:52:25 +00:00
|
|
|
int flags, struct in46_prefix *blacklist, size_t blacklist_size)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Parse only first instance of pool for now */
|
|
|
|
|
|
|
|
int i;
|
2018-11-22 07:12:28 +00:00
|
|
|
struct in46_addr addr = { 0 };
|
2017-08-02 17:49:47 +00:00
|
|
|
size_t addrprefixlen;
|
|
|
|
struct in46_addr stataddr;
|
|
|
|
size_t stataddrprefixlen;
|
2011-11-02 12:06:18 +00:00
|
|
|
int listsize;
|
|
|
|
int dynsize;
|
|
|
|
unsigned int statsize;
|
|
|
|
|
2017-08-12 10:55:04 +00:00
|
|
|
if (!dyn || dyn->addr.len == 0) {
|
2011-11-02 12:06:18 +00:00
|
|
|
dynsize = 0;
|
|
|
|
} else {
|
2017-08-12 10:55:04 +00:00
|
|
|
addr = dyn->addr;
|
|
|
|
addrprefixlen = dyn->prefixlen;
|
2017-08-08 16:10:43 +00:00
|
|
|
/* we want to work with /64 prefixes, i.e. allocate /64 prefixes rather
|
|
|
|
* than /128 (single IPv6 addresses) */
|
|
|
|
if (addr.len == sizeof(struct in6_addr))
|
|
|
|
addr.len = 64/8;
|
2011-11-02 12:06:18 +00:00
|
|
|
|
2017-10-13 09:56:16 +00:00
|
|
|
dynsize = (1 << (addr.len*8 - addrprefixlen));
|
2011-11-02 12:06:18 +00:00
|
|
|
if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
|
|
|
|
dynsize--;
|
|
|
|
if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
|
|
|
|
dynsize--;
|
ippool: Implement and use blacklist instead of blindly using IPPOOL_NOGATEWAY
Commit dda21ed7d4a897c9284c69175d0da598598eae40 modified previous calls
to ippool_new() removing the pass of flags to avoid allocating certain
problematic IPs from the pool to MS, such as the network, gateway and
broadcast IPs.
Today I did some unsucessful tests with osmo-ggsn with a pool "ip prefix
dynamic 176.16.222.0/24", and thus IP 176.16.222.0 was being assigned to
the MS. De-capsulated DNS packets were received in the tun interface,
but the Linux system in there was unable to correctly forward the
packets to the gateway interface connected to the Internet. However,
adding a second MS which got 176.16.222.1 had its packets forwarded
correctly.
However, previous implementation relies on flag IPPOOL_NOGATEWAY flag to
blindly blacklist first IP after the network ip (ie, .0 and .1 are
removed), which limits the IP reserved for the tun device to be .1. If a
different IP in the range is assigned, it may cause issues. As a result,
a blacklist is introduced in this commit to dynamically fetch the tun IP
address and exlucde it from the pool of available IPs.
Change-Id: I8e91f7280d60490c858a769dd578c1c8e54e9243
2017-10-16 12:52:25 +00:00
|
|
|
/* Exclude included blacklist addresses from pool */
|
|
|
|
for (i = 0; i < blacklist_size; i++) {
|
|
|
|
if (in46a_within_mask(&blacklist[i].addr, &addr, addrprefixlen))
|
|
|
|
dynsize--;
|
|
|
|
}
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-12 10:55:04 +00:00
|
|
|
if (!stat || stat->addr.len == 0) {
|
2011-11-02 12:06:18 +00:00
|
|
|
statsize = 0;
|
2017-08-02 17:49:47 +00:00
|
|
|
stataddr.len = 0;
|
|
|
|
stataddrprefixlen = 0;
|
2011-11-02 12:06:18 +00:00
|
|
|
} else {
|
2017-08-12 10:55:04 +00:00
|
|
|
stataddr = stat->addr;
|
|
|
|
stataddrprefixlen = stat->prefixlen;
|
2011-11-02 12:06:18 +00:00
|
|
|
|
2017-11-05 18:38:54 +00:00
|
|
|
statsize = (1 << (stataddr.len*8 - stataddrprefixlen));
|
2011-11-02 12:06:18 +00:00
|
|
|
if (statsize > IPPOOL_STATSIZE)
|
|
|
|
statsize = IPPOOL_STATSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
listsize = dynsize + statsize; /* Allocate space for static IP addresses */
|
|
|
|
|
|
|
|
if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Failed to allocate memory for ippool");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-08-12 10:55:04 +00:00
|
|
|
(*this)->allowdyn = dyn ? 1 : 0;
|
|
|
|
(*this)->allowstat = stat ? 1 : 0;
|
2017-08-02 17:49:47 +00:00
|
|
|
if (stataddr.len > 0)
|
|
|
|
(*this)->stataddr = stataddr;
|
|
|
|
(*this)->stataddrprefixlen = stataddrprefixlen;
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
(*this)->listsize += listsize;
|
|
|
|
if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Failed to allocate memory for members in ippool");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ((*this)->hashlog = 0;
|
|
|
|
((1 << (*this)->hashlog) < listsize); (*this)->hashlog++) ;
|
|
|
|
|
|
|
|
/* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
|
|
|
|
|
|
|
|
/* Determine hashsize */
|
|
|
|
(*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet */
|
|
|
|
(*this)->hashmask = (*this)->hashsize - 1;
|
|
|
|
|
|
|
|
/* Allocate hash table */
|
2018-11-21 13:26:18 +00:00
|
|
|
(*this)->hash = calloc((*this)->hashsize, sizeof(struct ippoolm_t *));
|
|
|
|
if (!(*this)->hash) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Failed to allocate memory for hash members in ippool");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*this)->firstdyn = NULL;
|
|
|
|
(*this)->lastdyn = NULL;
|
ippool: Implement and use blacklist instead of blindly using IPPOOL_NOGATEWAY
Commit dda21ed7d4a897c9284c69175d0da598598eae40 modified previous calls
to ippool_new() removing the pass of flags to avoid allocating certain
problematic IPs from the pool to MS, such as the network, gateway and
broadcast IPs.
Today I did some unsucessful tests with osmo-ggsn with a pool "ip prefix
dynamic 176.16.222.0/24", and thus IP 176.16.222.0 was being assigned to
the MS. De-capsulated DNS packets were received in the tun interface,
but the Linux system in there was unable to correctly forward the
packets to the gateway interface connected to the Internet. However,
adding a second MS which got 176.16.222.1 had its packets forwarded
correctly.
However, previous implementation relies on flag IPPOOL_NOGATEWAY flag to
blindly blacklist first IP after the network ip (ie, .0 and .1 are
removed), which limits the IP reserved for the tun device to be .1. If a
different IP in the range is assigned, it may cause issues. As a result,
a blacklist is introduced in this commit to dynamically fetch the tun IP
address and exlucde it from the pool of available IPs.
Change-Id: I8e91f7280d60490c858a769dd578c1c8e54e9243
2017-10-16 12:52:25 +00:00
|
|
|
if (flags & IPPOOL_NONETWORK) {
|
2017-08-02 17:49:47 +00:00
|
|
|
in46a_inc(&addr);
|
|
|
|
}
|
2011-11-02 12:06:18 +00:00
|
|
|
for (i = 0; i < dynsize; i++) {
|
ippool: Implement and use blacklist instead of blindly using IPPOOL_NOGATEWAY
Commit dda21ed7d4a897c9284c69175d0da598598eae40 modified previous calls
to ippool_new() removing the pass of flags to avoid allocating certain
problematic IPs from the pool to MS, such as the network, gateway and
broadcast IPs.
Today I did some unsucessful tests with osmo-ggsn with a pool "ip prefix
dynamic 176.16.222.0/24", and thus IP 176.16.222.0 was being assigned to
the MS. De-capsulated DNS packets were received in the tun interface,
but the Linux system in there was unable to correctly forward the
packets to the gateway interface connected to the Internet. However,
adding a second MS which got 176.16.222.1 had its packets forwarded
correctly.
However, previous implementation relies on flag IPPOOL_NOGATEWAY flag to
blindly blacklist first IP after the network ip (ie, .0 and .1 are
removed), which limits the IP reserved for the tun device to be .1. If a
different IP in the range is assigned, it may cause issues. As a result,
a blacklist is introduced in this commit to dynamically fetch the tun IP
address and exlucde it from the pool of available IPs.
Change-Id: I8e91f7280d60490c858a769dd578c1c8e54e9243
2017-10-16 12:52:25 +00:00
|
|
|
if (addr_in_prefix_list(&addr, blacklist, blacklist_size)) {
|
|
|
|
SYS_ERR(DIP, LOGL_DEBUG, 0,
|
|
|
|
"addr blacklisted from pool: %s", in46a_ntoa(&addr));
|
|
|
|
in46a_inc(&addr);
|
|
|
|
i--;
|
|
|
|
continue;
|
|
|
|
}
|
2017-08-02 17:49:47 +00:00
|
|
|
(*this)->member[i].addr = addr;
|
|
|
|
in46a_inc(&addr);
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
(*this)->member[i].inuse = 0;
|
2017-08-12 10:46:39 +00:00
|
|
|
(*this)->member[i].pool = *this;
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
/* Insert into list of unused */
|
|
|
|
(*this)->member[i].prev = (*this)->lastdyn;
|
|
|
|
if ((*this)->lastdyn) {
|
|
|
|
(*this)->lastdyn->next = &((*this)->member[i]);
|
|
|
|
} else {
|
|
|
|
(*this)->firstdyn = &((*this)->member[i]);
|
|
|
|
}
|
|
|
|
(*this)->lastdyn = &((*this)->member[i]);
|
|
|
|
(*this)->member[i].next = NULL; /* Redundant */
|
|
|
|
|
|
|
|
(void)ippool_hashadd(*this, &(*this)->member[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
(*this)->firststat = NULL;
|
|
|
|
(*this)->laststat = NULL;
|
|
|
|
for (i = dynsize; i < listsize; i++) {
|
2017-08-02 17:49:47 +00:00
|
|
|
struct in46_addr *i6al = &(*this)->member[i].addr;
|
|
|
|
memset(i6al, 0, sizeof(*i6al));
|
2011-11-02 12:06:18 +00:00
|
|
|
(*this)->member[i].inuse = 0;
|
2017-08-12 10:46:39 +00:00
|
|
|
(*this)->member[i].pool = *this;
|
2011-11-02 12:06:18 +00:00
|
|
|
|
|
|
|
/* Insert into list of unused */
|
|
|
|
(*this)->member[i].prev = (*this)->laststat;
|
|
|
|
if ((*this)->laststat) {
|
|
|
|
(*this)->laststat->next = &((*this)->member[i]);
|
|
|
|
} else {
|
|
|
|
(*this)->firststat = &((*this)->member[i]);
|
|
|
|
}
|
|
|
|
(*this)->laststat = &((*this)->member[i]);
|
|
|
|
(*this)->member[i].next = NULL; /* Redundant */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(*this);
|
|
|
|
return 0;
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete existing address pool */
|
2011-11-02 12:06:18 +00:00
|
|
|
int ippool_free(struct ippool_t *this)
|
|
|
|
{
|
|
|
|
free(this->hash);
|
|
|
|
free(this->member);
|
|
|
|
free(this);
|
|
|
|
return 0; /* Always OK */
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find an IP address in the pool */
|
|
|
|
int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
|
2017-08-02 17:49:47 +00:00
|
|
|
struct in46_addr *addr)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
|
|
|
struct ippoolm_t *p;
|
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
/* Find in hash table */
|
2017-08-02 17:49:47 +00:00
|
|
|
hash = ippool_hash(addr) & this->hashmask;
|
2011-11-02 12:06:18 +00:00
|
|
|
for (p = this->hash[hash]; p; p = p->nexthash) {
|
2017-08-08 16:10:43 +00:00
|
|
|
if (in46a_prefix_equal(&p->addr, addr)) {
|
2011-11-02 12:06:18 +00:00
|
|
|
if (member)
|
|
|
|
*member = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (member)
|
|
|
|
*member = NULL;
|
2014-12-04 15:32:37 +00:00
|
|
|
/*SYS_ERR(DIP, LOGL_ERROR, 0, "Address could not be found"); */
|
2011-11-02 12:06:18 +00:00
|
|
|
return -1;
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2003-07-06 19:33:18 +00:00
|
|
|
/**
|
|
|
|
* ippool_newip
|
|
|
|
* Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
|
|
|
|
* check to see if the given address is available. If available within
|
|
|
|
* dynamic address space allocate it there, otherwise allocate within static
|
|
|
|
* address space.
|
|
|
|
**/
|
2003-04-11 09:40:12 +00:00
|
|
|
int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
|
2017-08-02 17:49:47 +00:00
|
|
|
struct in46_addr *addr, int statip)
|
2011-11-02 12:06:18 +00:00
|
|
|
{
|
|
|
|
struct ippoolm_t *p;
|
|
|
|
struct ippoolm_t *p2 = NULL;
|
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
/* If static:
|
2017-10-13 12:32:24 +00:00
|
|
|
* Look in dynaddr.
|
2011-11-02 12:06:18 +00:00
|
|
|
* If found remove from firstdyn/lastdyn linked list.
|
|
|
|
* Else allocate from stataddr.
|
|
|
|
* Remove from firststat/laststat linked list.
|
|
|
|
* Insert into hash table.
|
|
|
|
*
|
|
|
|
* If dynamic
|
|
|
|
* Remove from firstdyn/lastdyn linked list.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
int specified = 0;
|
|
|
|
if (addr) {
|
|
|
|
if (addr->len == 4 && addr->v4.s_addr)
|
|
|
|
specified = 1;
|
|
|
|
if (addr->len == 16 && !IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
|
|
|
|
specified = 1;
|
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
/* First check to see if this type of address is allowed */
|
2017-08-02 17:49:47 +00:00
|
|
|
if (specified && statip) { /* IP address given */
|
2011-11-02 12:06:18 +00:00
|
|
|
if (!this->allowstat) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Static IP address not allowed");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_NOT_SUPPORTED;
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
2017-08-02 17:49:47 +00:00
|
|
|
if (!in46a_within_mask(addr, &this->stataddr, this->stataddrprefixlen)) {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Static out of range");
|
2011-11-02 12:06:18 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!this->allowdyn) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Dynamic IP address not allowed");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_NOT_SUPPORTED;
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If IP address given try to find it in dynamic address pool */
|
2017-08-02 17:49:47 +00:00
|
|
|
if (specified) { /* IP address given */
|
2011-11-02 12:06:18 +00:00
|
|
|
/* Find in hash table */
|
2017-08-02 17:49:47 +00:00
|
|
|
hash = ippool_hash(addr) & this->hashmask;
|
2011-11-02 12:06:18 +00:00
|
|
|
for (p = this->hash[hash]; p; p = p->nexthash) {
|
2017-08-08 16:10:43 +00:00
|
|
|
if (in46a_prefix_equal(&p->addr, addr)) {
|
2011-11-02 12:06:18 +00:00
|
|
|
p2 = p;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If IP was already allocated we can not use it */
|
|
|
|
if ((!statip) && (p2) && (p2->inuse)) {
|
|
|
|
p2 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If not found yet and dynamic IP then allocate dynamic IP */
|
|
|
|
if ((!p2) && (!statip)) {
|
|
|
|
if (!this->firstdyn) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"No more IP addresses available");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_ADDR_OCCUPIED;
|
2011-11-02 12:06:18 +00:00
|
|
|
} else
|
|
|
|
p2 = this->firstdyn;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p2) { /* Was allocated from dynamic address pool */
|
|
|
|
if (p2->inuse) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"IP address allready in use");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_SYS_FAIL; /* Allready in use / Should not happen */
|
2011-11-02 12:06:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 16:10:43 +00:00
|
|
|
if (p2->addr.len != addr->len && !(addr->len == 16 && p2->addr.len == 8)) {
|
2017-08-02 17:49:47 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_UNKNOWN_PDP;
|
2017-08-02 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
/* Remove from linked list of free dynamic addresses */
|
|
|
|
if (p2->prev)
|
|
|
|
p2->prev->next = p2->next;
|
|
|
|
else
|
|
|
|
this->firstdyn = p2->next;
|
|
|
|
if (p2->next)
|
|
|
|
p2->next->prev = p2->prev;
|
|
|
|
else
|
|
|
|
this->lastdyn = p2->prev;
|
|
|
|
p2->next = NULL;
|
|
|
|
p2->prev = NULL;
|
|
|
|
p2->inuse = 1; /* Dynamic address in use */
|
|
|
|
|
|
|
|
*member = p2;
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
return 0; /* Success */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It was not possible to allocate from dynamic address pool */
|
|
|
|
/* Try to allocate from static address space */
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
if (specified && (statip)) { /* IP address given */
|
2011-11-02 12:06:18 +00:00
|
|
|
if (!this->firststat) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"No more IP addresses available");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_ADDR_OCCUPIED; /* No more available */
|
2011-11-02 12:06:18 +00:00
|
|
|
} else
|
|
|
|
p2 = this->firststat;
|
|
|
|
|
2017-08-02 17:49:47 +00:00
|
|
|
if (p2->addr.len != addr->len) {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_UNKNOWN_PDP;
|
2017-08-02 17:49:47 +00:00
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
/* Remove from linked list of free static addresses */
|
|
|
|
if (p2->prev)
|
|
|
|
p2->prev->next = p2->next;
|
|
|
|
else
|
|
|
|
this->firststat = p2->next;
|
|
|
|
if (p2->next)
|
|
|
|
p2->next->prev = p2->prev;
|
|
|
|
else
|
|
|
|
this->laststat = p2->prev;
|
|
|
|
p2->next = NULL;
|
|
|
|
p2->prev = NULL;
|
|
|
|
p2->inuse = 2; /* Static address in use */
|
2018-11-21 13:52:43 +00:00
|
|
|
/* p2->addr.len and addr->len already match (see above). */
|
|
|
|
if (p2->addr.len == sizeof(struct in_addr))
|
|
|
|
p2->addr.v4 = addr->v4;
|
|
|
|
else if (p2->addr.len == sizeof(struct in6_addr))
|
|
|
|
p2->addr.v6 = addr->v6;
|
|
|
|
else {
|
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
|
|
|
|
return -GTPCAUSE_UNKNOWN_PDP;
|
|
|
|
}
|
2011-11-02 12:06:18 +00:00
|
|
|
*member = p2;
|
|
|
|
(void)ippool_hashadd(this, *member);
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
return 0; /* Success */
|
|
|
|
}
|
|
|
|
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Could not allocate IP address");
|
2017-08-02 22:00:23 +00:00
|
|
|
return -GTPCAUSE_SYS_FAIL; /* Should never get here. TODO: Bad code */
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2011-11-02 12:06:18 +00:00
|
|
|
int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
|
|
|
|
if (!member->inuse) {
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
|
2011-11-02 12:06:18 +00:00
|
|
|
return -1; /* Not in use: Should not happen */
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (member->inuse) {
|
|
|
|
case 0: /* Not in use: Should not happen */
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
|
2011-11-02 12:06:18 +00:00
|
|
|
return -1;
|
|
|
|
case 1: /* Allocated from dynamic address space */
|
|
|
|
/* Insert into list of unused */
|
|
|
|
member->prev = this->lastdyn;
|
|
|
|
if (this->lastdyn) {
|
|
|
|
this->lastdyn->next = member;
|
|
|
|
} else {
|
|
|
|
this->firstdyn = member;
|
|
|
|
}
|
|
|
|
this->lastdyn = member;
|
|
|
|
|
|
|
|
member->inuse = 0;
|
|
|
|
member->peer = NULL;
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
return 0;
|
|
|
|
case 2: /* Allocated from static address space */
|
|
|
|
if (ippool_hashdel(this, member))
|
|
|
|
return -1;
|
|
|
|
/* Insert into list of unused */
|
|
|
|
member->prev = this->laststat;
|
|
|
|
if (this->laststat) {
|
|
|
|
this->laststat->next = member;
|
|
|
|
} else {
|
|
|
|
this->firststat = member;
|
|
|
|
}
|
|
|
|
this->laststat = member;
|
|
|
|
|
|
|
|
member->inuse = 0;
|
2017-08-02 17:49:47 +00:00
|
|
|
memset(&member->addr, 0, sizeof(member->addr));
|
2011-11-02 12:06:18 +00:00
|
|
|
member->peer = NULL;
|
|
|
|
member->nexthash = NULL;
|
|
|
|
if (0)
|
|
|
|
(void)ippool_printaddr(this);
|
|
|
|
return 0;
|
|
|
|
default: /* Should not happen */
|
2014-12-04 15:32:37 +00:00
|
|
|
SYS_ERR(DIP, LOGL_ERROR, 0,
|
2011-11-02 12:06:18 +00:00
|
|
|
"Could not free IP address");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-04-11 09:40:12 +00:00
|
|
|
}
|