Annotation of embedaddon/coova-chilli/src/ippool.c, revision 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>