Annotation of embedaddon/coova-chilli/src/ippool.c, revision 1.1.1.1
1.1 misho 1: /*
2: *
3: * IP address pool functions.
4: * Copyright (C) 2003, 2004, 2005 Mondru AB.
5: * Copyright (c) 2006-2007 David Bird <david@coova.com>
6: *
7: * The contents of this file may be used under the terms of the GNU
8: * General Public License Version 2, provided that the above copyright
9: * notice and this permission notice is included in all copies or
10: * substantial portions of the software.
11: *
12: */
13:
14: #include "system.h"
15: #include "syserr.h"
16: #include "radius.h"
17: #include "md5.h"
18: #include "dhcp.h"
19: #include "redir.h"
20: #include "ippool.h"
21: #include "lookup.h"
22: #include "chilli.h"
23: #include "options.h"
24:
25: const unsigned int IPPOOL_STATSIZE = 0x10000;
26:
27: int ippool_printaddr(struct ippool_t *this) {
28: int n;
29: printf("ippool_printaddr\n");
30: printf("Firstdyn %d\n", this->firstdyn - this->member);
31: printf("Lastdyn %d\n", this->lastdyn - this->member);
32: printf("Firststat %d\n", this->firststat - this->member);
33: printf("Laststat %d\n", this->laststat - this->member);
34: printf("Listsize %d\n", this->listsize);
35:
36: for (n=0; n<this->listsize; n++) {
37: printf("Unit %d inuse %d prev %d next %d addr %s %x\n",
38: n,
39: this->member[n].inuse,
40: this->member[n].prev - this->member,
41: this->member[n].next - this->member,
42: inet_ntoa(this->member[n].addr),
43: this->member[n].addr.s_addr
44: );
45: }
46: return 0;
47: }
48:
49: int ippool_hashadd(struct ippool_t *this, struct ippoolm_t *member) {
50: uint32_t hash;
51: struct ippoolm_t *p;
52: struct ippoolm_t *p_prev = NULL;
53:
54: /* Insert into hash table */
55: hash = ippool_hash4(&member->addr) & this->hashmask;
56:
57: for (p = this->hash[hash]; p; p = p->nexthash)
58: p_prev = p;
59:
60: if (!p_prev)
61: this->hash[hash] = member;
62: else
63: p_prev->nexthash = member;
64:
65: return 0; /* Always OK to insert */
66: }
67:
68: int ippool_hashdel(struct ippool_t *this, struct ippoolm_t *member) {
69: uint32_t hash;
70: struct ippoolm_t *p;
71: struct ippoolm_t *p_prev = NULL;
72:
73: /* Find in hash table */
74: hash = ippool_hash4(&member->addr) & this->hashmask;
75: for (p = this->hash[hash]; p; p = p->nexthash) {
76: if (p == member) {
77: break;
78: }
79: p_prev = p;
80: }
81:
82: if (p!= member) {
83: log_err(0, "ippool_hashdel: Tried to delete member not in hash table");
84: return -1;
85: }
86:
87: if (!p_prev)
88: this->hash[hash] = p->nexthash;
89: else
90: p_prev->nexthash = p->nexthash;
91:
92: return 0;
93: }
94:
95: uint32_t ippool_hash4(struct in_addr *addr) {
96: return lookup((unsigned char *)&addr->s_addr, sizeof(addr->s_addr), 0);
97: }
98:
99: #ifndef IPPOOL_NOIP6
100: uint32_t ippool_hash6(struct in6_addr *addr) {
101: return lookup((unsigned char *)addr->u6_addr8, sizeof(addr->u6_addr8), 0);
102: }
103: #endif
104:
105: /* Create new address pool */
106: int ippool_new(struct ippool_t **this,
107: char *dyn, int start, int end, char *stat,
108: int allowdyn, int allowstat) {
109:
110: /* Parse only first instance of pool for now */
111:
112: int i;
113: struct in_addr addr;
114: struct in_addr mask;
115: struct in_addr stataddr;
116: struct in_addr statmask;
117: struct in_addr naddr;
118: unsigned int m;
119: unsigned int listsize;
120: unsigned int dynsize;
121: unsigned int statsize;
122:
123: if (!allowdyn) {
124: dynsize = 0;
125: }
126: else {
127: if (option_aton(&addr, &mask, dyn, 0)) {
128: log_err(0, "Failed to parse dynamic pool");
129: return -1;
130: }
131:
132: m = ntohl(mask.s_addr);
133: dynsize = ((~m)+1);
134:
135: if (start > 0 && end > 0) {
136:
137: if (end < start) {
138: log_err(0, "Bad arguments dhcpstart=%d and dhcpend=%d", start, end);
139: return -1;
140: }
141:
142: if ((end - start) > dynsize) {
143: log_err(0, "Too many IPs between dhcpstart=%d and dhcpend=%d for network", start, end);
144: return -1;
145: }
146:
147: dynsize = end - start;
148:
149: } else {
150:
151: if (start > 0) {
152:
153: /*
154: * if only dhcpstart is set, subtract that from count
155: */
156: dynsize -= start;
157:
158: dynsize--;/* no broadcast */
159:
160: } else if (end > 0) {
161:
162: /*
163: * if only dhcpend is set, ensure only that many
164: */
165: if (dynsize > end)
166: dynsize = end;
167:
168: dynsize--;/* no network */
169:
170: } else {
171: dynsize-=2;/* no network, no broadcast */
172: }
173:
174: dynsize--;/* no uamlisten */
175: }
176: }
177:
178: if (!allowstat) {
179: statsize = 0;
180: stataddr.s_addr = 0;
181: statmask.s_addr = 0;
182: }
183: else {
184: if (option_aton(&stataddr, &statmask, stat, 0)) {
185: log_err(0, "Failed to parse static range");
186: return -1;
187: }
188:
189: m = ntohl(statmask.s_addr);
190: statsize = ((~m)+1);
191:
192: if (statsize > IPPOOL_STATSIZE)
193: statsize = IPPOOL_STATSIZE;
194: }
195:
196: listsize = dynsize + statsize; /* Allocate space for static IP addresses */
197:
198: if (!(*this = calloc(sizeof(struct ippool_t), 1))) {
199: log_err(0, "Failed to allocate memory for ippool");
200: return -1;
201: }
202:
203: (*this)->allowdyn = allowdyn;
204: (*this)->allowstat = allowstat;
205: (*this)->stataddr = stataddr;
206: (*this)->statmask = statmask;
207:
208: (*this)->listsize += listsize;
209: if (!((*this)->member = calloc(sizeof(struct ippoolm_t), listsize))){
210: log_err(0, "Failed to allocate memory for members in ippool");
211: return -1;
212: }
213:
214: for ((*this)->hashlog = 0;
215: ((1 << (*this)->hashlog) < listsize);
216: (*this)->hashlog++);
217:
218: log_dbg("Hashlog %d %d %d\n", (*this)->hashlog, listsize, (1 << (*this)->hashlog));
219:
220: /* Determine hashsize */
221: (*this)->hashsize = 1 << (*this)->hashlog; /* Fails if mask=0: All Internet*/
222: (*this)->hashmask = (*this)->hashsize -1;
223:
224: /* Allocate hash table */
225: if (!((*this)->hash = calloc(sizeof(struct ippoolm_t), (*this)->hashsize))){
226: log_err(0, "Failed to allocate memory for hash members in ippool");
227: return -1;
228: }
229:
230: if (start <= 0) /* adjust for skipping network */
231: start = 1;
232:
233: (*this)->firstdyn = NULL;
234: (*this)->lastdyn = NULL;
235: for (i = 0; i<dynsize; i++) {
236:
237: naddr.s_addr = htonl(ntohl(addr.s_addr) + i + start);
238: if (naddr.s_addr == options.uamlisten.s_addr) {
239: start++; /* skip the uamlisten address! */
240: naddr.s_addr = htonl(ntohl(addr.s_addr) + i + start);
241: }
242:
243: (*this)->member[i].addr.s_addr = naddr.s_addr;
244: (*this)->member[i].inuse = 0;
245:
246: /* Insert into list of unused */
247: (*this)->member[i].prev = (*this)->lastdyn;
248: if ((*this)->lastdyn) {
249: (*this)->lastdyn->next = &((*this)->member[i]);
250: }
251: else {
252: (*this)->firstdyn = &((*this)->member[i]);
253: }
254: (*this)->lastdyn = &((*this)->member[i]);
255: (*this)->member[i].next = NULL; /* Redundant */
256:
257: ippool_hashadd(*this, &(*this)->member[i]);
258: }
259:
260: (*this)->firststat = NULL;
261: (*this)->laststat = NULL;
262: for (i = dynsize; i<listsize; i++) {
263: (*this)->member[i].addr.s_addr = 0;
264: (*this)->member[i].inuse = 0;
265:
266: /* Insert into list of unused */
267: (*this)->member[i].prev = (*this)->laststat;
268: if ((*this)->laststat) {
269: (*this)->laststat->next = &((*this)->member[i]);
270: }
271: else {
272: (*this)->firststat = &((*this)->member[i]);
273: }
274: (*this)->laststat = &((*this)->member[i]);
275: (*this)->member[i].next = NULL; /* Redundant */
276: }
277:
278: if (0) ippool_printaddr(*this);
279: return 0;
280: }
281:
282:
283:
284: /* Delete existing address pool */
285: int ippool_free(struct ippool_t *this) {
286: free(this->hash);
287: free(this->member);
288: free(this);
289: return 0; /* Always OK */
290: }
291:
292: /* Find an IP address in the pool */
293: int ippool_getip(struct ippool_t *this, struct ippoolm_t **member,
294: struct in_addr *addr) {
295: struct ippoolm_t *p;
296: uint32_t hash;
297:
298: /* Find in hash table */
299: hash = ippool_hash4(addr) & this->hashmask;
300: for (p = this->hash[hash]; p; p = p->nexthash) {
301: if ((p->addr.s_addr == addr->s_addr) && (p->inuse)) {
302: if (member) *member = p;
303: return 0;
304: }
305: }
306:
307: if (member) *member = NULL;
308: return -1;
309: }
310:
311: /**
312: * ippool_newip
313: * Get an IP address. If addr = 0.0.0.0 get a dynamic IP address. Otherwise
314: * check to see if the given address is available. If available within
315: * dynamic address space allocate it there, otherwise allocate within static
316: * address space.
317: **/
318: int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
319: struct in_addr *addr, int statip) {
320: struct ippoolm_t *p;
321: struct ippoolm_t *p2 = NULL;
322: uint32_t hash;
323:
324: log_dbg("Requesting new %s ip: %s", statip ? "static" : "dynamic", inet_ntoa(*addr));
325:
326: /* If static:
327: * Look in dynaddr.
328: * If found remove from firstdyn/lastdyn linked list.
329: * Else allocate from stataddr.
330: * Remove from firststat/laststat linked list.
331: * Insert into hash table.
332: *
333: * If dynamic
334: * Remove from firstdyn/lastdyn linked list.
335: *
336: */
337:
338: /*if(0)(void)ippool_printaddr(this);*/
339:
340: /* First check to see if this type of address is allowed */
341: if ((addr) && (addr->s_addr) && statip) { /* IP address given */
342: if (!options.uamanyip) {
343: if (!this->allowstat) {
344: log_dbg("Static IP address not allowed");
345: return -1;
346: }
347: if ((addr->s_addr & this->statmask.s_addr) != this->stataddr.s_addr) {
348: log_err(0, "Static out of range");
349: return -1;
350: }
351: }
352: }
353: else {
354: if (!this->allowdyn) {
355: log_err(0, "Dynamic IP address not allowed");
356: return -1;
357: }
358: }
359:
360: /* If IP address given try to find it in address pool */
361: if ((addr) && (addr->s_addr)) { /* IP address given */
362: /* Find in hash table */
363: hash = ippool_hash4(addr) & this->hashmask;
364: for (p = this->hash[hash]; p; p = p->nexthash) {
365: if ((p->addr.s_addr == addr->s_addr)) {
366: p2 = p;
367: break;
368: }
369: }
370: }
371:
372: /* if anyip is set and statip return the same ip */
373: if (statip && options.uamanyip && p2 && p2->inuse == 2) {
374: log_dbg("Found already allocated static ip");
375: *member = p2;
376: return 0;
377: }
378:
379: /* If IP was already allocated we can not use it */
380: if ((!statip) && (p2) && (p2->inuse)) {
381: p2 = NULL;
382: }
383:
384: /* If not found yet and dynamic IP then allocate dynamic IP */
385: if ((!p2) && (!statip) /*XXX: && (!addr || !addr->s_addr)*/) {
386: if (!this->firstdyn) {
387: log_err(0, "No more IP addresses available");
388: return -1;
389: }
390: else
391: p2 = this->firstdyn;
392: }
393:
394: if (p2) { /* Was allocated from dynamic address pool */
395: if (p2->inuse) {
396: log_err(0, "IP address allready in use");
397: return -1; /* Allready in use / Should not happen */
398: }
399:
400: /* Remove from linked list of free dynamic addresses */
401: if (p2->prev)
402: p2->prev->next = p2->next;
403: else
404: this->firstdyn = p2->next;
405:
406: if (p2->next)
407: p2->next->prev = p2->prev;
408: else
409: this->lastdyn = p2->prev;
410:
411: p2->next = NULL;
412: p2->prev = NULL;
413: p2->inuse = 1; /* Dynamic address in use */
414:
415: *member = p2;
416: if (0) (void)ippool_printaddr(this);
417: return 0; /* Success */
418: }
419:
420: /* It was not possible to allocate from dynamic address pool */
421: /* Try to allocate from static address space */
422:
423: if ((addr) && (addr->s_addr) && (statip||options.uamanyip)) { /* IP address given */
424: if (!this->firststat) {
425: log_err(0, "No more IP addresses available");
426: return -1; /* No more available */
427: }
428: else
429: p2 = this->firststat;
430:
431: /* Remove from linked list of free static addresses */
432: if (p2->prev)
433: p2->prev->next = p2->next;
434: else
435: this->firststat = p2->next;
436:
437: if (p2->next)
438: p2->next->prev = p2->prev;
439: else
440: this->laststat = p2->prev;
441:
442: p2->next = NULL;
443: p2->prev = NULL;
444: p2->inuse = 2; /* Static address in use */
445: memcpy(&p2->addr, addr, sizeof(addr));
446: *member = p2;
447:
448: log_dbg("Assigned a static ip to: %s", inet_ntoa(*addr));
449:
450: ippool_hashadd(this, *member);
451:
452: if (0) (void)ippool_printaddr(this);
453: return 0; /* Success */
454: }
455:
456: return -1;
457: }
458:
459:
460: int ippool_freeip(struct ippool_t *this, struct ippoolm_t *member) {
461:
462: if (0) ippool_printaddr(this);
463:
464: if (!member->inuse) {
465: log_err(0, "Address not in use");
466: return -1; /* Not in use: Should not happen */
467: }
468:
469: switch (member->inuse) {
470:
471: case 0: /* Not in use: Should not happen */
472: log_err(0, "Address not in use");
473: return -1;
474:
475: case 1: /* Allocated from dynamic address space */
476: /* Insert into list of unused */
477: member->prev = this->lastdyn;
478:
479: if (this->lastdyn) {
480: this->lastdyn->next = member;
481: }
482: else {
483: this->firstdyn = member;
484: }
485:
486: this->lastdyn = member;
487:
488: member->inuse = 0;
489: member->peer = NULL;
490: if (0) (void)ippool_printaddr(this);
491: return 0;
492:
493: case 2: /* Allocated from static address space */
494: if (ippool_hashdel(this, member))
495: return -1;
496:
497: /* Insert into list of unused */
498: member->prev = this->laststat;
499:
500: if (this->laststat) {
501: this->laststat->next = member;
502: }
503: else {
504: this->firststat = member;
505: }
506:
507: this->laststat = member;
508:
509: member->inuse = 0;
510: member->addr.s_addr = 0;
511: member->peer = NULL;
512: member->nexthash = NULL;
513: if (0) (void)ippool_printaddr(this);
514: return 0;
515:
516: default: /* Should not happen */
517: log_err(0, "Could not free IP address");
518: return -1;
519: }
520: }
521:
522:
523: #ifndef IPPOOL_NOIP6
524: extern uint32_t ippool_hash6(struct in6_addr *addr);
525: extern int ippool_getip6(struct ippool_t *this, struct in6_addr *addr);
526: extern int ippool_returnip6(struct ippool_t *this, struct in6_addr *addr);
527: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>