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>