blob: c3eb2674f015da80e4b96f9298c944f89e8b7e3a [file] [log] [blame]
jjakoada9ffa2004-12-30 16:39:11 +00001/*
jjakoa7cd2492003-04-11 09:40:12 +00002 * IP address pool functions.
jjakoc3213962004-09-09 20:23:50 +00003 * Copyright (C) 2003, 2004 Mondru AB.
Harald Welted12eab92017-08-02 19:49:47 +02004 * Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
jjakoada9ffa2004-12-30 16:39:11 +00005 *
jjakoa7cd2492003-04-11 09:40:12 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
10 *
jjakoa7cd2492003-04-11 09:40:12 +000011 */
12
jjako06e9f122004-01-19 18:37:58 +000013#include <sys/types.h>
Harald Weltebed35df2011-11-02 13:06:18 +010014#include <netinet/in.h> /* in_addr */
15#include <stdlib.h> /* calloc */
16#include <stdio.h> /* sscanf */
jjakoc3213962004-09-09 20:23:50 +000017#include <string.h>
18#include <sys/socket.h>
19#include <arpa/inet.h>
Harald Welted12eab92017-08-02 19:49:47 +020020#include <netdb.h>
jjakoc3213962004-09-09 20:23:50 +000021#include "syserr.h"
jjakoa7cd2492003-04-11 09:40:12 +000022#include "ippool.h"
jjakoada9ffa2004-12-30 16:39:11 +000023#include "lookup.h"
jjakoa7cd2492003-04-11 09:40:12 +000024
Harald Weltebed35df2011-11-02 13:06:18 +010025int ippool_printaddr(struct ippool_t *this)
26{
27 unsigned int n;
28 printf("ippool_printaddr\n");
29 printf("Firstdyn %d\n", this->firstdyn - this->member);
30 printf("Lastdyn %d\n", this->lastdyn - this->member);
31 printf("Firststat %d\n", this->firststat - this->member);
32 printf("Laststat %d\n", this->laststat - this->member);
33 printf("Listsize %d\n", this->listsize);
jjakoa7cd2492003-04-11 09:40:12 +000034
Harald Weltebed35df2011-11-02 13:06:18 +010035 for (n = 0; n < this->listsize; n++) {
Harald Welted12eab92017-08-02 19:49:47 +020036 char s[256];
37 in46a_ntop(&this->member[n].addr, s, sizeof(s));
38 printf("Unit %d inuse %d prev %d next %d addr %s\n",
Harald Weltebed35df2011-11-02 13:06:18 +010039 n,
40 this->member[n].inuse,
41 this->member[n].prev - this->member,
42 this->member[n].next - this->member,
Harald Welted12eab92017-08-02 19:49:47 +020043 s);
Harald Weltebed35df2011-11-02 13:06:18 +010044 }
45 return 0;
jjakoa7cd2492003-04-11 09:40:12 +000046}
47
Harald Weltebed35df2011-11-02 13:06:18 +010048int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member)
49{
50 uint32_t hash;
51 struct ippoolm_t *p;
52 struct ippoolm_t *p_prev = NULL;
jjako88c22162003-07-06 19:33:18 +000053
Harald Weltebed35df2011-11-02 13:06:18 +010054 /* Insert into hash table */
Harald Welted12eab92017-08-02 19:49:47 +020055 hash = ippool_hash(&member->addr) & this->hashmask;
Harald Weltebed35df2011-11-02 13:06:18 +010056 for (p = this->hash[hash]; p; p = p->nexthash)
57 p_prev = p;
58 if (!p_prev)
59 this->hash[hash] = member;
60 else
61 p_prev->nexthash = member;
62 return 0; /* Always OK to insert */
jjako88c22162003-07-06 19:33:18 +000063}
64
Harald Weltebed35df2011-11-02 13:06:18 +010065int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member)
66{
67 uint32_t hash;
68 struct ippoolm_t *p;
69 struct ippoolm_t *p_prev = NULL;
jjako88c22162003-07-06 19:33:18 +000070
Harald Weltebed35df2011-11-02 13:06:18 +010071 /* Find in hash table */
Harald Welted12eab92017-08-02 19:49:47 +020072 hash = ippool_hash(&member->addr) & this->hashmask;
Harald Weltebed35df2011-11-02 13:06:18 +010073 for (p = this->hash[hash]; p; p = p->nexthash) {
74 if (p == member) {
75 break;
76 }
77 p_prev = p;
78 }
jjako88c22162003-07-06 19:33:18 +000079
Harald Weltebed35df2011-11-02 13:06:18 +010080 if (p != member) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010081 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +010082 "ippool_hashdel: Tried to delete member not in hash table");
83 return -1;
84 }
jjako88c22162003-07-06 19:33:18 +000085
Harald Weltebed35df2011-11-02 13:06:18 +010086 if (!p_prev)
87 this->hash[hash] = p->nexthash;
88 else
89 p_prev->nexthash = p->nexthash;
jjako88c22162003-07-06 19:33:18 +000090
Harald Weltebed35df2011-11-02 13:06:18 +010091 return 0;
jjako88c22162003-07-06 19:33:18 +000092}
93
Harald Welted12eab92017-08-02 19:49:47 +020094static unsigned long int ippool_hash4(struct in_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +010095{
96 return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0);
jjakoa7cd2492003-04-11 09:40:12 +000097}
98
Harald Welted12eab92017-08-02 19:49:47 +020099static unsigned long int ippool_hash6(struct in6_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100100{
Harald Welted12eab92017-08-02 19:49:47 +0200101 /* TODO: Review hash spread for IPv6 */
102 return lookup((unsigned char *)addr->s6_addr, sizeof(addr->s6_addr),
Harald Weltebed35df2011-11-02 13:06:18 +0100103 0);
jjakoa7cd2492003-04-11 09:40:12 +0000104}
Harald Welted12eab92017-08-02 19:49:47 +0200105
106unsigned long int ippool_hash(struct in46_addr *addr)
107{
108 if (addr->len == 4)
109 return ippool_hash4(&addr->v4);
110 else
111 return ippool_hash6(&addr->v6);
112}
jjakoa7cd2492003-04-11 09:40:12 +0000113
jjakoa7cd2492003-04-11 09:40:12 +0000114/* Get IP address and mask */
Harald Welted12eab92017-08-02 19:49:47 +0200115int ippool_aton(struct in46_addr *addr, size_t *prefixlen, const char *pool_in, int number)
Harald Weltebed35df2011-11-02 13:06:18 +0100116{
Harald Welted12eab92017-08-02 19:49:47 +0200117 struct addrinfo *ai;
118 struct addrinfo hints = {
119 .ai_family = AF_UNSPEC,
120 .ai_socktype = SOCK_DGRAM,
121 .ai_flags = 0,
122 .ai_protocol = 0
123 };
124 char pool[strlen(pool_in)+1];
jjakoa7cd2492003-04-11 09:40:12 +0000125
Harald Welted12eab92017-08-02 19:49:47 +0200126 strcpy(pool, pool_in);
jjakoa7cd2492003-04-11 09:40:12 +0000127
Harald Welted12eab92017-08-02 19:49:47 +0200128 int err;
jjakoa7cd2492003-04-11 09:40:12 +0000129
Harald Welted12eab92017-08-02 19:49:47 +0200130 /* Find '/' and point to first char after it */
131 char *prefixlen_str = strchr(pool, '/');
132 if (prefixlen_str) {
133 *prefixlen_str = '\0';
134 prefixlen_str++;
135 if (*prefixlen_str == '\0') {
136 SYS_ERR(DIP, LOGL_ERROR, 0, "Empty prefix length specified");
137 return -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100138 }
Harald Weltebed35df2011-11-02 13:06:18 +0100139 }
jjakoa7cd2492003-04-11 09:40:12 +0000140
Harald Welted12eab92017-08-02 19:49:47 +0200141 /* convert address */
142 if ((err = getaddrinfo(pool, NULL, &hints, &ai))) {
143 SYS_ERR(DIP, LOGL_ERROR, 0, "Bad address");
Harald Weltebed35df2011-11-02 13:06:18 +0100144 return -1;
Harald Welted12eab92017-08-02 19:49:47 +0200145 }
146
147 /* Copy address, set lengths */
148 if (ai->ai_family == AF_INET) {
149 *prefixlen = 32;
150 addr->len = sizeof(struct in_addr);
151 addr->v4 = ((struct sockaddr_in*)ai->ai_addr)->sin_addr;
152 } else {
153 *prefixlen = 128;
154 addr->len = sizeof(struct in6_addr);
155 addr->v6 = ((struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
156 }
157 freeaddrinfo(ai);
158
159 /* parse prefixlen */
160 if (prefixlen_str) {
161 char *e;
162 *prefixlen = strtol(prefixlen_str, &e, 10);
163 if (*e != '\0') {
164 SYS_ERR(DIP, LOGL_ERROR, 0, "Prefixlen is not an int");
165 return -1;
166 }
167 }
168
169 if (*prefixlen > (addr->len * 8)) {
170 SYS_ERR(DIP, LOGL_ERROR, 0, "Perfixlen too big");
171 return -1;
172 }
jjakoa7cd2492003-04-11 09:40:12 +0000173
Harald Weltebed35df2011-11-02 13:06:18 +0100174 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000175}
176
Harald Welted12eab92017-08-02 19:49:47 +0200177/* Increase IPv4/IPv6 address by 1 */
178void in46a_inc(struct in46_addr *addr)
179{
180 size_t addrlen;
181 uint8_t *a = (uint8_t *)&addr->v6;
182 for (addrlen = addr->len; addrlen > 0; addrlen--) {
183 if (++a[addrlen-1])
184 break;
185 }
186}
187
jjakoa7cd2492003-04-11 09:40:12 +0000188/* Create new address pool */
Harald Weltebed35df2011-11-02 13:06:18 +0100189int ippool_new(struct ippool_t **this, char *dyn, char *stat,
190 int allowdyn, int allowstat, int flags)
191{
jjakoa7cd2492003-04-11 09:40:12 +0000192
Harald Weltebed35df2011-11-02 13:06:18 +0100193 /* Parse only first instance of pool for now */
jjakoa7cd2492003-04-11 09:40:12 +0000194
Harald Weltebed35df2011-11-02 13:06:18 +0100195 int i;
Harald Welted12eab92017-08-02 19:49:47 +0200196 struct in46_addr addr;
197 size_t addrprefixlen;
198 struct in46_addr stataddr;
199 size_t stataddrprefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +0100200 int listsize;
201 int dynsize;
202 unsigned int statsize;
jjakoa7cd2492003-04-11 09:40:12 +0000203
Harald Weltebed35df2011-11-02 13:06:18 +0100204 if (!allowdyn) {
205 dynsize = 0;
206 } else {
Harald Welted12eab92017-08-02 19:49:47 +0200207 if (ippool_aton(&addr, &addrprefixlen, dyn, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100208 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100209 "Failed to parse dynamic pool");
210 return -1;
211 }
jjakoc6762cf2004-04-28 14:52:58 +0000212
Harald Weltebed35df2011-11-02 13:06:18 +0100213 /* Set IPPOOL_NONETWORK if IPPOOL_NOGATEWAY is set */
214 if (flags & IPPOOL_NOGATEWAY) {
215 flags |= IPPOOL_NONETWORK;
216 }
jjakoa7cd2492003-04-11 09:40:12 +0000217
Harald Welted12eab92017-08-02 19:49:47 +0200218 dynsize = (1 << (addr.len*8 - addrprefixlen)) -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100219 if (flags & IPPOOL_NONETWORK) /* Exclude network address from pool */
220 dynsize--;
221 if (flags & IPPOOL_NOGATEWAY) /* Exclude gateway address from pool */
222 dynsize--;
223 if (flags & IPPOOL_NOBROADCAST) /* Exclude broadcast address from pool */
224 dynsize--;
225 }
jjakoc3213962004-09-09 20:23:50 +0000226
Harald Weltebed35df2011-11-02 13:06:18 +0100227 if (!allowstat) {
228 statsize = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200229 stataddr.len = 0;
230 stataddrprefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100231 } else {
Harald Welted12eab92017-08-02 19:49:47 +0200232 if (ippool_aton(&stataddr, &stataddrprefixlen, stat, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100233 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100234 "Failed to parse static range");
235 return -1;
236 }
jjako88c22162003-07-06 19:33:18 +0000237
Harald Welted12eab92017-08-02 19:49:47 +0200238 statsize = (1 << (addr.len - addrprefixlen + 1)) -1;
Harald Weltebed35df2011-11-02 13:06:18 +0100239 if (statsize > IPPOOL_STATSIZE)
240 statsize = IPPOOL_STATSIZE;
241 }
jjakoa7cd2492003-04-11 09:40:12 +0000242
Harald Weltebed35df2011-11-02 13:06:18 +0100243 listsize = dynsize + statsize; /* Allocate space for static IP addresses */
jjako88c22162003-07-06 19:33:18 +0000244
Harald Weltebed35df2011-11-02 13:06:18 +0100245 if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100246 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100247 "Failed to allocate memory for ippool");
248 return -1;
249 }
jjakoa7cd2492003-04-11 09:40:12 +0000250
Harald Weltebed35df2011-11-02 13:06:18 +0100251 (*this)->allowdyn = allowdyn;
252 (*this)->allowstat = allowstat;
Harald Welted12eab92017-08-02 19:49:47 +0200253 if (stataddr.len > 0)
254 (*this)->stataddr = stataddr;
255 (*this)->stataddrprefixlen = stataddrprefixlen;
jjakoa7cd2492003-04-11 09:40:12 +0000256
Harald Weltebed35df2011-11-02 13:06:18 +0100257 (*this)->listsize += listsize;
258 if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100259 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100260 "Failed to allocate memory for members in ippool");
261 return -1;
262 }
jjakoa7cd2492003-04-11 09:40:12 +0000263
Harald Weltebed35df2011-11-02 13:06:18 +0100264 for ((*this)->hashlog = 0;
265 ((1 << (*this)->hashlog) < listsize); (*this)->hashlog++) ;
jjakoa7cd2492003-04-11 09:40:12 +0000266
Harald Weltebed35df2011-11-02 13:06:18 +0100267 /* printf ("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog)); */
jjakoa7cd2492003-04-11 09:40:12 +0000268
Harald Weltebed35df2011-11-02 13:06:18 +0100269 /* Determine hashsize */
270 (*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet */
271 (*this)->hashmask = (*this)->hashsize - 1;
jjako88c22162003-07-06 19:33:18 +0000272
Harald Weltebed35df2011-11-02 13:06:18 +0100273 /* Allocate hash table */
274 if (!
275 ((*this)->hash =
276 calloc(sizeof(struct ippoolm_t), (*this)->hashsize))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100277 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100278 "Failed to allocate memory for hash members in ippool");
279 return -1;
280 }
jjako88c22162003-07-06 19:33:18 +0000281
Harald Weltebed35df2011-11-02 13:06:18 +0100282 (*this)->firstdyn = NULL;
283 (*this)->lastdyn = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200284 if (flags & IPPOOL_NOGATEWAY) {
285 in46a_inc(&addr);
286 in46a_inc(&addr);
287 } else if (flags & IPPOOL_NONETWORK) {
288 in46a_inc(&addr);
289 }
Harald Weltebed35df2011-11-02 13:06:18 +0100290 for (i = 0; i < dynsize; i++) {
Harald Welted12eab92017-08-02 19:49:47 +0200291 (*this)->member[i].addr = addr;
292 in46a_inc(&addr);
jjako88c22162003-07-06 19:33:18 +0000293
Harald Weltebed35df2011-11-02 13:06:18 +0100294 (*this)->member[i].inuse = 0;
295
296 /* Insert into list of unused */
297 (*this)->member[i].prev = (*this)->lastdyn;
298 if ((*this)->lastdyn) {
299 (*this)->lastdyn->next = &((*this)->member[i]);
300 } else {
301 (*this)->firstdyn = &((*this)->member[i]);
302 }
303 (*this)->lastdyn = &((*this)->member[i]);
304 (*this)->member[i].next = NULL; /* Redundant */
305
306 (void)ippool_hashadd(*this, &(*this)->member[i]);
307 }
308
309 (*this)->firststat = NULL;
310 (*this)->laststat = NULL;
311 for (i = dynsize; i < listsize; i++) {
Harald Welted12eab92017-08-02 19:49:47 +0200312 struct in46_addr *i6al = &(*this)->member[i].addr;
313 memset(i6al, 0, sizeof(*i6al));
Harald Weltebed35df2011-11-02 13:06:18 +0100314 (*this)->member[i].inuse = 0;
315
316 /* Insert into list of unused */
317 (*this)->member[i].prev = (*this)->laststat;
318 if ((*this)->laststat) {
319 (*this)->laststat->next = &((*this)->member[i]);
320 } else {
321 (*this)->firststat = &((*this)->member[i]);
322 }
323 (*this)->laststat = &((*this)->member[i]);
324 (*this)->member[i].next = NULL; /* Redundant */
325 }
326
327 if (0)
328 (void)ippool_printaddr(*this);
329 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000330}
331
332/* Delete existing address pool */
Harald Weltebed35df2011-11-02 13:06:18 +0100333int ippool_free(struct ippool_t *this)
334{
335 free(this->hash);
336 free(this->member);
337 free(this);
338 return 0; /* Always OK */
jjakoa7cd2492003-04-11 09:40:12 +0000339}
340
341/* Find an IP address in the pool */
342int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
Harald Welted12eab92017-08-02 19:49:47 +0200343 struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100344{
345 struct ippoolm_t *p;
346 uint32_t hash;
jjakoa7cd2492003-04-11 09:40:12 +0000347
Harald Weltebed35df2011-11-02 13:06:18 +0100348 /* Find in hash table */
Harald Welted12eab92017-08-02 19:49:47 +0200349 hash = ippool_hash(addr) & this->hashmask;
Harald Weltebed35df2011-11-02 13:06:18 +0100350 for (p = this->hash[hash]; p; p = p->nexthash) {
Harald Welted12eab92017-08-02 19:49:47 +0200351 if (in46a_equal(&p->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100352 if (member)
353 *member = p;
354 return 0;
355 }
356 }
357 if (member)
358 *member = NULL;
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100359 /*SYS_ERR(DIP, LOGL_ERROR, 0, "Address could not be found"); */
Harald Weltebed35df2011-11-02 13:06:18 +0100360 return -1;
jjakoa7cd2492003-04-11 09:40:12 +0000361}
362
jjako88c22162003-07-06 19:33:18 +0000363/**
364 * ippool_newip
365 * Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
366 * check to see if the given address is available. If available within
367 * dynamic address space allocate it there, otherwise allocate within static
368 * address space.
369**/
jjakoa7cd2492003-04-11 09:40:12 +0000370int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
Harald Welted12eab92017-08-02 19:49:47 +0200371 struct in46_addr *addr, int statip)
Harald Weltebed35df2011-11-02 13:06:18 +0100372{
373 struct ippoolm_t *p;
374 struct ippoolm_t *p2 = NULL;
375 uint32_t hash;
jjakoa7cd2492003-04-11 09:40:12 +0000376
Harald Weltebed35df2011-11-02 13:06:18 +0100377 /* If static:
378 * Look in dynaddr.
379 * If found remove from firstdyn/lastdyn linked list.
380 * Else allocate from stataddr.
381 * Remove from firststat/laststat linked list.
382 * Insert into hash table.
383 *
384 * If dynamic
385 * Remove from firstdyn/lastdyn linked list.
386 *
387 */
jjako88c22162003-07-06 19:33:18 +0000388
Harald Weltebed35df2011-11-02 13:06:18 +0100389 if (0)
390 (void)ippool_printaddr(this);
jjako88c22162003-07-06 19:33:18 +0000391
Harald Welted12eab92017-08-02 19:49:47 +0200392 int specified = 0;
393 if (addr) {
394 if (addr->len == 4 && addr->v4.s_addr)
395 specified = 1;
396 if (addr->len == 16 && !IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
397 specified = 1;
398 }
399
Harald Weltebed35df2011-11-02 13:06:18 +0100400 /* First check to see if this type of address is allowed */
Harald Welted12eab92017-08-02 19:49:47 +0200401 if (specified && statip) { /* IP address given */
Harald Weltebed35df2011-11-02 13:06:18 +0100402 if (!this->allowstat) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100403 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100404 "Static IP address not allowed");
405 return -1;
406 }
Harald Welted12eab92017-08-02 19:49:47 +0200407 if (!in46a_within_mask(addr, &this->stataddr, this->stataddrprefixlen)) {
408 SYS_ERR(DIP, LOGL_ERROR, 0, "Static out of range");
Harald Weltebed35df2011-11-02 13:06:18 +0100409 return -1;
410 }
411 } else {
412 if (!this->allowdyn) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100413 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100414 "Dynamic IP address not allowed");
415 return -1;
416 }
417 }
jjakoa7cd2492003-04-11 09:40:12 +0000418
Harald Weltebed35df2011-11-02 13:06:18 +0100419 /* If IP address given try to find it in dynamic address pool */
Harald Welted12eab92017-08-02 19:49:47 +0200420 if (specified) { /* IP address given */
Harald Weltebed35df2011-11-02 13:06:18 +0100421 /* Find in hash table */
Harald Welted12eab92017-08-02 19:49:47 +0200422 hash = ippool_hash(addr) & this->hashmask;
Harald Weltebed35df2011-11-02 13:06:18 +0100423 for (p = this->hash[hash]; p; p = p->nexthash) {
Harald Welted12eab92017-08-02 19:49:47 +0200424 if (in46a_equal(&p->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100425 p2 = p;
426 break;
427 }
428 }
429 }
jjakoada9ffa2004-12-30 16:39:11 +0000430
Harald Weltebed35df2011-11-02 13:06:18 +0100431 /* If IP was already allocated we can not use it */
432 if ((!statip) && (p2) && (p2->inuse)) {
433 p2 = NULL;
434 }
jjakoada9ffa2004-12-30 16:39:11 +0000435
Harald Weltebed35df2011-11-02 13:06:18 +0100436 /* If not found yet and dynamic IP then allocate dynamic IP */
437 if ((!p2) && (!statip)) {
438 if (!this->firstdyn) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100439 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100440 "No more IP addresses available");
441 return -1;
442 } else
443 p2 = this->firstdyn;
444 }
jjakoc3213962004-09-09 20:23:50 +0000445
Harald Weltebed35df2011-11-02 13:06:18 +0100446 if (p2) { /* Was allocated from dynamic address pool */
447 if (p2->inuse) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100448 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100449 "IP address allready in use");
450 return -1; /* Allready in use / Should not happen */
451 }
jjako88c22162003-07-06 19:33:18 +0000452
Harald Welted12eab92017-08-02 19:49:47 +0200453 if (p2->addr.len != addr->len) {
454 SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
455 return -1;
456 }
457
Harald Weltebed35df2011-11-02 13:06:18 +0100458 /* Remove from linked list of free dynamic addresses */
459 if (p2->prev)
460 p2->prev->next = p2->next;
461 else
462 this->firstdyn = p2->next;
463 if (p2->next)
464 p2->next->prev = p2->prev;
465 else
466 this->lastdyn = p2->prev;
467 p2->next = NULL;
468 p2->prev = NULL;
469 p2->inuse = 1; /* Dynamic address in use */
jjako88c22162003-07-06 19:33:18 +0000470
Harald Weltebed35df2011-11-02 13:06:18 +0100471 *member = p2;
472 if (0)
473 (void)ippool_printaddr(this);
474 return 0; /* Success */
475 }
jjako88c22162003-07-06 19:33:18 +0000476
Harald Weltebed35df2011-11-02 13:06:18 +0100477 /* It was not possible to allocate from dynamic address pool */
478 /* Try to allocate from static address space */
jjako88c22162003-07-06 19:33:18 +0000479
Harald Welted12eab92017-08-02 19:49:47 +0200480 if (specified && (statip)) { /* IP address given */
Harald Weltebed35df2011-11-02 13:06:18 +0100481 if (!this->firststat) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100482 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100483 "No more IP addresses available");
484 return -1; /* No more available */
485 } else
486 p2 = this->firststat;
487
Harald Welted12eab92017-08-02 19:49:47 +0200488 if (p2->addr.len != addr->len) {
489 SYS_ERR(DIP, LOGL_ERROR, 0, "MS requested unsupported PDP context type");
490 return -1;
491 }
492
Harald Weltebed35df2011-11-02 13:06:18 +0100493 /* Remove from linked list of free static addresses */
494 if (p2->prev)
495 p2->prev->next = p2->next;
496 else
497 this->firststat = p2->next;
498 if (p2->next)
499 p2->next->prev = p2->prev;
500 else
501 this->laststat = p2->prev;
502 p2->next = NULL;
503 p2->prev = NULL;
504 p2->inuse = 2; /* Static address in use */
505 memcpy(&p2->addr, addr, sizeof(addr));
506 *member = p2;
507 (void)ippool_hashadd(this, *member);
508 if (0)
509 (void)ippool_printaddr(this);
510 return 0; /* Success */
511 }
512
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100513 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100514 "Could not allocate IP address");
515 return -1; /* Should never get here. TODO: Bad code */
jjakoa7cd2492003-04-11 09:40:12 +0000516}
517
Harald Weltebed35df2011-11-02 13:06:18 +0100518int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member)
519{
jjakoa7cd2492003-04-11 09:40:12 +0000520
Harald Weltebed35df2011-11-02 13:06:18 +0100521 if (0)
522 (void)ippool_printaddr(this);
jjakoa7cd2492003-04-11 09:40:12 +0000523
Harald Weltebed35df2011-11-02 13:06:18 +0100524 if (!member->inuse) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100525 SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
Harald Weltebed35df2011-11-02 13:06:18 +0100526 return -1; /* Not in use: Should not happen */
527 }
jjakoa7cd2492003-04-11 09:40:12 +0000528
Harald Weltebed35df2011-11-02 13:06:18 +0100529 switch (member->inuse) {
530 case 0: /* Not in use: Should not happen */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100531 SYS_ERR(DIP, LOGL_ERROR, 0, "Address not in use");
Harald Weltebed35df2011-11-02 13:06:18 +0100532 return -1;
533 case 1: /* Allocated from dynamic address space */
534 /* Insert into list of unused */
535 member->prev = this->lastdyn;
536 if (this->lastdyn) {
537 this->lastdyn->next = member;
538 } else {
539 this->firstdyn = member;
540 }
541 this->lastdyn = member;
542
543 member->inuse = 0;
544 member->peer = NULL;
545 if (0)
546 (void)ippool_printaddr(this);
547 return 0;
548 case 2: /* Allocated from static address space */
549 if (ippool_hashdel(this, member))
550 return -1;
551 /* Insert into list of unused */
552 member->prev = this->laststat;
553 if (this->laststat) {
554 this->laststat->next = member;
555 } else {
556 this->firststat = member;
557 }
558 this->laststat = member;
559
560 member->inuse = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200561 memset(&member->addr, 0, sizeof(member->addr));
Harald Weltebed35df2011-11-02 13:06:18 +0100562 member->peer = NULL;
563 member->nexthash = NULL;
564 if (0)
565 (void)ippool_printaddr(this);
566 return 0;
567 default: /* Should not happen */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100568 SYS_ERR(DIP, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100569 "Could not free IP address");
570 return -1;
571 }
jjakoa7cd2492003-04-11 09:40:12 +0000572}