Annotation of embedaddon/coova-chilli/src/dhcp.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * DHCP library functions.
                      3:  * Copyright (C) 2003, 2004, 2005, 2006 Mondru AB.
                      4:  * Copyright (c) 2006-2008 David Bird <david@coova.com>
                      5:  *
                      6:  * 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:  *
                     11:  */
                     12: 
                     13: #include "system.h"
                     14: #include "syserr.h"
                     15: #include "radius.h"
                     16: #include "radius_wispr.h"
                     17: #include "radius_chillispot.h"
                     18: #include "redir.h"
                     19: #include "md5.h"
                     20: #include "dhcp.h"
                     21: #include "dns.h"
                     22: #include "tun.h"
                     23: #include "chilli.h"
                     24: #include "options.h"
                     25: #include "ippool.h"
                     26: #include "lookup.h"
                     27: 
                     28: const uint32_t DHCP_OPTION_MAGIC      =  0x63825363;
                     29: 
                     30: #ifdef NAIVE
                     31: const static int paranoid = 0; /* Trust that the program has no bugs */
                     32: #else
                     33: const static int paranoid = 0; /* Check for errors which cannot happen */
                     34: #endif
                     35: 
                     36: extern time_t mainclock;
                     37: 
                     38: char *dhcp_state2name(int authstate) {
                     39:   switch(authstate) {
                     40:   case DHCP_AUTH_NONE: return "none";
                     41:   case DHCP_AUTH_DROP: return "drop";
                     42:   case DHCP_AUTH_PASS: return "pass";
                     43:   case DHCP_AUTH_DNAT: return "dnat";
                     44:   case DHCP_AUTH_SPLASH: return "splash";
                     45:   default: return "unknown";
                     46:   }
                     47: }
                     48: 
                     49: void dhcp_list(struct dhcp_t *this, bstring s, bstring pre, bstring post, int listfmt) {
                     50:   struct dhcp_conn_t *conn = this->firstusedconn;
                     51:   if (listfmt == LIST_JSON_FMT) {
                     52:     bcatcstr(s, "{ \"sessions\":[");
                     53:   }
                     54:   while (conn) {
                     55:     if (pre) bconcat(s, pre);
                     56:     dhcp_print(this, s, listfmt, conn);
                     57:     if (post) bconcat(s, post);
                     58:     conn = conn->next;
                     59:   }
                     60:   if (listfmt == LIST_JSON_FMT) {
                     61:     bcatcstr(s, "]}");
                     62:   }
                     63: }
                     64: 
                     65: void dhcp_print(struct dhcp_t *this, bstring s, int listfmt, struct dhcp_conn_t *conn) {
                     66:   struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
                     67:   bstring b = bfromcstr("");
                     68:   bstring tmp = bfromcstr("");
                     69: 
                     70:   if (conn && conn->inuse) {
                     71: 
                     72:     if (listfmt == LIST_JSON_FMT) {
                     73: 
                     74:       if (conn != this->firstusedconn)
                     75:        bcatcstr(b, ",");
                     76: 
                     77:       bcatcstr(b, "{");
                     78: 
                     79:       if (appconn) {
                     80:        bcatcstr(b, "\"nasPort\":");
                     81:        bassignformat(tmp, "%d", appconn->unit);
                     82:        bconcat(b, tmp);
                     83:        bcatcstr(b, ",\"clientState\":");
                     84:        bassignformat(tmp, "%d", appconn->s_state.authenticated);
                     85:        bconcat(b, tmp);
                     86:        bcatcstr(b, ",\"macAddress\":\"");
                     87:        bassignformat(tmp, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
                     88:                      conn->hismac[0], conn->hismac[1], conn->hismac[2],
                     89:                      conn->hismac[3], conn->hismac[4], conn->hismac[5]);
                     90:        bconcat(b, tmp);
                     91:        bcatcstr(b, "\",\"ipAddress\":\"");
                     92:        bcatcstr(b, inet_ntoa(conn->hisip));
                     93:        bcatcstr(b, "\"");
                     94:       }
                     95: 
                     96:     } else {
                     97: 
                     98:       bassignformat(b, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X %s %s",
                     99:                    conn->hismac[0], conn->hismac[1], conn->hismac[2],
                    100:                    conn->hismac[3], conn->hismac[4], conn->hismac[5],
                    101:                    inet_ntoa(conn->hisip), dhcp_state2name(conn->authstate));
                    102: 
                    103:     }
                    104:     
                    105:     if (listfmt && this->cb_getinfo)
                    106:       this->cb_getinfo(conn, b, listfmt);
                    107: 
                    108:     if (listfmt == LIST_JSON_FMT)
                    109:       bcatcstr(b, "}");
                    110:     else
                    111:       bcatcstr(b, "\n");
                    112: 
                    113:     bconcat(s, b);
                    114:   }
                    115: 
                    116:   bdestroy(b);
                    117:   bdestroy(tmp);
                    118: }
                    119: 
                    120: void dhcp_release_mac(struct dhcp_t *this, uint8_t *hwaddr, int term_cause) {
                    121:   struct dhcp_conn_t *conn;
                    122:   if (!dhcp_hashget(this, &conn, hwaddr)) {
                    123:     dhcp_freeconn(conn, term_cause);
                    124:   }
                    125: }
                    126: 
                    127: int dhcp_send(struct dhcp_t *this, struct _net_interface *netif, 
                    128:              unsigned char *hismac, void *packet, size_t length) {
                    129: #if defined(__linux__)
                    130:   struct sockaddr_ll dest;
                    131: 
                    132:   memset(&dest, 0, sizeof(dest));
                    133:   dest.sll_family = AF_PACKET;
                    134:   dest.sll_protocol = htons(netif->protocol);
                    135:   dest.sll_ifindex = netif->ifindex;
                    136:   dest.sll_halen = PKT_ETH_ALEN;
                    137:   memcpy(dest.sll_addr, hismac, PKT_ETH_ALEN);
                    138: 
                    139:   if (sendto(netif->fd, packet, length, 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
                    140: #ifdef ENETDOWN
                    141:     if (errno == ENETDOWN) {
                    142:       net_reopen(netif);
                    143:     }
                    144: #endif
                    145: #ifdef ENXIO
                    146:     if (errno == ENXIO) {
                    147:       net_reopen(netif);
                    148:     }
                    149: #endif
                    150:     log_err(errno, "sendto(fd=%d, len=%d) failed", netif->fd, length);
                    151:     return -1;
                    152:   }
                    153: #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
                    154:   if (write(netif->fd, packet, length) < 0) {
                    155:     log_err(errno, "write() failed");
                    156:     return -1;
                    157:   }
                    158: #endif
                    159:   return 0;
                    160: }
                    161: 
                    162: 
                    163: /**
                    164:  * dhcp_hash()
                    165:  * Generates a 32 bit hash based on a mac address
                    166:  **/
                    167: uint32_t dhcp_hash(uint8_t *hwaddr) {
                    168:   return lookup(hwaddr, PKT_ETH_ALEN, 0);
                    169: }
                    170: 
                    171: 
                    172: /**
                    173:  * dhcp_hashinit()
                    174:  * Initialises hash tables
                    175:  **/
                    176: int dhcp_hashinit(struct dhcp_t *this, int listsize) {
                    177:   /* Determine hashlog */
                    178:   for ((this)->hashlog = 0; 
                    179:        ((1 << (this)->hashlog) < listsize);
                    180:        (this)->hashlog++);
                    181:   
                    182:   /* Determine hashsize */
                    183:   (this)->hashsize = 1 << (this)->hashlog;
                    184:   (this)->hashmask = (this)->hashsize -1;
                    185:   
                    186:   /* Allocate hash table */
                    187:   if (!((this)->hash = calloc(sizeof(struct dhcp_conn_t), (this)->hashsize))){
                    188:     /* Failed to allocate memory for hash members */
                    189:     return -1;
                    190:   }
                    191:   return 0;
                    192: }
                    193: 
                    194: 
                    195: /**
                    196:  * dhcp_hashadd()
                    197:  * Adds a connection to the hash table
                    198:  **/
                    199: int dhcp_hashadd(struct dhcp_t *this, struct dhcp_conn_t *conn) {
                    200:   uint32_t hash;
                    201:   struct dhcp_conn_t *p;
                    202:   struct dhcp_conn_t *p_prev = NULL; 
                    203: 
                    204:   /* Insert into hash table */
                    205:   hash = dhcp_hash(conn->hismac) & this->hashmask;
                    206:   for (p = this->hash[hash]; p; p = p->nexthash)
                    207:     p_prev = p;
                    208:   if (!p_prev)
                    209:     this->hash[hash] = conn;
                    210:   else 
                    211:     p_prev->nexthash = conn;
                    212:   return 0; /* Always OK to insert */
                    213: }
                    214: 
                    215: 
                    216: /**
                    217:  * dhcp_hashdel()
                    218:  * Removes a connection from the hash table
                    219:  **/
                    220: int dhcp_hashdel(struct dhcp_t *this, struct dhcp_conn_t *conn) {
                    221:   uint32_t hash;
                    222:   struct dhcp_conn_t *p;
                    223:   struct dhcp_conn_t *p_prev = NULL; 
                    224: 
                    225:   /* Find in hash table */
                    226:   hash = dhcp_hash(conn->hismac) & this->hashmask;
                    227:   for (p = this->hash[hash]; p; p = p->nexthash) {
                    228:     if (p == conn) {
                    229:       break;
                    230:     }
                    231:     p_prev = p;
                    232:   }
                    233: 
                    234:   if ((paranoid) && (p!= conn)) {
                    235:     log_err(0, "Tried to delete connection not in hash table");
                    236:   }
                    237: 
                    238:   if (!p_prev)
                    239:     this->hash[hash] = p->nexthash;
                    240:   else
                    241:     p_prev->nexthash = p->nexthash;
                    242:   
                    243:   return 0;
                    244: }
                    245: 
                    246: 
                    247: /**
                    248:  * dhcp_hashget()
                    249:  * Uses the hash tables to find a connection based on the mac address.
                    250:  * Returns -1 if not found.
                    251:  **/
                    252: int dhcp_hashget(struct dhcp_t *this, struct dhcp_conn_t **conn,
                    253:                 uint8_t *hwaddr) {
                    254:   struct dhcp_conn_t *p;
                    255:   uint32_t hash;
                    256: 
                    257:   /* Find in hash table */
                    258:   hash = dhcp_hash(hwaddr) & this->hashmask;
                    259:   for (p = this->hash[hash]; p; p = p->nexthash) {
                    260:     if ((!memcmp(p->hismac, hwaddr, PKT_ETH_ALEN)) && (p->inuse)) {
                    261:       *conn = p;
                    262:       return 0;
                    263:     }
                    264:   }
                    265:   *conn = NULL;
                    266:   return -1; /* Address could not be found */
                    267: }
                    268: 
                    269: 
                    270: /**
                    271:  * dhcp_validate()
                    272:  * Valides reference structures of connections. 
                    273:  * Returns the number of active connections
                    274:  **/
                    275: int dhcp_validate(struct dhcp_t *this)
                    276: {
                    277:   int used = 0;
                    278:   int unused = 0;
                    279:   struct dhcp_conn_t *conn;
                    280:   struct dhcp_conn_t *hash_conn;
                    281: 
                    282:   /* Count the number of used connections */
                    283:   conn = this->firstusedconn;
                    284:   while (conn) {
                    285: 
                    286:     if (!conn->inuse) {
                    287:       log_err(0, "Connection with inuse == 0!");
                    288:     }
                    289:     
                    290:     dhcp_hashget(this, &hash_conn, conn->hismac);
                    291: 
                    292:     if (conn != hash_conn) {
                    293:       log_err(0, "Connection could not be found by hashget!");
                    294:     }
                    295: 
                    296:     used ++;
                    297:     conn = conn->next;
                    298:   }
                    299:   
                    300:   /* Count the number of unused connections */
                    301:   conn = this->firstfreeconn;
                    302:   while (conn) {
                    303:     if (conn->inuse) {
                    304:       log_err(0, "Connection with inuse != 0!");
                    305:     }
                    306:     unused ++;
                    307:     conn = conn->next;
                    308:   }
                    309: 
                    310:   if (this->numconn != (used + unused)) {
                    311:     log_err(0, "The number of free and unused connections does not match!");
                    312:     if (this->debug) {
                    313:       log_dbg("used %d unused %d", used, unused);
                    314:       conn = this->firstusedconn;
                    315:       while (conn) {
                    316:        log_dbg("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 
                    317:               conn->hismac[0], conn->hismac[1], conn->hismac[2],
                    318:               conn->hismac[3], conn->hismac[4], conn->hismac[5]);
                    319:        conn = conn->next;
                    320:       }
                    321:     }
                    322:   }
                    323:   
                    324:   return used;
                    325: }
                    326: 
                    327: 
                    328: /**
                    329:  * dhcp_initconn()
                    330:  * Initialises connection references
                    331:  **/
                    332: int dhcp_initconn(struct dhcp_t *this)
                    333: {
                    334:   int n;
                    335:   this->firstusedconn = NULL; /* Redundant */
                    336:   this->lastusedconn  = NULL; /* Redundant */
                    337: 
                    338:   for (n=0; n<this->numconn; n++) {
                    339:     this->conn[n].inuse = 0; /* Redundant */
                    340:     if (n == 0) {
                    341:       this->conn[n].prev = NULL; /* Redundant */
                    342:       this->firstfreeconn = &this->conn[n];
                    343: 
                    344:     }
                    345:     else {
                    346:       this->conn[n].prev = &this->conn[n-1];
                    347:       this->conn[n-1].next = &this->conn[n];
                    348:     }
                    349:     if (n == (this->numconn-1)) {
                    350:       this->conn[n].next = NULL; /* Redundant */
                    351:       this->lastfreeconn  = &this->conn[n];
                    352:     }
                    353:   }
                    354: 
                    355:   if (paranoid) dhcp_validate(this);
                    356: 
                    357:   return 0;
                    358: }
                    359: 
                    360: /**
                    361:  * dhcp_newconn()
                    362:  * Allocates a new connection from the pool. 
                    363:  * Returns -1 if unsuccessful.
                    364:  **/
                    365: int dhcp_newconn(struct dhcp_t *this, 
                    366:                 struct dhcp_conn_t **conn, 
                    367:                 uint8_t *hwaddr)
                    368: {
                    369: 
                    370:   if (this->debug) 
                    371:     log_dbg("DHCP newconn: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 
                    372:            hwaddr[0], hwaddr[1], hwaddr[2],
                    373:            hwaddr[3], hwaddr[4], hwaddr[5]);
                    374: 
                    375: 
                    376:   if (!this->firstfreeconn) {
                    377:     log_err(0, "Out of free connections");
                    378:     return -1;
                    379:   }
                    380: 
                    381:   *conn = this->firstfreeconn;
                    382: 
                    383:   /* Remove from link of free */
                    384:   if (this->firstfreeconn->next) {
                    385:     this->firstfreeconn->next->prev = NULL;
                    386:     this->firstfreeconn = this->firstfreeconn->next;
                    387:   }
                    388:   else { /* Took the last one */
                    389:     this->firstfreeconn = NULL; 
                    390:     this->lastfreeconn = NULL;
                    391:   }
                    392: 
                    393:   /* Initialise structures */
                    394:   memset(*conn, 0, sizeof(**conn));
                    395: 
                    396:   /* Insert into link of used */
                    397:   if (this->firstusedconn) {
                    398:     this->firstusedconn->prev = *conn;
                    399:     (*conn)->next = this->firstusedconn;
                    400:   }
                    401:   else { /* First insert */
                    402:     this->lastusedconn = *conn;
                    403:   }
                    404: 
                    405:   this->firstusedconn = *conn;
                    406: 
                    407:   (*conn)->inuse = 1;
                    408:   (*conn)->parent = this;
                    409: 
                    410:   /* Application specific initialisations */
                    411:   memcpy((*conn)->hismac, hwaddr, PKT_ETH_ALEN);
                    412:   memcpy((*conn)->ourmac, this->ipif.hwaddr, PKT_ETH_ALEN);
                    413:   (*conn)->lasttime = mainclock;
                    414:   
                    415:   dhcp_hashadd(this, *conn);
                    416:   
                    417:   if (paranoid) dhcp_validate(this);
                    418: 
                    419:   /* Inform application that connection was created */
                    420:   if (this->cb_connect)
                    421:     this->cb_connect(*conn);
                    422:   
                    423:   return 0; /* Success */
                    424: }
                    425: 
                    426: 
                    427: /**
                    428:  * dhcp_freeconn()
                    429:  * Returns a connection to the pool. 
                    430:  **/
                    431: int dhcp_freeconn(struct dhcp_conn_t *conn, int term_cause)
                    432: {
                    433:   /* TODO: Always returns success? */
                    434: 
                    435:   struct dhcp_t *this = conn->parent;
                    436: 
                    437:   /* Tell application that we disconnected */
                    438:   if (this->cb_disconnect)
                    439:     this->cb_disconnect(conn, term_cause);
                    440: 
                    441:   if (this->debug)
                    442:     log_dbg("DHCP freeconn: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 
                    443:            conn->hismac[0], conn->hismac[1], conn->hismac[2],
                    444:            conn->hismac[3], conn->hismac[4], conn->hismac[5]);
                    445: 
                    446: 
                    447:   /* Application specific code */
                    448:   /* First remove from hash table */
                    449:   dhcp_hashdel(this, conn);
                    450: 
                    451:   /* Remove from link of used */
                    452:   if ((conn->next) && (conn->prev)) {
                    453:     conn->next->prev = conn->prev;
                    454:     conn->prev->next = conn->next;
                    455:   }
                    456:   else if (conn->next) { /* && prev == 0 */
                    457:     conn->next->prev = NULL;
                    458:     this->firstusedconn = conn->next;
                    459:   }
                    460:   else if (conn->prev) { /* && next == 0 */
                    461:     conn->prev->next = NULL;
                    462:     this->lastusedconn = conn->prev;
                    463:   }
                    464:   else { /* if ((next == 0) && (prev == 0)) */
                    465:     this->firstusedconn = NULL;
                    466:     this->lastusedconn = NULL;
                    467:   }
                    468: 
                    469:   /* Initialise structures */
                    470:   memset(conn, 0, sizeof(*conn));
                    471: 
                    472:   /* Insert into link of free */
                    473:   if (this->firstfreeconn) {
                    474:     this->firstfreeconn->prev = conn;
                    475:   }
                    476:   else { /* First insert */
                    477:     this->lastfreeconn = conn;
                    478:   }
                    479: 
                    480:   conn->next = this->firstfreeconn;
                    481:   this->firstfreeconn = conn;
                    482: 
                    483:   if (paranoid) dhcp_validate(this);
                    484: 
                    485:   return 0;
                    486: }
                    487: 
                    488: 
                    489: /**
                    490:  * dhcp_checkconn()
                    491:  * Checks connections to see if the lease has expired
                    492:  **/
                    493: int dhcp_checkconn(struct dhcp_t *this)
                    494: {
                    495:   struct dhcp_conn_t *conn;
                    496:   time_t now = mainclock;
                    497: 
                    498:   now -= this->lease;
                    499:   conn = this->firstusedconn;
                    500:   while (conn) {
                    501:     if (now > conn->lasttime) {
                    502:       if (this->debug) 
                    503:        log_dbg("DHCP timeout: Removing connection");
                    504:       dhcp_freeconn(conn, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
                    505:       return 0; /* Returning after first deletion */
                    506:     }
                    507:     conn = conn->next;
                    508:   }
                    509:   return 0;
                    510: }
                    511: 
                    512: /**
                    513:  * dhcp_new()
                    514:  * Allocates a new instance of the library
                    515:  **/
                    516: 
                    517: int
                    518: dhcp_new(struct dhcp_t **pdhcp, int numconn, char *interface,
                    519:         int usemac, uint8_t *mac, int promisc, 
                    520:         struct in_addr *listen, int lease, int allowdyn,
                    521:         struct in_addr *uamlisten, uint16_t uamport, int useeapol) {
                    522:   struct dhcp_t *dhcp;
                    523:   
                    524:   if (!(dhcp = *pdhcp = calloc(sizeof(struct dhcp_t), 1))) {
                    525:     log_err(0, "calloc() failed");
                    526:     return -1;
                    527:   }
                    528: 
                    529:   dhcp->numconn = numconn;
                    530: 
                    531:   if (!(dhcp->conn = calloc(sizeof(struct dhcp_conn_t), numconn))) {
                    532:     log_err(0, "calloc() failed");
                    533:     free(dhcp);
                    534:     return -1;
                    535:   }
                    536: 
                    537:   dhcp_initconn(dhcp);
                    538: 
                    539:   if (net_init(&dhcp->ipif, interface, PKT_ETH_PROTO_IP, promisc, usemac ? mac : 0) < 0) {
                    540:     free(dhcp->conn);
                    541:     free(dhcp);
                    542:     return -1; 
                    543:   }
                    544: 
                    545: #if defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__)
                    546:   { 
                    547:     int blen=0;
                    548:     if (ioctl(dhcp->ipif.fd, BIOCGBLEN, &blen) < 0) {
                    549:       log_err(errno,"ioctl() failed!");
                    550:     }
                    551:     dhcp->rbuf_max = blen;
                    552:     if (!(dhcp->rbuf = calloc(dhcp->rbuf_max, 1))) {
                    553:       /* TODO: Free malloc */
                    554:       log_err(errno, "malloc() failed");
                    555:     }
                    556:     dhcp->rbuf_offset = 0;
                    557:     dhcp->rbuf_len = 0;
                    558:   }
                    559: #endif
                    560:   
                    561:   if (net_init(&dhcp->arpif, interface, PKT_ETH_PROTO_ARP, promisc, usemac ? mac : 0) < 0) {
                    562:       close(dhcp->ipif.fd);
                    563:       free(dhcp->conn);
                    564:       free(dhcp);
                    565:       return -1; /* Error reporting done in dhcp_open_eth */
                    566:     }
                    567: 
                    568:   if (useeapol) {
                    569:     if (net_init(&dhcp->eapif, interface, PKT_ETH_PROTO_EAPOL, promisc, usemac ? mac : 0) < 0) {
                    570:       close(dhcp->ipif.fd);
                    571:       close(dhcp->arpif.fd);
                    572:       free(dhcp->conn);
                    573:       free(dhcp);
                    574:       return -1; /* Error reporting done in eapol_open_eth */
                    575:     }
                    576:   }
                    577: 
                    578:   if (options.dhcpgwip.s_addr != 0) {
                    579:     int fd;
                    580:     struct sockaddr_in addr;
                    581:     int on = 1;
                    582: 
                    583:     memset(&addr, 0, sizeof(addr));
                    584:     addr.sin_family = AF_INET;
                    585:     addr.sin_addr.s_addr = htonl(INADDR_ANY);
                    586:     addr.sin_port = htons(68);
                    587:     
                    588:     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
                    589:        bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                    590:       log_err(errno, "socket or bind failed for dhcp relay!");
                    591:       close(dhcp->ipif.fd);
                    592:       close(dhcp->arpif.fd);
                    593:       close(dhcp->eapif.fd);
                    594:       free(dhcp->conn);
                    595:       free(dhcp);
                    596:       close(fd);
                    597:       return -1;
                    598:     }
                    599: 
                    600:     if (setsockopt(dhcp->relayfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
                    601:       log_err(errno, "Can't set reuse option");
                    602:     }
                    603: 
                    604:     dhcp->relayfd = fd;
                    605:   }
                    606: 
                    607:   if (dhcp_hashinit(dhcp, dhcp->numconn))
                    608:     return -1; /* Failed to allocate hash tables */
                    609: 
                    610:   /* Initialise various variables */
                    611:   dhcp->ourip.s_addr = listen->s_addr;
                    612:   dhcp->lease = lease;
                    613:   dhcp->allowdyn = allowdyn;
                    614:   dhcp->uamlisten.s_addr = uamlisten->s_addr;
                    615:   dhcp->uamport = uamport;
                    616: 
                    617:   /* Initialise call back functions */
                    618:   dhcp->cb_data_ind = 0;
                    619:   dhcp->cb_eap_ind = 0;
                    620:   dhcp->cb_request = 0;
                    621:   dhcp->cb_disconnect = 0;
                    622:   dhcp->cb_connect = 0;
                    623:   
                    624:   return 0;
                    625: }
                    626: 
                    627: /**
                    628:  * dhcp_se()
                    629:  * Set dhcp parameters which can be altered at runtime.
                    630:  **/
                    631: int
                    632: dhcp_set(struct dhcp_t *dhcp, int debug) {
                    633:   dhcp->debug = debug;
                    634:   dhcp->anydns = options.uamanydns;
                    635: 
                    636:   /* Copy list of uamserver IP addresses */
                    637:   if (dhcp->authip) free(dhcp->authip);
                    638:   dhcp->authiplen = options.uamserverlen;
                    639: 
                    640:   if (!(dhcp->authip = calloc(sizeof(struct in_addr), options.uamserverlen))) {
                    641:     log_err(0, "calloc() failed");
                    642:     dhcp->authip = 0;
                    643:     return -1;
                    644:   }
                    645:   
                    646:   memcpy(dhcp->authip, &options.uamserver, sizeof(struct in_addr) * options.uamserverlen);
                    647: 
                    648:   return 0;
                    649: }
                    650: 
                    651: /**
                    652:  * dhcp_free()
                    653:  * Releases ressources allocated to the instance of the library
                    654:  **/
                    655: int dhcp_free(struct dhcp_t *dhcp) {
                    656:   if (dhcp->hash) free(dhcp->hash);
                    657:   if (dhcp->authip) free(dhcp->authip);
                    658:   dev_set_flags(dhcp->ipif.devname, dhcp->ipif.devflags);
                    659:   net_close(&dhcp->ipif);
                    660:   net_close(&dhcp->arpif);
                    661:   net_close(&dhcp->eapif);
                    662:   free(dhcp->conn);
                    663:   free(dhcp);
                    664:   return 0;
                    665: }
                    666: 
                    667: /**
                    668:  * dhcp_timeout()
                    669:  * Need to call this function at regular intervals to clean up old connections.
                    670:  **/
                    671: int
                    672: dhcp_timeout(struct dhcp_t *this)
                    673: {
                    674:   if (paranoid) 
                    675:     dhcp_validate(this);
                    676: 
                    677:   dhcp_checkconn(this);
                    678:   
                    679:   return 0;
                    680: }
                    681: 
                    682: /**
                    683:  * dhcp_timeleft()
                    684:  * Use this function to find out when to call dhcp_timeout()
                    685:  * If service is needed after the value given by tvp then tvp
                    686:  * is left unchanged.
                    687:  **/
                    688: struct timeval* dhcp_timeleft(struct dhcp_t *this, struct timeval *tvp) {
                    689:   return tvp;
                    690: }
                    691: 
                    692: int check_garden(pass_through *ptlist, int ptcnt, struct pkt_ippacket_t *pack, int dst) {
                    693:   struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
                    694:   struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
                    695:   pass_through *pt;
                    696:   int i;
                    697: 
                    698:   for (i = 0; i < ptcnt; i++) {
                    699:     pt = &ptlist[i];
                    700:     if (pt->proto == 0 || pack->iph.protocol == pt->proto)
                    701:       if (pt->host.s_addr == 0 || 
                    702:          pt->host.s_addr == ((dst ? pack->iph.daddr : pack->iph.saddr) & pt->mask.s_addr))
                    703:        if (pt->port == 0 || 
                    704:            (pack->iph.protocol == PKT_IP_PROTO_TCP && (dst ? tcph->dst : tcph->src) == htons(pt->port)) ||
                    705:            (pack->iph.protocol == PKT_IP_PROTO_UDP && (dst ? udph->dst : udph->src) == htons(pt->port)))
                    706:          return 1;
                    707:   }
                    708: 
                    709:   return 0;
                    710: }
                    711: 
                    712: static
                    713: int dhcp_nakDNS(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t len) {
                    714:   struct dhcp_t *this = conn->parent;
                    715:   struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
                    716:   struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
                    717:   struct dns_fullpacket_t answer;
                    718: 
                    719:   memcpy(&answer, pack, len); 
                    720:     
                    721:   /* DNS response, with no host error code */
                    722:   answer.dns.flags = htons(0x8583); 
                    723:   
                    724:   /* UDP */
                    725:   answer.udph.src = udph->dst;
                    726:   answer.udph.dst = udph->src;
                    727:   
                    728:   /* IP */
                    729:   answer.iph.check = 0; /* Calculate at end of packet */      
                    730:   memcpy(&answer.iph.daddr, &pack->iph.saddr, PKT_IP_ALEN);
                    731:   memcpy(&answer.iph.saddr, &pack->iph.daddr, PKT_IP_ALEN);
                    732:   
                    733:   /* Ethernet */
                    734:   memcpy(&answer.ethh.dst, &pack->ethh.src, PKT_ETH_ALEN);
                    735:   memcpy(&answer.ethh.src, &pack->ethh.dst, PKT_ETH_ALEN);
                    736:   answer.ethh.prot = htons(PKT_ETH_PROTO_IP);
                    737:     
                    738:   /* checksums */
                    739:   chksum(&answer.iph);
                    740:   
                    741:   dhcp_send(this, &this->ipif, conn->hismac, &answer, len);
                    742: 
                    743:   return 0;
                    744: }
                    745: 
                    746: static 
                    747: int _filterDNSreq(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t plen) {
                    748:   /*struct dhcp_udphdr_t *udph = (struct dhcp_udphdr_t*)pack->payload;*/
                    749:   struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
                    750:   size_t len = plen - DHCP_DNS_HLEN - PKT_UDP_HLEN - PKT_IP_HLEN - PKT_ETH_HLEN;
                    751:   size_t olen = len;
                    752: 
                    753:   uint16_t id = ntohs(dnsp->id);
                    754:   uint16_t flags = ntohs(dnsp->flags);
                    755:   uint16_t qdcount = ntohs(dnsp->qdcount);
                    756:   uint16_t ancount = ntohs(dnsp->ancount);
                    757:   uint16_t nscount = ntohs(dnsp->nscount);
                    758:   uint16_t arcount = ntohs(dnsp->arcount);
                    759: 
                    760:   uint8_t *p_pkt = (uint8_t *)dnsp->records;
                    761:   char q[256];
                    762: 
                    763:   int d = options.debug; /* XXX: debug */
                    764:   int i;
                    765: 
                    766:   if (d) log_dbg("DNS ID:    %d", id);
                    767:   if (d) log_dbg("DNS Flags: %d", flags);
                    768: 
                    769:   /* it was a response? shouldn't be */
                    770:   /*if (((flags & 0x8000) >> 15) == 1) return 0;*/
                    771: 
                    772:   memset(q,0,sizeof(q));
                    773: 
                    774: #undef  copyres
                    775: #define copyres(isq,n)                         \
                    776:   if (d) log_dbg(#n ": %d", n ## count);        \
                    777:   for (i=0; i < n ## count; i++)                \
                    778:     if (dns_copy_res(isq, &p_pkt, &len,         \
                    779:                     (uint8_t *)dnsp, olen,     \
                    780:                      q, sizeof(q)))            \
                    781:       return dhcp_nakDNS(conn,pack,plen)
                    782: 
                    783:   copyres(1,qd);
                    784:   copyres(0,an);
                    785:   copyres(0,ns);
                    786:   copyres(0,ar);
                    787: 
                    788:   if (d) log_dbg("left (should be zero): %d", len);
                    789: 
                    790:   return 1;
                    791: }
                    792: 
                    793: static
                    794: int _filterDNSresp(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t plen) {
                    795:   /*struct dhcp_udphdr_t *udph = (struct dhcp_udphdr_t*)pack->payload;*/
                    796:   struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
                    797:   size_t len = plen - DHCP_DNS_HLEN - PKT_UDP_HLEN - PKT_IP_HLEN - PKT_ETH_HLEN;
                    798:   size_t olen = len;
                    799: 
                    800:   uint16_t id = ntohs(dnsp->id);
                    801:   uint16_t flags = ntohs(dnsp->flags);
                    802:   uint16_t qdcount = ntohs(dnsp->qdcount);
                    803:   uint16_t ancount = ntohs(dnsp->ancount);
                    804:   uint16_t nscount = ntohs(dnsp->nscount);
                    805:   uint16_t arcount = ntohs(dnsp->arcount);
                    806: 
                    807:   uint8_t *p_pkt = (uint8_t *)dnsp->records;
                    808:   char q[256];
                    809: 
                    810:   int d = options.debug; /* XXX: debug */
                    811:   int i;
                    812: 
                    813:   if (d) log_dbg("DNS ID:    %d", id);
                    814:   if (d) log_dbg("DNS Flags: %d", flags);
                    815: 
                    816:   /* it was a query? shouldn't be */
                    817:   if (((flags & 0x8000) >> 15) == 0) return 0;
                    818: 
                    819:   memset(q,0,sizeof(q));
                    820: 
                    821: #undef  copyres
                    822: #define copyres(isq,n)                         \
                    823:   if (d) log_dbg(#n ": %d", n ## count);        \
                    824:   for (i=0; i < n ## count; i++)                \
                    825:     dns_copy_res(isq, &p_pkt, &len,             \
                    826:                     (uint8_t *)dnsp, olen,     \
                    827:                      q, sizeof(q))
                    828: 
                    829:   copyres(1,qd);
                    830:   copyres(0,an);
                    831:   copyres(0,ns);
                    832:   copyres(0,ar);
                    833: 
                    834:   if (d) log_dbg("left (should be zero): %d", len);
                    835: 
                    836:   /*
                    837:   dnsp->flags = htons(flags);
                    838:   dnsp->qdcount = htons(qdcount);
                    839:   dnsp->ancount = htons(ancount);
                    840:   dnsp->nscount = htons(nscount);
                    841:   dnsp->arcount = htons(arcount);
                    842:   */
                    843: 
                    844:   return 1;
                    845: }
                    846: 
                    847: 
                    848: /**
                    849:  * dhcp_doDNAT()
                    850:  * Change destination address to authentication server.
                    851:  **/
                    852: int dhcp_doDNAT(struct dhcp_conn_t *conn, 
                    853:                struct pkt_ippacket_t *pack, size_t len) {
                    854:   struct dhcp_t *this = conn->parent;
                    855:   struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
                    856:   struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
                    857:   int i;
                    858: 
                    859:   /* Allow localhost through network... */
                    860:   if (pack->iph.daddr == INADDR_LOOPBACK)
                    861:     return 0;
                    862: 
                    863:   /* Was it an ICMP request for us? */
                    864:   if (pack->iph.protocol == PKT_IP_PROTO_ICMP)
                    865:     if (pack->iph.daddr == conn->ourip.s_addr)
                    866:       return 0;
                    867: 
                    868:   /* Was it a DNS request? */
                    869:   if (((this->anydns) ||
                    870:        (pack->iph.daddr == conn->dns1.s_addr) ||
                    871:        (pack->iph.daddr == conn->dns2.s_addr)) &&
                    872:       (pack->iph.protocol == PKT_IP_PROTO_UDP && udph->dst == htons(DHCP_DNS))) {
                    873:     if (options.dnsparanoia) {
                    874:       if (_filterDNSreq(conn, pack, len)) 
                    875:        return 0;
                    876:       else /* drop */
                    877:        return -1;
                    878:     } else { /* allow */
                    879:       return 0;
                    880:     }
                    881:   }
                    882: 
                    883:   /* Was it a request for authentication server? */
                    884:   for (i = 0; i<this->authiplen; i++) {
                    885:     if ((pack->iph.daddr == this->authip[i].s_addr) /* &&
                    886:        (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                    887:        ((tcph->dst == htons(DHCP_HTTP)) ||
                    888:        (tcph->dst == htons(DHCP_HTTPS)))*/)
                    889:       return 0; /* Destination was authentication server */
                    890:   }
                    891: 
                    892:   /* Was it a request for local redirection server? */
                    893:   if ((pack->iph.daddr == this->uamlisten.s_addr) &&
                    894:       (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                    895:       (tcph->dst == htons(this->uamport)))
                    896:     return 0; /* Destination was local redir server */
                    897: 
                    898:   /* Was it a request for a pass-through entry? */
                    899:   if (check_garden(options.pass_throughs, options.num_pass_throughs, pack, 1))
                    900:     return 0;
                    901:   /* Check uamdomain driven walled garden */
                    902:   if (check_garden(this->pass_throughs, this->num_pass_throughs, pack, 1))
                    903:     return 0;
                    904: 
                    905:   /* Check appconn session specific pass-throughs */
                    906:   if (conn->peer) {
                    907:     struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
                    908:     if (check_garden(appconn->s_params.pass_throughs, appconn->s_params.pass_through_count, pack, 1))
                    909:       return 0;
                    910:   }
                    911:   
                    912:   /* Was it a http request for another server? */
                    913:   /* We are changing dest IP and dest port to local UAM server */
                    914:   if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                    915:       (tcph->dst == htons(DHCP_HTTP))) {
                    916:     int n;
                    917:     int pos=-1;
                    918: 
                    919:     for (n=0; n<DHCP_DNAT_MAX; n++) {
                    920:       if ((conn->dnatip[n] == pack->iph.daddr) && 
                    921:          (conn->dnatport[n] == tcph->src)) {
                    922:        pos = n;
                    923:        break;
                    924:       }
                    925:     }
                    926:     if (pos==-1) { /* Save for undoing */
                    927:       if (options.usetap) 
                    928:        memcpy(conn->dnatmac[conn->nextdnat], pack->ethh.dst, PKT_ETH_ALEN); 
                    929:       conn->dnatip[conn->nextdnat] = pack->iph.daddr; 
                    930:       conn->dnatport[conn->nextdnat] = tcph->src;
                    931:       conn->nextdnat = (conn->nextdnat + 1) % DHCP_DNAT_MAX;
                    932:     }
                    933: 
                    934:     if (options.usetap) 
                    935:       memcpy(pack->ethh.dst, tuntap(tun).hwaddr, PKT_ETH_ALEN); 
                    936: 
                    937:     pack->iph.daddr = this->uamlisten.s_addr;
                    938:     tcph->dst = htons(this->uamport);
                    939: 
                    940:     chksum(&pack->iph);
                    941:     return 0;
                    942:   }
                    943: 
                    944:   return -1; /* Something else */
                    945: 
                    946: }
                    947: 
                    948: int dhcp_postauthDNAT(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t len, int isreturn) {
                    949:   struct dhcp_t *this = conn->parent;
                    950:   struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
                    951:   /*struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;*/
                    952: 
                    953:   if (options.postauth_proxyport > 0) {
                    954:     if (isreturn) {
                    955:       if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                    956:          (pack->iph.saddr == options.postauth_proxyip.s_addr) &&
                    957:          (tcph->src == htons(options.postauth_proxyport))) {
                    958:        int n;
                    959:        for (n=0; n<DHCP_DNAT_MAX; n++) {
                    960:          if (tcph->dst == conn->dnatport[n]) {
                    961:            if (options.usetap) 
                    962:              memcpy(pack->ethh.src, conn->dnatmac[n], PKT_ETH_ALEN); 
                    963:            pack->iph.saddr = conn->dnatip[n];
                    964:            tcph->src = htons(DHCP_HTTP);
                    965: 
                    966:            chksum(&pack->iph);
                    967: 
                    968:            return 0; /* It was a DNAT reply */
                    969:          }
                    970:        }
                    971:        return 0; 
                    972:       }
                    973:     }
                    974:     else {
                    975:       if ((pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                    976:          (tcph->dst == htons(DHCP_HTTP))) {
                    977: 
                    978:        int n;
                    979:        int pos=-1;
                    980: 
                    981:        for (n = 0; n<this->authiplen; n++)
                    982:          if ((pack->iph.daddr == this->authip[n].s_addr))
                    983:              return 0;
                    984:        
                    985:        for (n=0; n<DHCP_DNAT_MAX; n++) {
                    986:          if ((conn->dnatip[n] == pack->iph.daddr) && 
                    987:              (conn->dnatport[n] == tcph->src)) {
                    988:            pos = n;
                    989:            break;
                    990:          }
                    991:        }
                    992:        
                    993:        if (pos==-1) { /* Save for undoing */
                    994:          if (options.usetap) 
                    995:            memcpy(conn->dnatmac[conn->nextdnat], pack->ethh.dst, PKT_ETH_ALEN); 
                    996:          conn->dnatip[conn->nextdnat] = pack->iph.daddr; 
                    997:          conn->dnatport[conn->nextdnat] = tcph->src;
                    998:          conn->nextdnat = (conn->nextdnat + 1) % DHCP_DNAT_MAX;
                    999:        }
                   1000:        
                   1001:        log_dbg("rewriting packet for post-auth proxy %s:%d",
                   1002:                inet_ntoa(options.postauth_proxyip),
                   1003:                options.postauth_proxyport);
                   1004:        
                   1005:        pack->iph.daddr = options.postauth_proxyip.s_addr;
                   1006:        tcph->dst = htons(options.postauth_proxyport);
                   1007: 
                   1008:        chksum(&pack->iph);
                   1009: 
                   1010:        return 0;
                   1011:       }
                   1012:     }
                   1013:   }
                   1014: 
                   1015:   return -1; /* Something else */
                   1016: }
                   1017: 
                   1018: /**
                   1019:  * dhcp_undoDNAT()
                   1020:  * Change source address back to original server
                   1021:  **/
                   1022: int dhcp_undoDNAT(struct dhcp_conn_t *conn, struct pkt_ippacket_t *pack, size_t *plen) {
                   1023:   struct dhcp_t *this = conn->parent;
                   1024:   struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)pack->payload;
                   1025:   struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
                   1026:   size_t len = *plen;
                   1027:   int i;
                   1028: 
                   1029:   /* Allow localhost through network... */
                   1030:   if (pack->iph.saddr == INADDR_LOOPBACK)
                   1031:     return 0;
                   1032: 
                   1033:   /* Was it a DNS reply? */
                   1034:   if (((this->anydns) ||
                   1035:        (pack->iph.saddr == conn->dns1.s_addr) ||
                   1036:        (pack->iph.saddr == conn->dns2.s_addr)) &&
                   1037:       (pack->iph.protocol == PKT_IP_PROTO_UDP && udph->src == htons(DHCP_DNS))) {
                   1038:     if (options.uamdomains) {
                   1039:        if (_filterDNSresp(conn, pack, *plen)) 
                   1040:          return 0;
                   1041:        else
                   1042:          return -1; /* drop */
                   1043:     } else {   /* always let through dns when not filtering */
                   1044:       return 0;
                   1045:     }
                   1046:   }
                   1047: 
                   1048:   if (pack->iph.protocol == PKT_IP_PROTO_ICMP) {
                   1049:     /* Was it an ICMP reply from us? */
                   1050:     if (pack->iph.saddr == conn->ourip.s_addr)
                   1051:       return 0;
                   1052:     /* Allow for MTU negotiation */
                   1053:     if (options.debug)
                   1054:       log_dbg("Received ICMP type=%d code=%d",
                   1055:              (int)pack->payload[0],(int)pack->payload[1]);
                   1056:     switch((unsigned char)pack->payload[0]) {
                   1057:     case 0:  /* echo reply */
                   1058:     case 3:  /* destination unreachable */
                   1059:     case 5:  /* redirect */
                   1060:     case 11: /* time excedded */
                   1061:       switch((unsigned char)pack->payload[1]) {
                   1062:       case 4: 
                   1063:        log(LOG_NOTICE, "Fragmentation needed ICMP");
                   1064:       }
                   1065:       if (options.debug)
                   1066:        log_dbg("Forwarding ICMP to chilli client");
                   1067:       return 0;
                   1068:     }
                   1069:     /* fail all else */
                   1070:     return -1;
                   1071:   }
                   1072: 
                   1073:   /*
                   1074: 12:46:20.767600 IP 10.1.0.1.49335 > 68.142.197.198.80: S 1442428713:1442428713(0) win 65535 <mss 1460,sackOK,eol>
                   1075: 12:46:20.768234 IP 10.1.0.10.3990 > 10.1.0.1.49335: S 746818639:746818639(0) ack 1442428714 win 5840 <mss 1460,nop,nop,sackOK>
                   1076:   */
                   1077: 
                   1078:   /* Was it a reply from redir server? */
                   1079:   if ((pack->iph.saddr == this->uamlisten.s_addr) &&
                   1080:       (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                   1081:       (tcph->src == htons(this->uamport))) {
                   1082:     int n;
                   1083: 
                   1084:     for (n=0; n<DHCP_DNAT_MAX; n++) {
                   1085:       if (tcph->dst == conn->dnatport[n]) {
                   1086: 
                   1087:        if (options.usetap) 
                   1088:          memcpy(pack->ethh.src, conn->dnatmac[n], PKT_ETH_ALEN); 
                   1089: 
                   1090:        pack->iph.saddr = conn->dnatip[n];
                   1091:        tcph->src = htons(DHCP_HTTP);
                   1092: 
                   1093:        chksum(&pack->iph);
                   1094: 
                   1095:        return 0; /* It was a DNAT reply */
                   1096:       }
                   1097:     }
                   1098:     return 0; /* It was a normal reply from redir server */
                   1099:   }
                   1100:   
                   1101:   /* Was it a normal http or https reply from authentication server? */
                   1102:   /* Was it a normal reply from authentication server? */
                   1103:   for (i = 0; i<this->authiplen; i++) {
                   1104:     if ((pack->iph.saddr == this->authip[i].s_addr) /* &&
                   1105:        (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                   1106:        ((tcph->src == htons(DHCP_HTTP)) ||
                   1107:        (tcph->src == htons(DHCP_HTTPS)))*/)
                   1108:       return 0; /* Destination was authentication server */
                   1109:   }
                   1110:   
                   1111:   /* Was it a reply for a pass-through entry? */
                   1112:   if (check_garden(options.pass_throughs, options.num_pass_throughs, pack, 0))
                   1113:     return 0;
                   1114:   if (check_garden(this->pass_throughs, this->num_pass_throughs, pack, 0))
                   1115:     return 0;
                   1116: 
                   1117:   /* Check appconn session specific pass-throughs */
                   1118:   if (conn->peer) {
                   1119:     struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
                   1120:     if (check_garden(appconn->s_params.pass_throughs, appconn->s_params.pass_through_count, pack, 0))
                   1121:       return 0;
                   1122:   }
                   1123: 
                   1124:   return -1; /* Something else */
                   1125: }
                   1126: 
                   1127: /**
                   1128:  * dhcp_checkDNS()
                   1129:  * Check if it was request for known domain name.
                   1130:  * In case it was a request for a known keyword then
                   1131:  * redirect to the login/logout page
                   1132:  * 2005-09-19: This stuff is highly experimental.
                   1133:  **/
                   1134: int dhcp_checkDNS(struct dhcp_conn_t *conn, 
                   1135:                  struct pkt_ippacket_t *pack, size_t len) {
                   1136: 
                   1137:   struct dhcp_t *this = conn->parent;
                   1138:   struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)pack->payload;
                   1139:   struct dns_packet_t *dnsp = (struct dns_packet_t *)((char*)pack->payload + sizeof(struct pkt_udphdr_t));
                   1140:   struct dns_fullpacket_t answer;
                   1141:   uint8_t *p1 = NULL;
                   1142:   uint8_t *p2 = NULL;
                   1143:   size_t length;
                   1144:   size_t udp_len;
                   1145:   uint8_t query[256];
                   1146:   size_t query_len = 0;
                   1147:   int n;
                   1148: 
                   1149:   log_dbg("DNS ID:    %d", ntohs(dnsp->id));
                   1150:   log_dbg("DNS flags: %d", ntohs(dnsp->flags));
                   1151: 
                   1152:   if ((ntohs(dnsp->flags)   == 0x0100) &&
                   1153:       (ntohs(dnsp->qdcount) == 0x0001) &&
                   1154:       (ntohs(dnsp->ancount) == 0x0000) &&
                   1155:       (ntohs(dnsp->nscount) == 0x0000) &&
                   1156:       (ntohs(dnsp->arcount) == 0x0000)) {
                   1157: 
                   1158:     log_dbg("It was a query %s", dnsp->records);
                   1159: 
                   1160:     p1 = dnsp->records + 1 + dnsp->records[0];
                   1161:     p2 = dnsp->records;
                   1162: 
                   1163:     do {
                   1164:       if (query_len < 256)
                   1165:        query[query_len++] = *p2;
                   1166:     } while (*p2++ != 0); /* TODO */
                   1167: 
                   1168:     for (n=0; n<4; n++) {
                   1169:       if (query_len < 256)
                   1170:        query[query_len++] = *p2++;
                   1171:     }
                   1172: 
                   1173:     query[query_len++] = 0xc0;
                   1174:     query[query_len++] = 0x0c;
                   1175:     query[query_len++] = 0x00;
                   1176:     query[query_len++] = 0x01;
                   1177:     query[query_len++] = 0x00;
                   1178:     query[query_len++] = 0x01;
                   1179:     query[query_len++] = 0x00;
                   1180:     query[query_len++] = 0x00;
                   1181:     query[query_len++] = 0x01;
                   1182:     query[query_len++] = 0x2c;
                   1183:     query[query_len++] = 0x00;
                   1184:     query[query_len++] = 0x04;
                   1185:     memcpy(&query[query_len], &conn->ourip.s_addr, 4);
                   1186:     query_len += 4;
                   1187: 
                   1188:     if (!memcmp(p1, 
                   1189:                "\3key\12chillispot\3org", 
                   1190:                sizeof("\3key\12chillispot\3org"))) {
                   1191:       log_dbg("It was a matching query %s: \n", dnsp->records);
                   1192:       memcpy(&answer, pack, len); /* TODO */
                   1193:       
                   1194:       /* DNS Header */
                   1195:       answer.dns.id      = dnsp->id;
                   1196:       answer.dns.flags   = htons(0x8000);
                   1197:       answer.dns.qdcount = htons(0x0001);
                   1198:       answer.dns.ancount = htons(0x0001);
                   1199:       answer.dns.nscount = htons(0x0000);
                   1200:       answer.dns.arcount = htons(0x0000);
                   1201:       memcpy(answer.dns.records, query, query_len);
                   1202:       
                   1203:       /* UDP header */
                   1204:       udp_len = query_len + DHCP_DNS_HLEN + PKT_UDP_HLEN;
                   1205:       answer.udph.len = htons(udp_len);
                   1206:       answer.udph.src = udph->dst;
                   1207:       answer.udph.dst = udph->src;
                   1208:       
                   1209:       /* IP header */
                   1210:       answer.iph.version_ihl = PKT_IP_VER_HLEN;
                   1211:       answer.iph.tos = 0;
                   1212:       answer.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
                   1213:       answer.iph.id = 0;
                   1214:       answer.iph.frag_off = 0;
                   1215:       answer.iph.ttl = 0x10;
                   1216:       answer.iph.protocol = 0x11;
                   1217:       answer.iph.check = 0; /* Calculate at end of packet */      
                   1218:       memcpy(&answer.iph.daddr, &pack->iph.saddr, PKT_IP_ALEN);
                   1219:       memcpy(&answer.iph.saddr, &pack->iph.saddr, PKT_IP_ALEN);
                   1220: 
                   1221:       /* Ethernet header */
                   1222:       memcpy(&answer.ethh.dst, &pack->ethh.src, PKT_ETH_ALEN);
                   1223:       memcpy(&answer.ethh.src, &pack->ethh.dst, PKT_ETH_ALEN);
                   1224:       answer.ethh.prot = htons(PKT_ETH_PROTO_IP);
                   1225: 
                   1226:       /* Work out checksums */
                   1227:       chksum(&answer.iph);
                   1228: 
                   1229:       /* Calculate total length */
                   1230:       length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
                   1231:       
                   1232:       return dhcp_send(this, &this->ipif, conn->hismac, &answer, length);
                   1233:     }
                   1234:   }
                   1235:   return -1; /* Something else */
                   1236: }
                   1237: 
                   1238: /**
                   1239:  * dhcp_getdefault()
                   1240:  * Fill in a DHCP packet with most essential values
                   1241:  **/
                   1242: int
                   1243: dhcp_getdefault(struct dhcp_fullpacket_t *pack) {
                   1244: 
                   1245:   /* Initialise reply packet with request */
                   1246:   memset(pack, 0, sizeof(struct dhcp_fullpacket_t));
                   1247: 
                   1248:   /* DHCP Payload */
                   1249:   pack->dhcp.op     = DHCP_BOOTREPLY;
                   1250:   pack->dhcp.htype  = DHCP_HTYPE_ETH;
                   1251:   pack->dhcp.hlen   = PKT_ETH_ALEN;
                   1252: 
                   1253:   /* IP header */
                   1254:   pack->iph.version_ihl = PKT_IP_VER_HLEN;
                   1255:   pack->iph.tos = 0;
                   1256:   pack->iph.tot_len = 0; /* Calculate at end of packet */
                   1257:   pack->iph.id = 0;
                   1258:   pack->iph.frag_off = 0;
                   1259:   pack->iph.ttl = 0x10;
                   1260:   pack->iph.protocol = 0x11;
                   1261:   pack->iph.check = 0; /* Calculate at end of packet */
                   1262: 
                   1263:   /* Ethernet header */
                   1264:   pack->ethh.prot = htons(PKT_ETH_PROTO_IP);
                   1265: 
                   1266:   return 0;
                   1267: }
                   1268: 
                   1269: /**
                   1270:  * dhcp_create_pkt()
                   1271:  * Create a new typed DHCP packet
                   1272:  */
                   1273: int
                   1274: dhcp_create_pkt(uint8_t type, struct dhcp_fullpacket_t *pack, 
                   1275:                struct dhcp_fullpacket_t *req, struct dhcp_conn_t *conn) {
                   1276:   struct dhcp_t *this = conn->parent;
                   1277:   int pos = 0;
                   1278: 
                   1279:   dhcp_getdefault(pack);
                   1280: 
                   1281:   pack->dhcp.xid      = req->dhcp.xid;
                   1282:   pack->dhcp.flags[0] = req->dhcp.flags[0];
                   1283:   pack->dhcp.flags[1] = req->dhcp.flags[1];
                   1284:   pack->dhcp.giaddr   = req->dhcp.giaddr;
                   1285: 
                   1286:   memcpy(&pack->dhcp.chaddr, &req->dhcp.chaddr, DHCP_CHADDR_LEN);
                   1287:   memcpy(&pack->dhcp.sname, conn->dhcp_opts.sname, DHCP_SNAME_LEN);
                   1288:   memcpy(&pack->dhcp.file, conn->dhcp_opts.file, DHCP_FILE_LEN);
                   1289: 
                   1290:   log_dbg("!!! dhcp server : %s !!!", pack->dhcp.sname);
                   1291: 
                   1292:   switch(type) {
                   1293:   case DHCPOFFER:
                   1294:     pack->dhcp.yiaddr = conn->hisip.s_addr;
                   1295:     break;
                   1296:   case DHCPACK:
                   1297:     pack->dhcp.xid    = req->dhcp.xid;
                   1298:     pack->dhcp.ciaddr = req->dhcp.ciaddr;
                   1299:     pack->dhcp.yiaddr = conn->hisip.s_addr;
                   1300:     break;
                   1301:   case DHCPNAK:
                   1302:     break;
                   1303:   }
                   1304: 
                   1305:   /* Ethernet Header */
                   1306:   memcpy(pack->ethh.dst, conn->hismac, PKT_ETH_ALEN);
                   1307:   memcpy(pack->ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   1308: 
                   1309:   /* UDP and IP Headers */
                   1310:   pack->udph.src = htons(DHCP_BOOTPS);
                   1311:   pack->iph.saddr = conn->ourip.s_addr;
                   1312: 
                   1313:   /** http://www.faqs.org/rfcs/rfc1542.html
                   1314:       BOOTREQUEST fields     BOOTREPLY values for UDP, IP, link-layer
                   1315:    +-----------------------+-----------------------------------------+
                   1316:    | 'ciaddr'  'giaddr'  B | UDP dest     IP destination   link dest |
                   1317:    +-----------------------+-----------------------------------------+
                   1318:    | non-zero     X      X | BOOTPC (68)  'ciaddr'         normal    |
                   1319:    | 0.0.0.0   non-zero  X | BOOTPS (67)  'giaddr'         normal    |
                   1320:    | 0.0.0.0   0.0.0.0   0 | BOOTPC (68)  'yiaddr'         'chaddr'  |
                   1321:    | 0.0.0.0   0.0.0.0   1 | BOOTPC (68)  255.255.255.255  broadcast |
                   1322:    +-----------------------+-----------------------------------------+
                   1323: 
                   1324:         B = BROADCAST flag
                   1325: 
                   1326:         X = Don't care
                   1327: 
                   1328:    normal = determine from the given IP destination using normal
                   1329:             IP routing mechanisms and/or ARP as for any other
                   1330:             normal datagram
                   1331: 
                   1332:    If the 'giaddr' field in a DHCP message from a client is non-zero,
                   1333:    the server sends any return messages to the 'DHCP server' port on the
                   1334:    BOOTP relay agent whose address appears in 'giaddr'. 
                   1335: 
                   1336:    If the 'giaddr' field is zero and the 'ciaddr' field is nonzero, then the
                   1337:    server unicasts DHCPOFFER and DHCPACK messages to the address in
                   1338:    'ciaddr'.  
                   1339: 
                   1340:    If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set,
                   1341:    then the server broadcasts DHCPOFFER and DHCPACK messages to
                   1342:    0xffffffff. 
                   1343: 
                   1344:    If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is
                   1345:    zero, then the server unicasts DHCPOFFER and DHCPACK messages to the
                   1346:    client's hardware address and 'yiaddr' address.  
                   1347: 
                   1348:    In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
                   1349:    messages to 0xffffffff.
                   1350: 
                   1351:   **/
                   1352: 
                   1353:   if (req->dhcp.ciaddr) {
                   1354:     pack->iph.daddr = req->dhcp.ciaddr; 
                   1355:     pack->udph.dst = htons(DHCP_BOOTPC);
                   1356:   } else if (req->dhcp.giaddr) {
                   1357:     pack->iph.daddr = req->dhcp.giaddr; 
                   1358:     pack->udph.dst = htons(DHCP_BOOTPS);
                   1359:   } else if (type == DHCPNAK || req->dhcp.flags[0] & 0x80) {
                   1360:     pack->iph.daddr = ~0; 
                   1361:     pack->udph.dst = htons(DHCP_BOOTPC);
                   1362:     pack->dhcp.flags[0] = 0x80;
                   1363:   } else {
                   1364:     pack->iph.daddr = pack->dhcp.yiaddr; 
                   1365:     pack->udph.dst = htons(DHCP_BOOTPC);
                   1366:   }
                   1367: 
                   1368:   /* Magic cookie */
                   1369:   pack->dhcp.options[pos++] = 0x63;
                   1370:   pack->dhcp.options[pos++] = 0x82;
                   1371:   pack->dhcp.options[pos++] = 0x53;
                   1372:   pack->dhcp.options[pos++] = 0x63;
                   1373: 
                   1374:   pack->dhcp.options[pos++] = DHCP_OPTION_MESSAGE_TYPE;
                   1375:   pack->dhcp.options[pos++] = 1;
                   1376:   pack->dhcp.options[pos++] = type;
                   1377: 
                   1378:   memcpy(&pack->dhcp.options[pos], conn->dhcp_opts.options, DHCP_OPTIONS_LEN-pos);
                   1379:   pos += conn->dhcp_opts.option_length;
                   1380: 
                   1381:   return pos;
                   1382: }
                   1383: 
                   1384: 
                   1385: /**
                   1386:  * dhcp_gettag()
                   1387:  * Search a DHCP packet for a particular tag.
                   1388:  * Returns -1 if not found.
                   1389:  **/
                   1390: int dhcp_gettag(struct dhcp_packet_t *pack, size_t length,
                   1391:                struct dhcp_tag_t **tag, uint8_t tagtype) {
                   1392:   struct dhcp_tag_t *t;
                   1393:   size_t offset = DHCP_MIN_LEN + DHCP_OPTION_MAGIC_LEN;
                   1394: 
                   1395:   /* if (length > DHCP_LEN) {
                   1396:     log_warn(0,"Length of dhcp packet larger then %d: %d", DHCP_LEN, length);
                   1397:     length = DHCP_LEN;
                   1398:   } */
                   1399:   
                   1400:   while ((offset + 2) < length) {
                   1401:     t = (struct dhcp_tag_t *)(((void *)pack) + offset);
                   1402:     if (t->t == tagtype) {
                   1403:       if ((offset +  2 + (size_t)(t->l)) > length)
                   1404:        return -1; /* Tag length too long */
                   1405:       *tag = t;
                   1406:       return 0;
                   1407:     }
                   1408:     offset +=  2 + t->l;
                   1409:   }
                   1410:   
                   1411:   return -1; /* Not found  */
                   1412: }
                   1413: 
                   1414: 
                   1415: /**
                   1416:  * dhcp_sendOFFER()
                   1417:  * Send of a DHCP offer message to a peer.
                   1418:  **/
                   1419: int dhcp_sendOFFER(struct dhcp_conn_t *conn, 
                   1420:                   struct dhcp_fullpacket_t *pack, size_t len) {
                   1421: 
                   1422:   struct dhcp_t *this = conn->parent;
                   1423:   struct dhcp_fullpacket_t packet;
                   1424:   uint16_t length = 576 + 4; /* Maximum length */
                   1425:   uint16_t udp_len = 576 - 20; /* Maximum length */
                   1426:   size_t pos = 0;
                   1427: 
                   1428:   /* Get packet default values */
                   1429:   pos = dhcp_create_pkt(DHCPOFFER, &packet, pack, conn);
                   1430:   
                   1431:   /* DHCP Payload */
                   1432: 
                   1433:   packet.dhcp.options[pos++] = DHCP_OPTION_SUBNET_MASK;
                   1434:   packet.dhcp.options[pos++] = 4;
                   1435:   memcpy(&packet.dhcp.options[pos], &conn->hismask.s_addr, 4);
                   1436:   pos += 4;
                   1437: 
                   1438:   packet.dhcp.options[pos++] = DHCP_OPTION_ROUTER_OPTION;
                   1439:   packet.dhcp.options[pos++] = 4;
                   1440:   memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
                   1441:   pos += 4;
                   1442: 
                   1443:   /* Insert DNS Servers if given */
                   1444:   if (conn->dns1.s_addr && conn->dns2.s_addr) {
                   1445:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1446:     packet.dhcp.options[pos++] = 8;
                   1447:     memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
                   1448:     pos += 4;
                   1449:     memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
                   1450:     pos += 4;
                   1451:   }
                   1452:   else if (conn->dns1.s_addr) {
                   1453:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1454:     packet.dhcp.options[pos++] = 4;
                   1455:     memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
                   1456:     pos += 4;
                   1457:   }
                   1458:   else if (conn->dns2.s_addr) {
                   1459:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1460:     packet.dhcp.options[pos++] = 4;
                   1461:     memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
                   1462:     pos += 4;
                   1463:   }
                   1464: 
                   1465:   /* Insert Domain Name if present */
                   1466:   if (strlen(conn->domain)) {
                   1467:     packet.dhcp.options[pos++] = DHCP_OPTION_DOMAIN_NAME;
                   1468:     packet.dhcp.options[pos++] = strlen(conn->domain);
                   1469:     memcpy(&packet.dhcp.options[pos], &conn->domain, strlen(conn->domain));
                   1470:     pos += strlen(conn->domain);
                   1471:   }
                   1472: 
                   1473:   packet.dhcp.options[pos++] = DHCP_OPTION_LEASE_TIME;
                   1474:   packet.dhcp.options[pos++] = 4;
                   1475:   packet.dhcp.options[pos++] = (this->lease >> 24) & 0xFF;
                   1476:   packet.dhcp.options[pos++] = (this->lease >> 16) & 0xFF;
                   1477:   packet.dhcp.options[pos++] = (this->lease >>  8) & 0xFF;
                   1478:   packet.dhcp.options[pos++] = (this->lease >>  0) & 0xFF;
                   1479: 
                   1480:   /* Must be listening address */
                   1481:   packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
                   1482:   packet.dhcp.options[pos++] = 4;
                   1483:   memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
                   1484:   pos += 4;
                   1485: 
                   1486:   packet.dhcp.options[pos++] = DHCP_OPTION_END;
                   1487: 
                   1488:   /* UDP header */
                   1489:   udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
                   1490:   packet.udph.len = htons(udp_len);
                   1491: 
                   1492:   /* IP header */
                   1493:   packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
                   1494: 
                   1495:   /* Work out checksums */
                   1496:   chksum(&packet.iph);
                   1497: 
                   1498:   /* Calculate total length */
                   1499:   length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
                   1500: 
                   1501:   return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
                   1502: }
                   1503: 
                   1504: /**
                   1505:  * dhcp_sendACK()
                   1506:  * Send of a DHCP acknowledge message to a peer.
                   1507:  **/
                   1508: int dhcp_sendACK(struct dhcp_conn_t *conn, 
                   1509:                 struct dhcp_fullpacket_t *pack, size_t len) {
                   1510: 
                   1511:   struct dhcp_t *this = conn->parent;
                   1512:   struct dhcp_fullpacket_t packet;
                   1513:   uint16_t length = 576 + 4; /* Maximum length */
                   1514:   uint16_t udp_len = 576 - 20; /* Maximum length */
                   1515:   size_t pos = 0;
                   1516: 
                   1517:   /* Get packet default values */
                   1518:   pos = dhcp_create_pkt(DHCPACK, &packet, pack, conn);
                   1519:   
                   1520:   /* DHCP Payload */
                   1521:   packet.dhcp.options[pos++] = DHCP_OPTION_SUBNET_MASK;
                   1522:   packet.dhcp.options[pos++] = 4;
                   1523:   memcpy(&packet.dhcp.options[pos], &conn->hismask.s_addr, 4);
                   1524:   pos += 4;
                   1525: 
                   1526:   packet.dhcp.options[pos++] = DHCP_OPTION_ROUTER_OPTION;
                   1527:   packet.dhcp.options[pos++] = 4;
                   1528:   memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
                   1529:   pos += 4;
                   1530: 
                   1531:   /* Insert DNS Servers if given */
                   1532:   if (conn->dns1.s_addr && conn->dns2.s_addr) {
                   1533:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1534:     packet.dhcp.options[pos++] = 8;
                   1535:     memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
                   1536:     pos += 4;
                   1537:     memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
                   1538:     pos += 4;
                   1539:   }
                   1540:   else if (conn->dns1.s_addr) {
                   1541:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1542:     packet.dhcp.options[pos++] = 4;
                   1543:     memcpy(&packet.dhcp.options[pos], &conn->dns1.s_addr, 4);
                   1544:     pos += 4;
                   1545:   }
                   1546:   else if (conn->dns2.s_addr) {
                   1547:     packet.dhcp.options[pos++] = DHCP_OPTION_DNS;
                   1548:     packet.dhcp.options[pos++] = 4;
                   1549:     memcpy(&packet.dhcp.options[pos], &conn->dns2.s_addr, 4);
                   1550:     pos += 4;
                   1551:   }
                   1552: 
                   1553:   /* Insert Domain Name if present */
                   1554:   if (strlen(conn->domain)) {
                   1555:     packet.dhcp.options[pos++] = DHCP_OPTION_DOMAIN_NAME;
                   1556:     packet.dhcp.options[pos++] = strlen(conn->domain);
                   1557:     memcpy(&packet.dhcp.options[pos], &conn->domain, strlen(conn->domain));
                   1558:     pos += strlen(conn->domain);
                   1559:   }
                   1560: 
                   1561:   packet.dhcp.options[pos++] = DHCP_OPTION_LEASE_TIME;
                   1562:   packet.dhcp.options[pos++] = 4;
                   1563:   packet.dhcp.options[pos++] = (this->lease >> 24) & 0xFF;
                   1564:   packet.dhcp.options[pos++] = (this->lease >> 16) & 0xFF;
                   1565:   packet.dhcp.options[pos++] = (this->lease >>  8) & 0xFF;
                   1566:   packet.dhcp.options[pos++] = (this->lease >>  0) & 0xFF;
                   1567: 
                   1568:   /*
                   1569:   packet.dhcp.options[pos++] = DHCP_OPTION_INTERFACE_MTU;
                   1570:   packet.dhcp.options[pos++] = 2;
                   1571:   packet.dhcp.options[pos++] = (conn->mtu >> 8) & 0xFF;
                   1572:   packet.dhcp.options[pos++] = (conn->mtu >> 0) & 0xFF;
                   1573:   */
                   1574: 
                   1575:   /* Must be listening address */
                   1576:   packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
                   1577:   packet.dhcp.options[pos++] = 4;
                   1578:   memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
                   1579:   pos += 4;
                   1580: 
                   1581:   packet.dhcp.options[pos++] = DHCP_OPTION_END;
                   1582: 
                   1583:   /* UDP header */
                   1584:   udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
                   1585:   packet.udph.len = htons(udp_len);
                   1586: 
                   1587:   /* IP header */
                   1588:   packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
                   1589: 
                   1590:   /* Work out checksums */
                   1591:   chksum(&packet.iph);
                   1592: 
                   1593:   /* Calculate total length */
                   1594:   length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
                   1595: 
                   1596:   return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
                   1597: }
                   1598: 
                   1599: /**
                   1600:  * dhcp_sendNAK()
                   1601:  * Send of a DHCP negative acknowledge message to a peer.
                   1602:  * NAK messages are always sent to broadcast IP address (
                   1603:  * except when using a DHCP relay server)
                   1604:  **/
                   1605: int dhcp_sendNAK(struct dhcp_conn_t *conn, 
                   1606:                 struct dhcp_fullpacket_t *pack, size_t len) {
                   1607: 
                   1608:   struct dhcp_t *this = conn->parent;
                   1609:   struct dhcp_fullpacket_t packet;
                   1610:   uint16_t length = 576 + 4; /* Maximum length */
                   1611:   uint16_t udp_len = 576 - 20; /* Maximum length */
                   1612:   size_t pos = 0;
                   1613: 
                   1614:   /* Get packet default values */
                   1615:   pos = dhcp_create_pkt(DHCPNAK, &packet, pack, conn);
                   1616: 
                   1617:   /* DHCP Payload */
                   1618: 
                   1619:   /* Must be listening address */
                   1620:   packet.dhcp.options[pos++] = DHCP_OPTION_SERVER_ID;
                   1621:   packet.dhcp.options[pos++] = 4;
                   1622:   memcpy(&packet.dhcp.options[pos], &conn->ourip.s_addr, 4);
                   1623:   pos += 4;
                   1624: 
                   1625:   packet.dhcp.options[pos++] = DHCP_OPTION_END;
                   1626: 
                   1627:   /* UDP header */
                   1628:   udp_len = pos + DHCP_MIN_LEN + PKT_UDP_HLEN;
                   1629:   packet.udph.len = htons(udp_len);
                   1630: 
                   1631:   /* IP header */
                   1632:   packet.iph.tot_len = htons(udp_len + PKT_IP_HLEN);
                   1633: 
                   1634:   /* Work out checksums */
                   1635:   chksum(&packet.iph);
                   1636: 
                   1637:   /* Calculate total length */
                   1638:   length = udp_len + PKT_IP_HLEN + PKT_ETH_HLEN;
                   1639: 
                   1640:   return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
                   1641: }
                   1642: 
                   1643: 
                   1644: /**
                   1645:  *  dhcp_getreq()
                   1646:  *  Process a received DHCP request and sends a response.
                   1647:  **/
                   1648: int dhcp_getreq(struct dhcp_t *this, struct dhcp_fullpacket_t *pack, size_t len) {
                   1649:   uint8_t mac[PKT_ETH_ALEN];
                   1650:   struct dhcp_tag_t *message_type = 0;
                   1651:   struct dhcp_tag_t *requested_ip = 0;
                   1652:   struct dhcp_conn_t *conn;
                   1653:   struct in_addr addr;
                   1654: 
                   1655:   if (pack->udph.dst != htons(DHCP_BOOTPS)) 
                   1656:     return 0; /* Not a DHCP packet */
                   1657: 
                   1658:   if (dhcp_gettag(&pack->dhcp, ntohs(pack->udph.len)-PKT_UDP_HLEN, 
                   1659:                  &message_type, DHCP_OPTION_MESSAGE_TYPE)) {
                   1660:     return -1;
                   1661:   }
                   1662: 
                   1663:   if (message_type->l != 1)
                   1664:     return -1; /* Wrong length of message type */
                   1665: 
                   1666:   if (pack->dhcp.giaddr)
                   1667:     memcpy(mac, pack->dhcp.chaddr, PKT_ETH_ALEN);
                   1668:   else
                   1669:     memcpy(mac, pack->ethh.src, PKT_ETH_ALEN);
                   1670: 
                   1671:   switch(message_type->v[0]) {
                   1672: 
                   1673:   case DHCPRELEASE:
                   1674:     dhcp_release_mac(this, mac, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
                   1675: 
                   1676:   case DHCPDISCOVER:
                   1677:   case DHCPREQUEST:
                   1678:   case DHCPINFORM:
                   1679:     break;
                   1680: 
                   1681:   default:
                   1682:     return 0; /* Unsupported message type */
                   1683:   }
                   1684: 
                   1685:   if (this->relayfd > 0) {
                   1686:     /** Relay the DHCP request **/
                   1687:     struct sockaddr_in addr;
                   1688: 
                   1689:     memset(&addr, 0, sizeof(addr));
                   1690:     addr.sin_family = AF_INET;
                   1691:     addr.sin_addr.s_addr = options.dhcpgwip.s_addr;
                   1692:     addr.sin_port = htons(options.dhcpgwport);
                   1693: 
                   1694:     if (options.dhcprelayip.s_addr)
                   1695:       pack->dhcp.giaddr = options.dhcprelayip.s_addr;
                   1696:     else
                   1697:       pack->dhcp.giaddr = options.uamlisten.s_addr;
                   1698: 
                   1699:     /* if we can't send, lets do dhcp ourselves */
                   1700:     if (sendto(this->relayfd, &pack->dhcp, ntohs(pack->udph.len) - PKT_UDP_HLEN, 0, 
                   1701:               (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                   1702:       log_err(errno, "could not relay DHCP request!");
                   1703:     }
                   1704:     else {
                   1705:       return 0;
                   1706:     }
                   1707:   }
                   1708: 
                   1709:   if (message_type->v[0] == DHCPRELEASE) {
                   1710:     /* No Reply to client is sent */
                   1711:     return 0;
                   1712:   }
                   1713: 
                   1714:   /* Check to see if we know MAC address. If not allocate new conn */
                   1715:   if (dhcp_hashget(this, &conn, mac)) {
                   1716:     
                   1717:     /* Do we allow dynamic allocation of IP addresses? */
                   1718:     if (!this->allowdyn) /* TODO: Should be deleted! */
                   1719:       return 0; 
                   1720: 
                   1721:     /* Allocate new connection */
                   1722:     if (dhcp_newconn(this, &conn, mac)) /* TODO: Delete! */
                   1723:       return 0; /* Out of connections */
                   1724:   }
                   1725: 
                   1726:   /* Request an IP address */
                   1727:   if (conn->authstate == DHCP_AUTH_NONE) {
                   1728:     addr.s_addr = pack->dhcp.ciaddr;
                   1729:     if (this->cb_request)
                   1730:       if (this->cb_request(conn, &addr, pack, len)) {
                   1731:        return 0; /* Ignore request if IP address was not allocated */
                   1732:       }
                   1733:   }
                   1734:   
                   1735:   conn->lasttime = mainclock;
                   1736: 
                   1737:   /* Discover message */
                   1738:   /* If an IP address was assigned offer it to the client */
                   1739:   /* Otherwise ignore the request */
                   1740:   if (message_type->v[0] == DHCPDISCOVER) {
                   1741:     if (conn->hisip.s_addr) 
                   1742:       dhcp_sendOFFER(conn, pack, len);
                   1743:     return 0;
                   1744:   }
                   1745:   
                   1746:   /* Request message */
                   1747:   if (message_type->v[0] == DHCPREQUEST) {
                   1748:     
                   1749:     if (!conn->hisip.s_addr) {
                   1750:       if (this->debug) log_dbg("hisip not set");
                   1751:       return dhcp_sendNAK(conn, pack, len);
                   1752:     }
                   1753: 
                   1754:     if (!memcmp(&conn->hisip.s_addr, &pack->dhcp.ciaddr, 4)) {
                   1755:       if (this->debug) log_dbg("hisip match ciaddr");
                   1756:       return dhcp_sendACK(conn, pack, len);
                   1757:     }
                   1758: 
                   1759:     if (!dhcp_gettag(&pack->dhcp, ntohs(pack->udph.len)-PKT_UDP_HLEN, 
                   1760:                     &requested_ip, DHCP_OPTION_REQUESTED_IP)) {
                   1761:       if (!memcmp(&conn->hisip.s_addr, requested_ip->v, 4))
                   1762:        return dhcp_sendACK(conn, pack, len);
                   1763:     }
                   1764: 
                   1765:     if (this->debug) log_dbg("Sending NAK to client");
                   1766:     return dhcp_sendNAK(conn, pack, len);
                   1767:   }
                   1768:   
                   1769:   /* 
                   1770:    *  Unsupported DHCP message: Ignore 
                   1771:    */
                   1772:   if (this->debug) log_dbg("Unsupported DHCP message ignored");
                   1773:   return 0;
                   1774: }
                   1775: 
                   1776: 
                   1777: /**
                   1778:  * dhcp_set_addrs()
                   1779:  * Set various IP addresses of a connection.
                   1780:  **/
                   1781: int dhcp_set_addrs(struct dhcp_conn_t *conn, struct in_addr *hisip,
                   1782:                   struct in_addr *hismask, struct in_addr *ourip,
                   1783:                   struct in_addr *ourmask, struct in_addr *dns1,
                   1784:                   struct in_addr *dns2, char *domain) {
                   1785: 
                   1786:   conn->hisip.s_addr = hisip->s_addr;
                   1787:   conn->hismask.s_addr = hismask->s_addr;
                   1788:   conn->ourip.s_addr = ourip->s_addr;
                   1789:   conn->dns1.s_addr = dns1->s_addr;
                   1790:   conn->dns2.s_addr = dns2->s_addr;
                   1791: 
                   1792:   if (domain) {
                   1793:     strncpy(conn->domain, domain, DHCP_DOMAIN_LEN);
                   1794:     conn->domain[DHCP_DOMAIN_LEN-1] = 0;
                   1795:   }
                   1796:   else {
                   1797:     conn->domain[0] = 0;
                   1798:   }
                   1799: 
                   1800:   if (options.uamanyip && 
                   1801:       (hisip->s_addr & ourmask->s_addr) != (ourip->s_addr & ourmask->s_addr)) {
                   1802:     /**
                   1803:      *  We have enabled ''uamanyip'' and the address we are setting does
                   1804:      *  not fit in ourip's network. In this case, add a route entry. 
                   1805:      */
                   1806:     struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
                   1807:     if (appconn) {
                   1808:       struct ippoolm_t *ipm = (struct ippoolm_t*)appconn->uplink;
                   1809:       if (ipm && ipm->inuse == 2) {
                   1810:        struct in_addr mask;
                   1811:        mask.s_addr = 0xffffffff;
                   1812:        log_dbg("Adding route for %s %d", inet_ntoa(*hisip), 
                   1813:                net_add_route(hisip, ourip, &mask));
                   1814:       }
                   1815:     }
                   1816:   }
                   1817: 
                   1818:   return 0;
                   1819: }
                   1820: 
                   1821: static unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                   1822: 
                   1823: int dhcp_receive_ip(struct dhcp_t *this, struct pkt_ippacket_t *pack, size_t len) {
                   1824:   struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t*) pack->payload;
                   1825:   /*struct pkt_udphdr_t *udph = (struct pkt_udphdr_t*) pack->payload;*/
                   1826:   struct dhcp_conn_t *conn;
                   1827:   struct in_addr ourip;
                   1828:   struct in_addr addr;
                   1829: 
                   1830:   /*
                   1831:    *  Received a packet from the dhcpif
                   1832:    */
                   1833: 
                   1834:   if (this->debug)
                   1835:     log_dbg("DHCP packet received");
                   1836:   
                   1837:   /* 
                   1838:    *  Check that the destination MAC address is our MAC or Broadcast 
                   1839:    */
                   1840:   if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) && 
                   1841:       (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN))) {
                   1842:     log_dbg("dropping packet; not for our MAC or broadcast");
                   1843:     return 0;
                   1844:   }
                   1845: 
                   1846:   ourip.s_addr = this->ourip.s_addr;
                   1847: 
                   1848:   /* 
                   1849:    *  DHCP (BOOTPS) packets for broadcast or us specifically
                   1850:    */
                   1851:   if (((pack->iph.daddr == 0) ||
                   1852:        (pack->iph.daddr == 0xffffffff) ||
                   1853:        (pack->iph.daddr == ourip.s_addr)) &&
                   1854:       ((pack->iph.version_ihl == PKT_IP_VER_HLEN) && 
                   1855:        (pack->iph.protocol == PKT_IP_PROTO_UDP) &&
                   1856:        (((struct dhcp_fullpacket_t*)pack)->udph.dst == htons(DHCP_BOOTPS)))) {
                   1857:     log_dbg("dhcp/bootps request being processed");
                   1858:     return dhcp_getreq(this, (struct dhcp_fullpacket_t*) pack, len);
                   1859:   }
                   1860: 
                   1861:   /* 
                   1862:    *  Check to see if we know MAC address
                   1863:    */
                   1864:   if (!dhcp_hashget(this, &conn, pack->ethh.src)) {
                   1865:     if (this->debug) log_dbg("Address found");
                   1866:     ourip.s_addr = conn->ourip.s_addr;
                   1867:   }
                   1868:   else {
                   1869:     /* ALPAPAD */
                   1870:     struct in_addr reqaddr;
                   1871:     /* Get local copy */
                   1872:     memcpy(&reqaddr.s_addr, &pack->iph.saddr, PKT_IP_ALEN);
                   1873: 
                   1874:     if (options.debug) 
                   1875:       log_dbg("Address not found (%s)", inet_ntoa(reqaddr)); 
                   1876: 
                   1877:     /* Do we allow dynamic allocation of IP addresses? */
                   1878:     if (!this->allowdyn && !options.uamanyip)
                   1879:       return 0; 
                   1880: 
                   1881:     /* Allocate new connection */
                   1882:     if (dhcp_newconn(this, &conn, pack->ethh.src)) {
                   1883:       if (this->debug) 
                   1884:        log_dbg("dropping packet; out of connections");
                   1885:       return 0; /* Out of connections */
                   1886:     }
                   1887:   }
                   1888: 
                   1889:   /* Request an IP address 
                   1890:   if (options.uamanyip && 
                   1891:       conn->authstate == DHCP_AUTH_NONE) {
                   1892:     this->cb_request(conn, &pack->iph.saddr);
                   1893:   } */
                   1894:   
                   1895:   /* Return if we do not know peer */
                   1896:   if (!conn) {
                   1897:     if (this->debug) 
                   1898:       log_dbg("dropping packet; no peer");
                   1899:     return 0;
                   1900:   }
                   1901: 
                   1902:   /* 
                   1903:    *  Request an IP address 
                   1904:    */
                   1905:   if ((conn->authstate == DHCP_AUTH_NONE) && 
                   1906:       (options.uamanyip || 
                   1907:        ((pack->iph.daddr != 0) && 
                   1908:        (pack->iph.daddr != 0xffffffff)))) {
                   1909:     addr.s_addr = pack->iph.saddr;
                   1910:     if (this->cb_request)
                   1911:       if (this->cb_request(conn, &addr, 0, 0)) {
                   1912:        if (this->debug) 
                   1913:          log_dbg("dropping packet; ip not known");
                   1914:        return 0; /* Ignore request if IP address was not allocated */
                   1915:       }
                   1916:   }
                   1917: 
                   1918: 
                   1919:   conn->lasttime = mainclock;
                   1920: 
                   1921:   /*
                   1922:   if (((pack->iph.daddr == conn->dns1.s_addr) ||
                   1923:        (pack->iph.daddr == conn->dns2.s_addr)) &&
                   1924:       (pack->iph.protocol == PKT_IP_PROTO_UDP) &&
                   1925:       (udph->dst == htons(DHCP_DNS))) {
                   1926:     if (dhcp_checkDNS(conn, pack, len)) return 0;
                   1927:     }*/
                   1928: 
                   1929:   /* Was it a request for the auto-logout service? */
                   1930:   if ((pack->iph.daddr == options.uamlogout.s_addr) &&
                   1931:       (pack->iph.protocol == PKT_IP_PROTO_TCP) &&
                   1932:       (tcph->dst == htons(DHCP_HTTP))) {
                   1933:     if (conn->peer) {
                   1934:       struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
                   1935:       if (appconn->s_state.authenticated) {
                   1936:        terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
                   1937:        if (options.debug)
                   1938:          log_dbg("Dropping session due to request for auto-logout ip");
                   1939:        appconn->uamexit=1;
                   1940:       }
                   1941:     }
                   1942:   }
                   1943: 
                   1944:   switch (conn->authstate) {
                   1945:   case DHCP_AUTH_PASS:
                   1946:     /* Check for post-auth proxy, otherwise pass packets unmodified */
                   1947:     dhcp_postauthDNAT(conn, pack, len, 0);
                   1948:     break; 
                   1949: 
                   1950:   case DHCP_AUTH_UNAUTH_TOS:
                   1951:     /* Set TOS to specified value (unauthenticated) */
                   1952:     pack->iph.tos = conn->unauth_cp;
                   1953:     chksum(&pack->iph);
                   1954:     break;
                   1955: 
                   1956:   case DHCP_AUTH_AUTH_TOS:
                   1957:     /* Set TOS to specified value (authenticated) */
                   1958:     pack->iph.tos = conn->auth_cp;
                   1959:     chksum(&pack->iph);
                   1960:     break;
                   1961: 
                   1962:   case DHCP_AUTH_SPLASH:
                   1963:     dhcp_doDNAT(conn, pack, len);
                   1964:     break;
                   1965: 
                   1966:   case DHCP_AUTH_DNAT:
                   1967:     /* Destination NAT if request to unknown web server */
                   1968:     if (dhcp_doDNAT(conn, pack, len)) {
                   1969:       if (this->debug) log_dbg("dropping packet; not nat'ed");
                   1970:       return 0; /* Drop is not http or dns */
                   1971:     }
                   1972:     break;
                   1973: 
                   1974:   case DHCP_AUTH_DROP: 
                   1975:   default:
                   1976:     if (this->debug) 
                   1977:       log_dbg("dropping packet; auth-drop");
                   1978:     return 0;
                   1979:   }
                   1980: 
                   1981:   /*done:*/
                   1982: 
                   1983:   if (options.usetap) {
                   1984:     struct pkt_ethhdr_t *ethh = (struct pkt_ethhdr_t *)pack;
                   1985:     memcpy(ethh->dst,tuntap(tun).hwaddr,PKT_ETH_ALEN);
                   1986:   }
                   1987: 
                   1988:   if ((conn->hisip.s_addr) && (this->cb_data_ind)) {
                   1989:     this->cb_data_ind(conn, pack, len);
                   1990:   } else {
                   1991:     if (this->debug) 
                   1992:       log_dbg("no hisip; packet-drop");
                   1993:   }
                   1994:   
                   1995:   return 0;
                   1996: }
                   1997: 
                   1998: /**
                   1999:  * Call this function when a new IP packet has arrived. This function
                   2000:  * should be part of a select() loop in the application.
                   2001:  **/
                   2002: int dhcp_decaps(struct dhcp_t *this) {
                   2003:   struct pkt_ippacket_t packet;
                   2004:   ssize_t length;
                   2005:   
                   2006:   if ((length = net_read(&this->ipif, &packet, sizeof(packet))) < 0) 
                   2007:     return -1;
                   2008: 
                   2009:   if (this->debug) {
                   2010:     struct pkt_ethhdr_t *ethh = &packet.ethh;
                   2011:     log_dbg("dhcp_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
                   2012:            ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
                   2013:            ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
                   2014:            ntohs(ethh->prot));
                   2015:   }
                   2016: 
                   2017:   return dhcp_receive_ip(this, &packet, length);
                   2018: }
                   2019: 
                   2020: int dhcp_relay_decaps(struct dhcp_t *this) {
                   2021:   struct dhcp_tag_t *message_type = 0;
                   2022:   struct dhcp_fullpacket_t fullpack;
                   2023:   struct dhcp_conn_t *conn;
                   2024:   struct dhcp_packet_t packet;
                   2025:   struct sockaddr_in addr;
                   2026:   socklen_t fromlen = sizeof(addr);
                   2027:   ssize_t length;
                   2028: 
                   2029: 
                   2030:   if ((length = recvfrom(this->relayfd, &packet, sizeof(packet), 0,
                   2031:                          (struct sockaddr *) &addr, &fromlen)) <= 0) {
                   2032:     log_err(errno, "recvfrom() failed");
                   2033:     return -1;
                   2034:   }
                   2035: 
                   2036:   log_dbg("DHCP relay response of length %d received", length);
                   2037: 
                   2038:   if (addr.sin_addr.s_addr != options.dhcpgwip.s_addr) {
                   2039:     log_err(0, "received DHCP response from host other than our gateway");
                   2040:     return -1;
                   2041:   }
                   2042: 
                   2043:   if (addr.sin_port != htons(options.dhcpgwport)) {
                   2044:     log_err(0, "received DHCP response from port other than our gateway");
                   2045:     return -1;
                   2046:   }
                   2047: 
                   2048:   if (dhcp_gettag(&packet, length, &message_type, DHCP_OPTION_MESSAGE_TYPE)) {
                   2049:     log_err(0, "no message type");
                   2050:     return -1;
                   2051:   }
                   2052:   
                   2053:   if (message_type->l != 1) {
                   2054:     log_err(0, "wrong message type length");
                   2055:     return -1; /* Wrong length of message type */
                   2056:   }
                   2057:   
                   2058:   if (dhcp_hashget(this, &conn, packet.chaddr)) {
                   2059: 
                   2060:     /* Allocate new connection */
                   2061:     if (dhcp_newconn(this, &conn, packet.chaddr)) {
                   2062:       log_err(0, "out of connections");
                   2063:       return 0; /* Out of connections */
                   2064:     }
                   2065: 
                   2066:     this->cb_request(conn, (struct in_addr *)&packet.yiaddr, 0, 0);
                   2067:   }
                   2068: 
                   2069:   packet.giaddr = 0;
                   2070: 
                   2071:   memset(&fullpack, 0, sizeof(fullpack));
                   2072: 
                   2073:   memcpy(fullpack.ethh.dst, conn->hismac, PKT_ETH_ALEN);
                   2074:   memcpy(fullpack.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   2075:   fullpack.ethh.prot = htons(PKT_ETH_PROTO_IP);
                   2076: 
                   2077:   fullpack.iph.version_ihl = PKT_IP_VER_HLEN;
                   2078:   fullpack.iph.tot_len = htons(length + PKT_UDP_HLEN + PKT_IP_HLEN);
                   2079:   fullpack.iph.ttl = 0x10;
                   2080:   fullpack.iph.protocol = 0x11;
                   2081: 
                   2082:   fullpack.iph.saddr = conn->ourip.s_addr;
                   2083:   fullpack.udph.src = htons(DHCP_BOOTPS);
                   2084:   fullpack.udph.len = htons(length + PKT_UDP_HLEN);
                   2085: 
                   2086:   /*if (fullpack.dhcp.ciaddr) {
                   2087:     fullpack.udph.daddr = req->dhcp.ciaddr; 
                   2088:     fullpack.udph.dst = htons(DHCP_BOOTPC);
                   2089:   } else if (req->dhcp.giaddr) {
                   2090:     fullpack.iph.daddr = req->dhcp.giaddr; 
                   2091:     fullpack.udph.dst = htons(DHCP_BOOTPS);
                   2092:     } else */
                   2093: 
                   2094:   if (message_type->v[0] == DHCPNAK || packet.flags[0] & 0x80) {
                   2095:     fullpack.iph.daddr = ~0; 
                   2096:     fullpack.udph.dst = htons(DHCP_BOOTPC);
                   2097:     fullpack.dhcp.flags[0] = 0x80;
                   2098:   } if (packet.ciaddr) {
                   2099:     fullpack.iph.daddr = packet.ciaddr; 
                   2100:     fullpack.udph.dst = htons(DHCP_BOOTPC);
                   2101:   } else {
                   2102:     fullpack.iph.daddr = packet.yiaddr; 
                   2103:     fullpack.udph.dst = htons(DHCP_BOOTPC);
                   2104:   }
                   2105: 
                   2106:   memcpy(&fullpack.dhcp, &packet, sizeof(packet));
                   2107: 
                   2108:   { /* rewrite the server-id, otherwise will not get subsequent requests */
                   2109:     struct dhcp_tag_t *tag = 0;
                   2110:     if (!dhcp_gettag(&fullpack.dhcp, length, &tag, DHCP_OPTION_SERVER_ID)) {
                   2111:       memcpy(tag->v, &conn->ourip.s_addr, 4);
                   2112:     }
                   2113:   }
                   2114: 
                   2115:   chksum(&fullpack.iph);
                   2116: 
                   2117:   return dhcp_send(this, &this->ipif, conn->hismac, &fullpack, 
                   2118:                   length + PKT_UDP_HLEN + PKT_IP_HLEN + PKT_ETH_HLEN);
                   2119: }
                   2120: 
                   2121: /**
                   2122:  * dhcp_data_req()
                   2123:  * Call this function to send an IP packet to the peer.
                   2124:  * Called from the tun_ind function. This method is passed either
                   2125:  * an Ethernet frame or an IP packet. 
                   2126:  **/
                   2127: int dhcp_data_req(struct dhcp_conn_t *conn, void *pack, size_t len, int ethhdr) {
                   2128:   struct dhcp_t *this = conn->parent;
                   2129:   struct pkt_ippacket_t packet;
                   2130:   size_t length = len;
                   2131: 
                   2132:   if (ethhdr) { /* Ethernet frame */
                   2133:     memcpy(&packet, pack, len);
                   2134:   } else {      /* IP packet */
                   2135:     memcpy(&packet.iph, pack, len);
                   2136:     length += PKT_ETH_HLEN;
                   2137:   }
                   2138: 
                   2139:   /* Ethernet header */
                   2140:   memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
                   2141:   memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   2142:   packet.ethh.prot = htons(PKT_ETH_PROTO_IP);
                   2143:   
                   2144:   switch (conn->authstate) {
                   2145: 
                   2146:   case DHCP_AUTH_PASS:
                   2147:   case DHCP_AUTH_AUTH_TOS:
                   2148:     dhcp_postauthDNAT(conn, &packet, length, 1);
                   2149:     break;
                   2150: 
                   2151:   case DHCP_AUTH_SPLASH:
                   2152:   case DHCP_AUTH_UNAUTH_TOS:
                   2153:     dhcp_undoDNAT(conn, &packet, &length);
                   2154:     break;
                   2155: 
                   2156:   case DHCP_AUTH_DNAT:
                   2157:     /* undo destination NAT */
                   2158:     if (dhcp_undoDNAT(conn, &packet, &length)) {
                   2159:       if (this->debug) log_dbg("dhcp_undoDNAT() returns true");
                   2160:       return 0;
                   2161:     }
                   2162:     break;
                   2163: 
                   2164:   case DHCP_AUTH_DROP: 
                   2165:   default: return 0;
                   2166:   }
                   2167: 
                   2168:   return dhcp_send(this, &this->ipif, conn->hismac, &packet, length);
                   2169: }
                   2170: 
                   2171: 
                   2172: /**
                   2173:  * dhcp_sendARP()
                   2174:  * Send ARP message to peer
                   2175:  **/
                   2176: static int
                   2177: dhcp_sendARP(struct dhcp_conn_t *conn, struct arp_fullpacket_t *pack, size_t len) {
                   2178: 
                   2179:   struct dhcp_t *this = conn->parent;
                   2180:   struct arp_fullpacket_t packet;
                   2181:   struct in_addr reqaddr;
                   2182:   size_t length = sizeof(packet);
                   2183: 
                   2184:   /* Get local copy */
                   2185:   memcpy(&reqaddr.s_addr, pack->arp.tpa, PKT_IP_ALEN);
                   2186: 
                   2187:   /* Check that request is within limits */
                   2188: 
                   2189:   /* Get packet default values */
                   2190:   memset(&packet, 0, sizeof(packet));
                   2191:         
                   2192:   /* ARP Payload */
                   2193:   packet.arp.hrd = htons(DHCP_HTYPE_ETH);
                   2194:   packet.arp.pro = htons(PKT_ETH_PROTO_IP);
                   2195:   packet.arp.hln = PKT_ETH_ALEN;
                   2196:   packet.arp.pln = PKT_IP_ALEN;
                   2197:   packet.arp.op  = htons(DHCP_ARP_REPLY);
                   2198: 
                   2199:   /* Source address */
                   2200:   memcpy(packet.arp.sha, this->arpif.hwaddr, PKT_ETH_ALEN);
                   2201:   memcpy(packet.arp.spa, &reqaddr.s_addr, PKT_IP_ALEN);
                   2202: 
                   2203:   /* Target address */
                   2204:   memcpy(packet.arp.tha, &conn->hismac, PKT_ETH_ALEN);
                   2205:   memcpy(packet.arp.tpa, &conn->hisip.s_addr, PKT_IP_ALEN);
                   2206: 
                   2207:   /* Ethernet header */
                   2208:   memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
                   2209:   memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   2210:   packet.ethh.prot = htons(PKT_ETH_PROTO_ARP);
                   2211: 
                   2212:   return dhcp_send(this, &this->arpif, conn->hismac, &packet, length);
                   2213: }
                   2214: 
                   2215: 
                   2216: int dhcp_receive_arp(struct dhcp_t *this, 
                   2217:                     struct arp_fullpacket_t *pack, size_t len) {
                   2218:   
                   2219:   unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                   2220:   struct dhcp_conn_t *conn;
                   2221:   struct in_addr reqaddr;
                   2222:   struct in_addr taraddr;
                   2223: 
                   2224:   /* Check that this is ARP request */
                   2225:   if (pack->arp.op != htons(DHCP_ARP_REQUEST)) {
                   2226:     if (this->debug)
                   2227:       log_dbg("Received other ARP than request!");
                   2228:     return 0;
                   2229:   }
                   2230: 
                   2231:   /* Check that MAC address is our MAC or Broadcast */
                   2232:   if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) && 
                   2233:       (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN))) {
                   2234:     if (this->debug) 
                   2235:       log_dbg("Received ARP request for other destination!");
                   2236:     return 0;
                   2237:   }
                   2238: 
                   2239:   /* get sender IP address */
                   2240:   memcpy(&reqaddr.s_addr, &pack->arp.spa, PKT_IP_ALEN);
                   2241: 
                   2242:   /* get target IP address */
                   2243:   memcpy(&taraddr.s_addr, &pack->arp.tpa, PKT_IP_ALEN);
                   2244: 
                   2245: 
                   2246:   /* Check to see if we know MAC address. */
                   2247:   if (dhcp_hashget(this, &conn, pack->ethh.src)) {
                   2248: 
                   2249:     if (options.debug) 
                   2250:       log_dbg("Address not found: %s", inet_ntoa(reqaddr));
                   2251: 
                   2252:     /* Do we allow dynamic allocation of IP addresses? */
                   2253:     if (!this->allowdyn && !options.uamanyip) {
                   2254:       if (this->debug) 
                   2255:        log_dbg("ARP: Unknown client and no dynip: %s", inet_ntoa(taraddr));
                   2256:       return 0; 
                   2257:     }
                   2258:     
                   2259:     /* Allocate new connection */
                   2260:     if (dhcp_newconn(this, &conn, pack->ethh.src)) {
                   2261:       log_warn(0, "ARP: out of connections");
                   2262:       return 0; /* Out of connections */
                   2263:     }
                   2264:   }
                   2265:   
                   2266:   /* if no sender ip, then client is checking their own ip */
                   2267:   if (!reqaddr.s_addr) {
                   2268:     /* XXX: lookup in ippool to see if we really do know who has this */
                   2269:     /* XXX: it should also ack if *we* are that ip */
                   2270:     if (this->debug) 
                   2271:       log_dbg("ARP: Ignoring self-discovery: %s", inet_ntoa(taraddr));
                   2272: 
                   2273:     /* If a static ip address... */
                   2274:     this->cb_request(conn, &taraddr, 0, 0);
                   2275: 
                   2276:     return 0;
                   2277:   }
                   2278: 
                   2279:   if (!memcmp(&reqaddr.s_addr, &taraddr.s_addr, 4)) { 
                   2280: 
                   2281:     /* Request an IP address */
                   2282:     if (options.uamanyip /*or static ip*/ &&
                   2283:        conn->authstate == DHCP_AUTH_NONE) {
                   2284:       this->cb_request(conn, &reqaddr, 0, 0);
                   2285:     } 
                   2286: 
                   2287:     if (this->debug)
                   2288:       log_dbg("ARP: gratuitous arp %s!", inet_ntoa(taraddr));
                   2289: 
                   2290:     return 0;
                   2291:   }
                   2292: 
                   2293:   if (!conn->hisip.s_addr && !options.uamanyip) {
                   2294:     if (this->debug)
                   2295:       log_dbg("ARP: request did not come from known client!");
                   2296:     return 0; /* Only reply if he was allocated an address */
                   2297:   }
                   2298: 
                   2299:   /* Is ARP request for clients own address: Ignore */
                   2300:   if (conn->hisip.s_addr == taraddr.s_addr) {
                   2301:     if (this->debug)
                   2302:       log_dbg("ARP: hisip equals target ip: %s!",
                   2303:              inet_ntoa(conn->hisip));
                   2304:     return 0;
                   2305:   }
                   2306:   
                   2307:   if (!options.uamanyip) {
                   2308:     /* If ARP request outside of mask: Ignore */
                   2309:     if (reqaddr.s_addr &&
                   2310:        (conn->hisip.s_addr & conn->hismask.s_addr) !=
                   2311:        (reqaddr.s_addr & conn->hismask.s_addr)) {
                   2312:       if (this->debug) 
                   2313:        log_dbg("ARP: request not in our subnet");
                   2314:       return 0;
                   2315:     }
                   2316:     
                   2317:     if (memcmp(&conn->ourip.s_addr, &taraddr.s_addr, 4)) { /* if ourip differs from target ip */
                   2318:       if (options.debug) {
                   2319:        log_dbg("ARP: Did not ask for router address: %s", inet_ntoa(conn->ourip));
                   2320:        log_dbg("ARP: Asked for target: %s", inet_ntoa(taraddr));
                   2321:       }
                   2322:       return 0; /* Only reply if he asked for his router address */
                   2323:     }
                   2324:   }
                   2325:   else if ((taraddr.s_addr != options.dhcplisten.s_addr) &&
                   2326:           ((taraddr.s_addr & options.mask.s_addr) == options.net.s_addr)) {
                   2327:     /* when uamanyip is on we should ignore arp requests that ARE within our subnet except of course the ones for ourselves */
                   2328:     if (options.debug)
                   2329:       log_dbg("ARP: request for IP=%s other than us within our subnet(uamanyip on), ignoring", inet_ntoa(taraddr));
                   2330:     return 0;
                   2331:   }
                   2332: 
                   2333:   conn->lasttime = mainclock;
                   2334: 
                   2335:   dhcp_sendARP(conn, pack, len);
                   2336: 
                   2337:   return 0;
                   2338: }
                   2339: 
                   2340: 
                   2341: /**
                   2342:  * dhcp_arp_ind()
                   2343:  * Call this function when a new ARP packet has arrived. This function
                   2344:  * should be part of a select() loop in the application.
                   2345:  **/
                   2346: int dhcp_arp_ind(struct dhcp_t *this)  /* ARP Indication */
                   2347: {
                   2348:   struct arp_fullpacket_t packet;
                   2349:   ssize_t length;
                   2350:   
                   2351:   if ((length = net_read(&this->arpif, &packet, sizeof(packet))) < 0) 
                   2352:     return -1;
                   2353: 
                   2354:   if (options.debug) {
                   2355:     struct pkt_ethhdr_t *ethh = &packet.ethh;
                   2356:     log_dbg("arp_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
                   2357:            ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
                   2358:            ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
                   2359:            ntohs(ethh->prot));
                   2360:   }
                   2361: 
                   2362:   dhcp_receive_arp(this, &packet, length);
                   2363: 
                   2364:   return 0;
                   2365: }
                   2366: 
                   2367: 
                   2368: /**
                   2369:  * eapol_sendNAK()
                   2370:  * Send of a EAPOL negative acknowledge message to a peer.
                   2371:  * NAK messages are always sent to broadcast IP address (
                   2372:  * except when using a EAPOL relay server)
                   2373:  **/
                   2374: int dhcp_senddot1x(struct dhcp_conn_t *conn,  
                   2375:                   struct dot1xpacket_t *pack, size_t len) {
                   2376:   struct dhcp_t *this = conn->parent;
                   2377:   return dhcp_send(this, &this->eapif, conn->hismac, pack, len);
                   2378: }
                   2379: 
                   2380: /**
                   2381:  * eapol_sendNAK()
                   2382:  * Send of a EAPOL negative acknowledge message to a peer.
                   2383:  * NAK messages are always sent to broadcast IP address (
                   2384:  * except when using a EAPOL relay server)
                   2385:  **/
                   2386: int dhcp_sendEAP(struct dhcp_conn_t *conn, void *pack, size_t len) {
                   2387: 
                   2388:   struct dhcp_t *this = conn->parent;
                   2389:   struct dot1xpacket_t packet;
                   2390: 
                   2391:   /* Ethernet header */
                   2392:   memcpy(packet.ethh.dst, conn->hismac, PKT_ETH_ALEN);
                   2393:   memcpy(packet.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   2394:   packet.ethh.prot = htons(PKT_ETH_PROTO_EAPOL);
                   2395:   
                   2396:   /* 802.1x header */
                   2397:   packet.dot1x.ver  = 1;
                   2398:   packet.dot1x.type = 0; /* EAP */
                   2399:   packet.dot1x.len =  htons((uint16_t)len);
                   2400: 
                   2401:   memcpy(&packet.eap, pack, len);
                   2402:   
                   2403:   return dhcp_send(this, &this->eapif, conn->hismac, &packet, (PKT_ETH_HLEN + 4 + len));
                   2404: }
                   2405: 
                   2406: int dhcp_sendEAPreject(struct dhcp_conn_t *conn, void *pack, size_t len) {
                   2407: 
                   2408:   /*struct dhcp_t *this = conn->parent;*/
                   2409: 
                   2410:   struct eap_packet_t packet;
                   2411: 
                   2412:   if (pack) {
                   2413:     dhcp_sendEAP(conn, pack, len);
                   2414:   }
                   2415:   else {
                   2416:     memset(&packet, 0, sizeof(packet));
                   2417:     packet.code      =  4;
                   2418:     packet.id        =  1; /* TODO ??? */
                   2419:     packet.length    =  htons(4);
                   2420:   
                   2421:     dhcp_sendEAP(conn, &packet, 4);
                   2422:   }
                   2423: 
                   2424:   return 0;
                   2425: 
                   2426: }
                   2427: 
                   2428: int dhcp_receive_eapol(struct dhcp_t *this, struct dot1xpacket_t *pack) {
                   2429:   struct dhcp_conn_t *conn = NULL;
                   2430:   unsigned char const bmac[PKT_ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                   2431:   unsigned char const amac[PKT_ETH_ALEN] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03};
                   2432: 
                   2433:   /* Check to see if we know MAC address. */
                   2434:   if (!dhcp_hashget(this, &conn, pack->ethh.src)) {
                   2435:     if (this->debug) log_dbg("Address found");
                   2436:   }
                   2437:   else {
                   2438:     if (this->debug) log_dbg("Address not found");
                   2439:   }
                   2440:   
                   2441:   if (this->debug) 
                   2442:     log_dbg("IEEE 802.1x Packet: %.2x, %.2x %d",
                   2443:            pack->dot1x.ver, pack->dot1x.type,
                   2444:            ntohs(pack->dot1x.len));
                   2445:   
                   2446:   /* Check that MAC address is our MAC, Broadcast or authentication MAC */
                   2447:   if ((memcmp(pack->ethh.dst, this->ipif.hwaddr, PKT_ETH_ALEN)) && 
                   2448:       (memcmp(pack->ethh.dst, bmac, PKT_ETH_ALEN)) && 
                   2449:       (memcmp(pack->ethh.dst, amac, PKT_ETH_ALEN)))
                   2450:     return 0;
                   2451:   
                   2452:   if (pack->dot1x.type == 1) { /* Start */
                   2453:     struct dot1xpacket_t p;
                   2454:     memset(&p, 0, sizeof(p));
                   2455:     
                   2456:     /* Allocate new connection */
                   2457:     if (conn == NULL) {
                   2458:       if (dhcp_newconn(this, &conn, pack->ethh.src))
                   2459:        return 0; /* Out of connections */
                   2460:     }
                   2461: 
                   2462:     /* Ethernet header */
                   2463:     memcpy(p.ethh.dst, pack->ethh.src, PKT_ETH_ALEN);
                   2464:     memcpy(p.ethh.src, this->ipif.hwaddr, PKT_ETH_ALEN);
                   2465:     p.ethh.prot = htons(PKT_ETH_PROTO_EAPOL);
                   2466: 
                   2467:     /* 802.1x header */
                   2468:     p.dot1x.ver  = 1;
                   2469:     p.dot1x.type = 0; /* EAP */
                   2470:     p.dot1x.len =  htons(5);
                   2471:     
                   2472:     /* EAP Packet */
                   2473:     p.eap.code      =  1;
                   2474:     p.eap.id        =  1;
                   2475:     p.eap.length    =  htons(5);
                   2476:     p.eap.type      =  1; /* Identity */
                   2477: 
                   2478:     dhcp_senddot1x(conn, &p, PKT_ETH_HLEN + 4 + 5);
                   2479:     return 0;
                   2480:   }
                   2481:   else if (pack->dot1x.type == 0) { /* EAP */
                   2482: 
                   2483:     /* TODO: Currently we only support authentications starting with a
                   2484:        client sending a EAPOL start message. Need to also support
                   2485:        authenticator initiated communications. */
                   2486:     if (!conn)
                   2487:       return 0;
                   2488: 
                   2489:     conn->lasttime = mainclock;
                   2490:     
                   2491:     if (this->cb_eap_ind)
                   2492:       this->cb_eap_ind(conn, &pack->eap, ntohs(pack->eap.length));
                   2493: 
                   2494:     return 0;
                   2495:   }
                   2496:   else { /* Check for logoff */
                   2497:     return 0;
                   2498:   }
                   2499: }
                   2500: 
                   2501: /**
                   2502:  * dhcp_eapol_ind()
                   2503:  * Call this function when a new EAPOL packet has arrived. This function
                   2504:  * should be part of a select() loop in the application.
                   2505:  **/
                   2506: int dhcp_eapol_ind(struct dhcp_t *this) {
                   2507:   struct dot1xpacket_t packet;
                   2508:   ssize_t length;
                   2509:   
                   2510:   if ((length = net_read(&this->eapif, &packet, sizeof(packet))) < 0) 
                   2511:     return -1;
                   2512: 
                   2513:   if (options.debug) {
                   2514:     struct pkt_ethhdr_t *ethh = &packet.ethh;
                   2515:     log_dbg("eapol_decaps: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x",
                   2516:            ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
                   2517:            ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
                   2518:            ntohs(ethh->prot));
                   2519:   }
                   2520: 
                   2521:   return dhcp_receive_eapol(this, &packet);
                   2522: }
                   2523: 
                   2524: 
                   2525: /**
                   2526:  * dhcp_set_cb_eap_ind()
                   2527:  * Set callback function which is called when packet has arrived
                   2528:  * Used for eap packets
                   2529:  **/
                   2530: int dhcp_set_cb_eap_ind(struct dhcp_t *this, 
                   2531:   int (*cb_eap_ind) (struct dhcp_conn_t *conn, void *pack, size_t len)) {
                   2532:   this->cb_eap_ind = cb_eap_ind;
                   2533:   return 0;
                   2534: }
                   2535: 
                   2536: 
                   2537: /**
                   2538:  * dhcp_set_cb_data_ind()
                   2539:  * Set callback function which is called when packet has arrived
                   2540:  **/
                   2541: int dhcp_set_cb_data_ind(struct dhcp_t *this, 
                   2542:   int (*cb_data_ind) (struct dhcp_conn_t *conn, void *pack, size_t len)) {
                   2543:   this->cb_data_ind = cb_data_ind;
                   2544:   return 0;
                   2545: }
                   2546: 
                   2547: 
                   2548: /**
                   2549:  * dhcp_set_cb_data_ind()
                   2550:  * Set callback function which is called when a dhcp request is received
                   2551:  **/
                   2552: int dhcp_set_cb_request(struct dhcp_t *this, 
                   2553:   int (*cb_request) (struct dhcp_conn_t *conn, struct in_addr *addr, struct dhcp_fullpacket_t *pack, size_t len)) {
                   2554:   this->cb_request = cb_request;
                   2555:   return 0;
                   2556: }
                   2557: 
                   2558: 
                   2559: /**
                   2560:  * dhcp_set_cb_connect()
                   2561:  * Set callback function which is called when a connection is created
                   2562:  **/
                   2563: int dhcp_set_cb_connect(struct dhcp_t *this, 
                   2564:              int (*cb_connect) (struct dhcp_conn_t *conn)) {
                   2565:   this->cb_connect = cb_connect;
                   2566:   return 0;
                   2567: }
                   2568: 
                   2569: /**
                   2570:  * dhcp_set_cb_disconnect()
                   2571:  * Set callback function which is called when a connection is deleted
                   2572:  **/
                   2573: int dhcp_set_cb_disconnect(struct dhcp_t *this, 
                   2574:   int (*cb_disconnect) (struct dhcp_conn_t *conn, int term_cause)) {
                   2575:   this->cb_disconnect = cb_disconnect;
                   2576:   return 0;
                   2577: }
                   2578: 
                   2579: int dhcp_set_cb_getinfo(struct dhcp_t *this, 
                   2580:   int (*cb_getinfo) (struct dhcp_conn_t *conn, bstring b, int fmt)) {
                   2581:   this->cb_getinfo = cb_getinfo;
                   2582:   return 0;
                   2583: }
                   2584: 
                   2585: 
                   2586: #if defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__)
                   2587: 
                   2588: int dhcp_receive(struct dhcp_t *this) {
                   2589:   ssize_t length = 0;
                   2590:   size_t offset = 0;
                   2591:   struct bpf_hdr *hdrp;
                   2592:   struct pkt_ethhdr_t *ethhdr;
                   2593:   
                   2594:   if (this->rbuf_offset == this->rbuf_len) {
                   2595:     length = read(this->ipif.fd, this->rbuf, this->rbuf_max);
                   2596: 
                   2597:     if (length <= 0)
                   2598:       return length;
                   2599: 
                   2600:     this->rbuf_offset = 0;
                   2601:     this->rbuf_len = length;
                   2602:   }
                   2603:   
                   2604:   while (this->rbuf_offset != this->rbuf_len) {
                   2605:     
                   2606:     if (this->rbuf_len - this->rbuf_offset < sizeof(struct bpf_hdr)) {
                   2607:       this->rbuf_offset = this->rbuf_len;
                   2608:       continue;
                   2609:     }
                   2610:     
                   2611:     hdrp = (struct bpf_hdr *) &this->rbuf[this->rbuf_offset];
                   2612:     
                   2613:     if (this->rbuf_offset + hdrp->bh_hdrlen + hdrp->bh_caplen > 
                   2614:        this->rbuf_len) {
                   2615:       this->rbuf_offset = this->rbuf_len;
                   2616:       continue;
                   2617:     }
                   2618: 
                   2619:     if (hdrp->bh_caplen != hdrp->bh_datalen) {
                   2620:       this->rbuf_offset += hdrp->bh_hdrlen + hdrp->bh_caplen;
                   2621:       continue;
                   2622:     }
                   2623: 
                   2624:     ethhdr = (struct pkt_ethhdr_t *) 
                   2625:       (this->rbuf + this->rbuf_offset + hdrp->bh_hdrlen);
                   2626: 
                   2627:     switch (ntohs(ethhdr->prot)) {
                   2628:     case PKT_ETH_PROTO_IP:
                   2629:       dhcp_receive_ip(this, (struct pkt_ippacket_t*) ethhdr, hdrp->bh_caplen);
                   2630:       break;
                   2631:     case PKT_ETH_PROTO_ARP:
                   2632:       dhcp_receive_arp(this, (struct arp_fullpacket_t*) ethhdr, hdrp->bh_caplen);
                   2633:       break;
                   2634:     case PKT_ETH_PROTO_EAPOL:
                   2635:       dhcp_receive_eapol(this, (struct dot1xpacket_t*) ethhdr);
                   2636:       break;
                   2637: 
                   2638:     default:
                   2639:       break;
                   2640:     }
                   2641:     this->rbuf_offset += hdrp->bh_hdrlen + hdrp->bh_caplen;
                   2642:   };
                   2643:   return (0);
                   2644: }
                   2645: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>