Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2004, 2008 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: 
                     14: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                     15: 
                     16: /** \file dhcp.c <pre>
                     17:  * **************** State-transition diagram for DHCP client  *************
                     18:  *
                     19:  *   +---------+                  Note: DHCP-server msg / DHCP-client msg
                     20:  *   |  INIT   |
                     21:  *   +---------+
                     22:  *        |
                     23:  *        |  - / Discover
                     24:  *        V
                     25:  *   +---------+
                     26:  *   | SELECT  |                     Timeout
                     27:  *   +---------+                        |
                     28:  *        |                             |
                     29:  *        |  Offer / Request            |
                     30:  *        |                             |
                     31:  *        V                             V
                     32:  *   +---------+     NACK / -      ***********
                     33:  *   | REQUEST | ----------------> *  FAULT  *
                     34:  *   +---------+                   ***********
                     35:  *        |
                     36:  *        |          ACK / -       ***********
                     37:  *        +----------------------> * SUCCESS *
                     38:  *                                 ***********
                     39:  *
                     40:  * ************************************************************************
                     41:  * </pre> */
                     42: 
                     43: 
                     44: /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
                     45: 
                     46: #include <dhcp.h>
                     47: #include <ethernet.h>
                     48: #include <ipv4.h>
                     49: #include <udp.h>
                     50: #include <dns.h>
                     51: 
                     52: #include <stdio.h>
                     53: #include <string.h>
                     54: #include <time.h>
                     55: #include <sys/socket.h>
                     56: #include <ctype.h>
                     57: #include <stdlib.h>
                     58: 
                     59: /* DHCP Message Types */
                     60: #define DHCPDISCOVER    1
                     61: #define DHCPOFFER       2
                     62: #define DHCPREQUEST     3
                     63: #define DHCPDECLINE     4
                     64: #define DHCPACK                5
                     65: #define DHCPNACK        6
                     66: #define DHCPRELEASE     7
                     67: #define DHCPINFORM      8
                     68: 
                     69: /* DHCP Option Codes */
                     70: #define DHCP_MASK              1
                     71: #define DHCP_ROUTER            3
                     72: #define DHCP_DNS               6
                     73: #define DHCP_REQUESTED_IP     50
                     74: #define DHCP_OVERLOAD         52
                     75: #define DHCP_MSG_TYPE         53
                     76: #define DHCP_SERVER_ID        54
                     77: #define DHCP_REQUEST_LIST     55
                     78: #define DHCP_TFTP_SERVER      66
                     79: #define DHCP_BOOTFILE         67
                     80: #define DHCP_ENDOPT         0xFF
                     81: #define DHCP_PADOPT         0x00
                     82: 
                     83: /* "file/sname" overload option values */
                     84: #define DHCP_OVERLOAD_FILE     1
                     85: #define DHCP_OVERLOAD_SNAME    2
                     86: #define DHCP_OVERLOAD_BOTH     3
                     87: 
                     88: /* DHCP states codes */
                     89: #define DHCP_STATE_SELECT      1
                     90: #define DHCP_STATE_REQUEST     2
                     91: #define DHCP_STATE_SUCCESS     3
                     92: #define DHCP_STATE_FAULT       4
                     93: 
                     94: static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
                     95: /**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
                     96: 
                     97: /** \struct dhcp_options_t
                     98:  *  This structure is used to fill options in DHCP-msg during transmitting
                     99:  *  or to retrieve options from DHCP-msg during receiving.
                    100:  *  <p>
                    101:  *  If flag[i] == TRUE then field for i-th option retains valid value and
                    102:  *  information from this field may retrived (in case of receiving) or will
                    103:  *  be transmitted (in case of transmitting).
                    104:  *  
                    105:  */
                    106: typedef struct {
                    107:        uint8_t    flag[256];         /**< Show if corresponding opt. is valid */
                    108:        uint8_t    request_list[256]; /**< o.55 If i-th member is TRUE, then i-th  
                    109:                                          option will be requested from server */
                    110:        uint32_t   server_ID;         /**< o.54 Identifies DHCP-server         */
                    111:        uint32_t   requested_IP;      /**< o.50 Must be filled in DHCP-Request */
                    112:        uint32_t   dns_IP;            /**< o. 6 DNS IP                         */
                    113:        uint32_t   router_IP;         /**< o. 3 Router IP                      */
                    114:        uint32_t   subnet_mask;       /**< o. 1 Subnet mask                    */
                    115:        uint8_t    msg_type;          /**< o.53 DHCP-message type              */
                    116:        uint8_t    overload;          /**< o.52 Overload sname/file fields     */
                    117:        int8_t     tftp_server[256];  /**< o.66 TFTP server name               */
                    118:        int8_t     bootfile[256];     /**< o.67 Boot file name                 */
                    119: } dhcp_options_t;
                    120: 
                    121: /** Stores state of DHCP-client (refer to State-transition diagram) */
                    122: static uint8_t dhcp_state;
                    123: 
                    124: 
                    125: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                    126: 
                    127: static int32_t
                    128: dhcp_attempt(void);
                    129: 
                    130: static int32_t
                    131: dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
                    132: 
                    133: static int32_t
                    134: dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
                    135:                     dhcp_options_t * opt_struct);
                    136: 
                    137: static int8_t
                    138: dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
                    139:                    uint8_t src_options[], uint32_t src_len);
                    140: 
                    141: static int8_t
                    142: dhcp_find_option(uint8_t options[], uint32_t len,
                    143:                  uint8_t op_code, uint32_t * op_offset);
                    144: 
                    145: static void
                    146: dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
                    147:                    uint8_t * new_option);
                    148: 
                    149: static void
                    150: dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
                    151:                     uint32_t dst_offset, uint8_t * new_option);
                    152: 
                    153: static void
                    154: dhcp_send_discover(void);
                    155: 
                    156: static void
                    157: dhcp_send_request(void);
                    158: 
                    159: static uint8_t
                    160: strtoip(int8_t * str, uint32_t * ip);
                    161: 
                    162: 
                    163: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
                    164: 
                    165: static uint8_t  ether_packet[ETH_MTU_SIZE];
                    166: static uint32_t dhcp_own_ip        = 0;
                    167: static uint32_t dhcp_server_ip     = 0;
                    168: static uint32_t dhcp_siaddr_ip     = 0;
                    169: static int8_t   dhcp_filename[256];
                    170: static int8_t   dhcp_tftp_name[256];
                    171: 
                    172: static char   * response_buffer;
                    173: 
                    174: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
                    175: 
                    176: /**
                    177:  * DHCP: Obtains IP and configuration info from DHCP server
                    178:  *       (makes several attempts).
                    179:  *
                    180:  * @param  boot_device   a socket number used to send and recieve packets
                    181:  * @param  fn_ip         contains the following configuration information:
                    182:  *                       client MAC, client IP, TFTP-server MAC, 
                    183:  *                       TFTP-server IP, Boot file name
                    184:  * @return               ZERO - IP and configuration info obtained;
                    185:  *                       NON ZERO - error condition occurs.
                    186:  */
                    187: int32_t
                    188: dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) {
                    189:        int i = (int) retries+1;
                    190: 
                    191:        uint32_t dhcp_tftp_ip     = 0;
                    192:        strcpy((char *) dhcp_filename, "");
                    193:        strcpy((char *) dhcp_tftp_name, "");
                    194: 
                    195:        response_buffer = ret_buffer;
                    196: 
                    197:        printf("    ");
                    198: 
                    199:        do {
                    200:                printf("\b\b\b%03d", i-1);
                    201:                if (getchar() == 27) {
                    202:                        printf("\nAborted\n");
                    203:                        return -1;
                    204:                }
                    205:                if (!--i) {
                    206:                        printf("\nGiving up after %d DHCP requests\n", retries);
                    207:                        return -1;
                    208:                }
                    209:        } while (!dhcp_attempt());
                    210:        printf("\b\b\b\b");
                    211: 
                    212:        if (fn_ip->own_ip) {
                    213:                dhcp_own_ip = fn_ip->own_ip;
                    214:        }
                    215:        if (fn_ip->server_ip) {
                    216:                dhcp_siaddr_ip = fn_ip->server_ip;
                    217:        }
                    218:        if(fn_ip->filename[0] != 0) {
                    219:                strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
                    220:        }
                    221: 
                    222:        // TFTP SERVER
                    223:        if (!strlen((char *) dhcp_tftp_name)) {
                    224:                if (!dhcp_siaddr_ip) {
                    225:                        // ERROR: TFTP name is not presented
                    226:                        return -3;
                    227:                }
                    228: 
                    229:                // take TFTP-ip from siaddr field
                    230:                dhcp_tftp_ip = dhcp_siaddr_ip;
                    231:        }
                    232:        else {
                    233:                // TFTP server defined by its name
                    234:                if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
                    235:                        if (!dns_get_ip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
                    236:                                // DNS error - can't obtain TFTP-server name  
                    237:                                // Use TFTP-ip from siaddr field, if presented
                    238:                                if (dhcp_siaddr_ip) {
                    239:                                        dhcp_tftp_ip = dhcp_siaddr_ip;
                    240:                                }
                    241:                                else {
                    242:                                        // ERROR: Can't obtain TFTP server IP
                    243:                                        return -4;
                    244:                                }
                    245:                        }
                    246:                }
                    247:        }
                    248: 
                    249:        // Store configuration info into filename_ip strucutre
                    250:        fn_ip -> own_ip = dhcp_own_ip;
                    251:        fn_ip -> server_ip = dhcp_tftp_ip;
                    252:        strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
                    253: 
                    254:        return 0;
                    255: }
                    256: 
                    257: /**
                    258:  * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
                    259:  */
                    260: static int32_t
                    261: dhcp_attempt(void) {
                    262:        int sec;
                    263: 
                    264:        // Send DISCOVER message and switch DHCP-client to SELECT state
                    265:        dhcp_send_discover();
                    266: 
                    267:        dhcp_state = DHCP_STATE_SELECT;
                    268: 
                    269:        // setting up a timer with a timeout of two seconds
                    270:        for (sec = 0; sec < 2; sec++) {
                    271:                set_timer(TICKS_SEC);
                    272:                do {
                    273:                        receive_ether();
                    274: 
                    275:                        // Wait until client will switch to Final state or Timeout occurs
                    276:                        switch (dhcp_state) {
                    277:                        case DHCP_STATE_SUCCESS :
                    278:                                return 1;
                    279:                        case DHCP_STATE_FAULT :
                    280:                                return 0;
                    281:                        }
                    282:                } while (get_timer() > 0);
                    283:        }
                    284: 
                    285:        // timeout 
                    286:        return 0;
                    287: }
                    288: 
                    289: /**
                    290:  * DHCP: Supplements DHCP-message with options stored in structure.
                    291:  *       For more information about option coding see dhcp_options_t.
                    292:  *
                    293:  * @param  opt_field     Points to the "vend" field of DHCP-message  
                    294:  *                       (destination)
                    295:  * @param  opt_struct    this structure stores info about the options wich
                    296:  *                       will be added to DHCP-message (source)
                    297:  * @return               TRUE - options packed;
                    298:  *                       FALSE - error condition occurs.
                    299:  * @see                  dhcp_options_t
                    300:  */
                    301: static int32_t
                    302: dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
                    303:        uint8_t * options = opt_field;
                    304:        uint16_t i, sum; // used to define is any options set
                    305: 
                    306:        // magic
                    307:        memcpy(options, dhcp_magic, 4);
                    308:        options += 4;
                    309: 
                    310:        // fill message type
                    311:        switch (opt_struct -> msg_type) {
                    312:        case DHCPDISCOVER :
                    313:        case DHCPREQUEST :
                    314:        case DHCPDECLINE :
                    315:        case DHCPINFORM :
                    316:        case DHCPRELEASE :
                    317:                options[0] = DHCP_MSG_TYPE;
                    318:                options[1] = 1;
                    319:                options[2] = opt_struct -> msg_type;
                    320:                options += 3;
                    321:                break;
                    322:        default :
                    323:                return 0; // Unsupported DHCP-message
                    324:        }
                    325: 
                    326:        if (opt_struct -> overload) {
                    327:                options[0] = DHCP_OVERLOAD;
                    328:                options[1] = 0x01;
                    329:                options[2] = opt_struct -> overload;
                    330:                options +=3;
                    331:        }
                    332: 
                    333:        if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
                    334:                options[0] = DHCP_REQUESTED_IP;
                    335:                options[1] = 0x04;
                    336:                * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
                    337:                options +=6;
                    338:        }
                    339: 
                    340:        if (opt_struct -> flag[DHCP_SERVER_ID]) {
                    341:                options[0] = DHCP_SERVER_ID;
                    342:                options[1] = 0x04;
                    343:                * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
                    344:                options +=6;
                    345:        }
                    346: 
                    347:        sum = 0;
                    348:        for (i = 0; i < 256; i++)
                    349:                sum += opt_struct -> request_list[i];
                    350: 
                    351:        if (sum) {
                    352:                options[0] = DHCP_REQUEST_LIST;
                    353:                options[1] = sum;
                    354:                options += 2;
                    355:                for (i = 0; i < 256; i++) {
                    356:                        if (opt_struct -> request_list[i]) {
                    357:                                options[0] = i; options++;
                    358:                        }
                    359:                }
                    360:        }
                    361: 
                    362:        if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
                    363:                options[0] = DHCP_TFTP_SERVER;
                    364:                options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
                    365:                memcpy(options + 2, opt_struct -> tftp_server, options[1]);
                    366:                options += options[1] + 2;
                    367:        }
                    368: 
                    369:        if (opt_struct -> flag[DHCP_BOOTFILE]) {
                    370:                options[0] = DHCP_BOOTFILE;
                    371:                options[1] = strlen((char *) opt_struct -> bootfile) + 1;
                    372:                memcpy(options + 2, opt_struct -> bootfile, options[1]);
                    373:                options += options[1] + 2;
                    374:        }
                    375: 
                    376:        // end options
                    377:        options[0] = 0xFF;
                    378:        options++;
                    379: 
                    380:        return 1;
                    381: }
                    382: 
                    383: /**
                    384:  * DHCP: Extracts encoded options from DHCP-message into the structure.
                    385:  *       For more information about option coding see dhcp_options_t.
                    386:  *
                    387:  * @param  opt_field     Points to the "options" field of DHCP-message  
                    388:  *                       (source).
                    389:  * @param  opt_len       Length of "options" field.
                    390:  * @param  opt_struct    this structure stores info about the options wich
                    391:  *                       was extracted from DHCP-message (destination).
                    392:  * @return               TRUE - options extracted;
                    393:  *                       FALSE - error condition occurs.
                    394:  * @see                  dhcp_options_t
                    395:  */
                    396: static int32_t
                    397: dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
                    398:                     dhcp_options_t * opt_struct) {
                    399:        int32_t offset = 0;
                    400: 
                    401:        memset(opt_struct, 0, sizeof(dhcp_options_t));
                    402: 
                    403:        // magic
                    404:        if (memcmp(opt_field, dhcp_magic, 4)) {
                    405:                return 0;
                    406:        }
                    407: 
                    408:        offset += 4;
                    409:        while (offset < opt_len) {
                    410:                opt_struct -> flag[opt_field[offset]] = 1;
                    411:                switch(opt_field[offset]) {
                    412:                case DHCP_OVERLOAD :
                    413:                        opt_struct -> overload = opt_field[offset + 2];
                    414:                        offset += 2 + opt_field[offset + 1]; 
                    415:                        break;
                    416: 
                    417:                case DHCP_REQUESTED_IP :
                    418:                        opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
                    419:                        offset += 2 + opt_field[offset + 1]; 
                    420:                        break;
                    421: 
                    422:                case DHCP_MASK :
                    423:                        opt_struct -> flag[DHCP_MASK] = 1;
                    424:                        opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
                    425:                        offset += 2 + opt_field[offset + 1]; 
                    426:                        break;
                    427: 
                    428:                case DHCP_DNS :
                    429:                        opt_struct -> flag[DHCP_DNS] = 1;
                    430:                        opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
                    431:                        offset += 2 + opt_field[offset + 1]; 
                    432:                        break;
                    433: 
                    434:                case DHCP_ROUTER :
                    435:                        opt_struct -> flag[DHCP_ROUTER] = 1;
                    436:                        opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
                    437:                        offset += 2 + opt_field[offset + 1]; 
                    438:                        break;
                    439: 
                    440:                case DHCP_MSG_TYPE :
                    441:                        if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
                    442:                                opt_struct -> msg_type = opt_field[offset + 2];
                    443:                        else
                    444:                                return 0;
                    445:                        offset += 2 + opt_field[offset + 1];
                    446:                        break;
                    447: 
                    448:                case DHCP_SERVER_ID :
                    449:                        opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
                    450:                        offset += 2 + opt_field[offset + 1];
                    451:                        break;
                    452: 
                    453:                case DHCP_TFTP_SERVER   :
                    454:                        memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
                    455:                        (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
                    456:                        offset += 2 + opt_field[offset + 1];
                    457:                        break;
                    458: 
                    459:                case DHCP_BOOTFILE :
                    460:                        memcpy(opt_struct ->  bootfile, opt_field + offset + 2, opt_field[offset + 1]);
                    461:                        (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
                    462:                        offset += 2 + opt_field[offset + 1];
                    463:                        break;
                    464: 
                    465:                case DHCP_PADOPT :
                    466:                        offset++;
                    467:                        break;
                    468: 
                    469:                case DHCP_ENDOPT :  // End of options
                    470:                        return 1;
                    471: 
                    472:                default :
                    473:                        offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
                    474:                }
                    475:        }
                    476:        if (offset == opt_len)
                    477:                return 1; // options finished without 0xFF
                    478: 
                    479:        return 0;
                    480: }
                    481: 
                    482: /**
                    483:  * DHCP: Appends information from source "options" into dest "options".
                    484:  *       This function is used to support "file/sname" overloading.
                    485:  *
                    486:  * @param  dst_options   destanation "options" field
                    487:  * @param  dst_len       size of dst_options (modified by this function)
                    488:  * @param  src_options   source "options" field
                    489:  * @param  src_len       size of src_options
                    490:  * @return               TRUE - options merged;
                    491:  *                       FALSE - error condition occurs.
                    492:  */
                    493: static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
                    494:                                  uint8_t src_options[], uint32_t src_len) {
                    495:        int32_t dst_offset, src_offset = 0;
                    496: 
                    497:        // remove ENDOPT if presented
                    498:        if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
                    499:                * dst_len = dst_offset;
                    500: 
                    501:        while (src_offset < src_len) {
                    502:                switch(src_options[src_offset]) {
                    503:                case DHCP_PADOPT:
                    504:                        src_offset++;
                    505:                        break;
                    506:                case DHCP_ENDOPT:
                    507:                        return 1;
                    508:                default:
                    509:                        if (dhcp_find_option(dst_options, * dst_len,
                    510:                                             src_options[src_offset],
                    511:                                             (uint32_t *) &dst_offset)) {
                    512:                                dhcp_combine_option(dst_options, dst_len,
                    513:                                                    dst_offset,
                    514:                                                    (uint8_t *) src_options +
                    515:                                                    src_offset);
                    516:                        }
                    517:                        else {
                    518:                                dhcp_append_option(dst_options, dst_len, src_options + src_offset);
                    519:                        }
                    520:                        src_offset += 2 + src_options[src_offset + 1];
                    521:                }
                    522:        }
                    523: 
                    524:        if (src_offset == src_len) 
                    525:                return 1;
                    526:        return 0;
                    527: }
                    528: 
                    529: /**
                    530:  * DHCP: Finds given occurence of the option with the given code (op_code)
                    531:  *       in "options" field of DHCP-message.
                    532:  *
                    533:  * @param  options       "options" field of DHCP-message
                    534:  * @param  len           length of the "options" field
                    535:  * @param  op_code       code of the option to find
                    536:  * @param  op_offset     SUCCESS - offset to an option occurence;
                    537:  *                       FAULT - offset is set to zero.
                    538:  * @return               TRUE - option was find;
                    539:  *                       FALSE - option wasn't find.
                    540:  */
                    541: static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
                    542:                                uint8_t op_code, uint32_t * op_offset) {
                    543:        uint32_t srch_offset = 0;
                    544:        * op_offset = 0;
                    545: 
                    546:        while (srch_offset < len) {
                    547:                if (options[srch_offset] == op_code) {
                    548:                        * op_offset = srch_offset;
                    549:                        return 1;
                    550:                }
                    551:                if (options[srch_offset] == DHCP_ENDOPT)
                    552:                        return 0;
                    553: 
                    554:                if (options[srch_offset] == DHCP_PADOPT)
                    555:                        srch_offset++;
                    556:                else
                    557:                        srch_offset += 2 + options[srch_offset + 1];
                    558:        }
                    559:        return 0;
                    560: }
                    561: 
                    562: /**
                    563:  * DHCP: Appends new option from one list (src) into the tail
                    564:  *       of another option list (dst)
                    565:  *
                    566:  * @param  dst_options   "options" field of DHCP-message
                    567:  * @param  dst_len       length of the "options" field (modified)
                    568:  * @param  new_option    points to an option in another list (src)
                    569:  */
                    570: static void
                    571: dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
                    572:                    uint8_t * new_option) {
                    573:        memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
                    574:        * dst_len += 2 + *(new_option + 1);
                    575: }
                    576: 
                    577: /**
                    578:  * DHCP: This function is used when options with the same code are
                    579:  *       presented in both merged lists. In this case information
                    580:  *       about the option from one list (src) is combined (complemented)
                    581:  *       with information about the option in another list (dst).
                    582:  *
                    583:  * @param  dst_options  "options" field of DHCP-message
                    584:  * @param  dst_len       length of the "options" field (modified)
                    585:  * @param  dst_offset    offset of the option from beggining of the list
                    586:  * @param  new_option    points to an option in another list (src)
                    587:  */
                    588: static void
                    589: dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
                    590:                     uint32_t dst_offset, uint8_t * new_option) {
                    591: 
                    592:        uint8_t tmp_buffer[1024]; // use to provide safe memcpy
                    593:        uint32_t tail_len;
                    594: 
                    595:        // move all subsequent options (allocate size for additional info)
                    596:        tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
                    597: 
                    598:        memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
                    599:        memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
                    600:               tmp_buffer, tail_len);
                    601: 
                    602:        // add new_content to option
                    603:        memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
                    604:               * (new_option + 1));
                    605:        dst_options[dst_offset + 1] += * (new_option + 1);
                    606: 
                    607:        // correct dst_len
                    608:        * dst_len += * (new_option + 1);
                    609: }
                    610: 
                    611: /**
                    612:  * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
                    613:  */
                    614: static void
                    615: dhcp_send_discover(void) {
                    616:        uint32_t packetsize = sizeof(struct iphdr) +
                    617:                              sizeof(struct udphdr) + sizeof(struct btphdr);
                    618:        struct btphdr *btph;
                    619:        dhcp_options_t opt;
                    620: 
                    621:        memset(ether_packet, 0, packetsize);
                    622: 
                    623:        btph = (struct btphdr *) (&ether_packet[
                    624:               sizeof(struct iphdr) + sizeof(struct udphdr)]);
                    625: 
                    626:        btph -> op = 1;
                    627:        btph -> htype = 1;
                    628:        btph -> hlen = 6;
                    629:        memcpy(btph -> chaddr, get_mac_address(), 6);
                    630: 
                    631:        memset(&opt, 0, sizeof(dhcp_options_t));
                    632: 
                    633:        opt.msg_type = DHCPDISCOVER;
                    634: 
                    635:        opt.request_list[DHCP_MASK] = 1;
                    636:        opt.request_list[DHCP_DNS] = 1;
                    637:        opt.request_list[DHCP_ROUTER] = 1;
                    638:        opt.request_list[DHCP_TFTP_SERVER] = 1;
                    639:        opt.request_list[DHCP_BOOTFILE] = 1;
                    640: 
                    641:        dhcp_encode_options(btph -> vend, &opt);
                    642: 
                    643:        fill_udphdr(&ether_packet[sizeof(struct iphdr)],
                    644:                    sizeof(struct btphdr) + sizeof(struct udphdr),
                    645:                    UDPPORT_BOOTPC, UDPPORT_BOOTPS);
                    646:        fill_iphdr(ether_packet, sizeof(struct btphdr) +
                    647:                   sizeof(struct udphdr) + sizeof(struct iphdr),
                    648:                   IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF);
                    649: 
                    650:        send_ipv4(ether_packet, packetsize);
                    651: }
                    652: 
                    653: /**
                    654:  * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
                    655:  */
                    656: static void
                    657: dhcp_send_request(void) {
                    658:        uint32_t packetsize = sizeof(struct iphdr) +
                    659:                              sizeof(struct udphdr) + sizeof(struct btphdr);
                    660:        struct btphdr *btph;
                    661:        dhcp_options_t opt;
                    662: 
                    663:        memset(ether_packet, 0, packetsize);
                    664: 
                    665:        btph = (struct btphdr *) (&ether_packet[
                    666:               sizeof(struct iphdr) + sizeof(struct udphdr)]);
                    667: 
                    668:        btph -> op = 1;
                    669:        btph -> htype = 1;
                    670:        btph -> hlen = 6;
                    671:        memcpy(btph -> chaddr, get_mac_address(), 6);
                    672: 
                    673:        memset(&opt, 0, sizeof(dhcp_options_t));
                    674: 
                    675:        opt.msg_type = DHCPREQUEST;
                    676:        memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
                    677:        opt.flag[DHCP_REQUESTED_IP] = 1;
                    678:        memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
                    679:        opt.flag[DHCP_SERVER_ID] = 1;
                    680: 
                    681:        opt.request_list[DHCP_MASK] = 1;
                    682:        opt.request_list[DHCP_DNS] = 1;
                    683:        opt.request_list[DHCP_ROUTER] = 1;
                    684:        opt.request_list[DHCP_TFTP_SERVER] = 1;
                    685:        opt.request_list[DHCP_BOOTFILE] = 1;
                    686: 
                    687:        dhcp_encode_options(btph -> vend, &opt);
                    688: 
                    689:        fill_udphdr(&ether_packet[sizeof(struct iphdr)],
                    690:                    sizeof(struct btphdr) + sizeof(struct udphdr),
                    691:                    UDPPORT_BOOTPC, UDPPORT_BOOTPS);
                    692:        fill_iphdr(ether_packet, sizeof(struct btphdr) +
                    693:                   sizeof(struct udphdr) + sizeof(struct iphdr),
                    694:                   IPTYPE_UDP, 0, 0xFFFFFFFF);
                    695: 
                    696:        send_ipv4(ether_packet, packetsize);
                    697: }
                    698: 
                    699: 
                    700: /**
                    701:  * DHCP: Sends DHCP-Release message. Releases occupied IP.
                    702:  */
                    703: void dhcp_send_release(void) {
                    704:        uint32_t packetsize = sizeof(struct iphdr) +
                    705:                              sizeof(struct udphdr) + sizeof(struct btphdr);
                    706:        struct btphdr *btph;
                    707:        dhcp_options_t opt;
                    708: 
                    709:        btph = (struct btphdr *) (&ether_packet[
                    710:               sizeof(struct iphdr) + sizeof(struct udphdr)]);
                    711: 
                    712:        memset(ether_packet, 0, packetsize);
                    713: 
                    714:        btph -> op = 1;
                    715:        btph -> htype = 1;
                    716:        btph -> hlen = 6;
                    717:        strcpy((char *) btph -> file, "");
                    718:        memcpy(btph -> chaddr, get_mac_address(), 6);
                    719:        btph -> ciaddr = htonl(dhcp_own_ip);
                    720: 
                    721:        memset(&opt, 0, sizeof(dhcp_options_t));
                    722: 
                    723:        opt.msg_type = DHCPRELEASE;
                    724:        opt.server_ID = dhcp_server_ip;
                    725:        opt.flag[DHCP_SERVER_ID] = 1;
                    726: 
                    727:        dhcp_encode_options(btph -> vend, &opt);
                    728: 
                    729:        fill_udphdr(&ether_packet[sizeof(struct iphdr)], 
                    730:                    sizeof(struct btphdr) + sizeof(struct udphdr),
                    731:                    UDPPORT_BOOTPC, UDPPORT_BOOTPS);
                    732:        fill_iphdr(ether_packet, sizeof(struct btphdr) +
                    733:                   sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP,
                    734:                   dhcp_own_ip, dhcp_server_ip);
                    735: 
                    736:        send_ipv4(ether_packet, packetsize);
                    737: }
                    738: 
                    739: /**
                    740:  * DHCP: Handles DHCP-messages according to Receive-handle diagram.
                    741:  *       Changes the state of DHCP-client.
                    742:  *
                    743:  * @param  packet     BootP/DHCP-packet to be handled
                    744:  * @param  packetsize length of the packet
                    745:  * @return            ZERO - packet handled successfully;
                    746:  *                    NON ZERO - packet was not handled (e.g. bad format)
                    747:  * @see               receive_ether
                    748:  * @see               btphdr
                    749:  */
                    750: 
                    751: int8_t
                    752: handle_dhcp(uint8_t * packet, int32_t packetsize) {
                    753:        struct btphdr * btph;
                    754:        struct iphdr * iph;
                    755:        dhcp_options_t opt;
                    756: 
                    757:        memset(&opt, 0, sizeof(dhcp_options_t));  
                    758:        btph = (struct btphdr *) packet;
                    759:        iph = (struct iphdr *) packet - sizeof(struct udphdr) -
                    760:              sizeof(struct iphdr);
                    761:        if (btph -> op != 2)
                    762:                return -1; // it is not Boot Reply
                    763: 
                    764:        if(response_buffer) {
                    765:                if(packetsize <= 1720)
                    766:                        memcpy(response_buffer, packet, packetsize);
                    767:                else
                    768:                        memcpy(response_buffer, packet, 1720);
                    769:        }
                    770: 
                    771:        if (memcmp(btph -> vend, dhcp_magic, 4)) {
                    772:                // It is BootP - RFC 951
                    773:                dhcp_own_ip    = htonl(btph -> yiaddr);
                    774:                dhcp_siaddr_ip = htonl(btph -> siaddr);
                    775:                dhcp_server_ip = htonl(iph -> ip_src);
                    776: 
                    777:                if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
                    778:                        strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
                    779:                                sizeof(btph -> sname));
                    780:                        dhcp_tftp_name[sizeof(btph -> sname)] = 0;
                    781:                }
                    782: 
                    783:                if (strlen((char *) btph -> file)) {
                    784:                        strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
                    785:                        dhcp_filename[sizeof(btph -> file)] = 0;
                    786:                }
                    787: 
                    788:                dhcp_state = DHCP_STATE_SUCCESS;
                    789:                return 0;
                    790:        }
                    791: 
                    792: 
                    793:        // decode options  
                    794:        if (!dhcp_decode_options(btph -> vend, packetsize -
                    795:                                 sizeof(struct btphdr) + sizeof(btph -> vend),
                    796:                                 &opt)) {
                    797:                return -1;  // can't decode options
                    798:        }
                    799: 
                    800:        if (opt.overload) {
                    801:                int16_t decode_res = 0;
                    802:                uint8_t options[1024]; // buffer for merged options
                    803:                uint32_t opt_len;
                    804: 
                    805:                // move 1-st part of options from vend field into buffer
                    806:                opt_len = packetsize - sizeof(struct btphdr) +
                    807:                          sizeof(btph -> vend) - 4;
                    808:                memcpy(options, btph -> vend, opt_len + 4);
                    809: 
                    810:                // add other parts
                    811:                switch (opt.overload) {
                    812:                case DHCP_OVERLOAD_FILE:
                    813:                        decode_res = dhcp_merge_options(options + 4, &opt_len,
                    814:                                                        btph -> file,
                    815:                                                        sizeof(btph -> file));
                    816:                        break;
                    817:                case DHCP_OVERLOAD_SNAME:
                    818:                        decode_res = dhcp_merge_options(options + 4, &opt_len,
                    819:                                                        btph -> sname,
                    820:                                                        sizeof(btph -> sname));
                    821:                        break;
                    822:                case DHCP_OVERLOAD_BOTH:
                    823:                        decode_res = dhcp_merge_options(options + 4, &opt_len,
                    824:                                                        btph -> file,
                    825:                                                        sizeof(btph -> file));
                    826:                        if (!decode_res)
                    827:                                break;
                    828:                        decode_res = dhcp_merge_options(options + 4, &opt_len,
                    829:                                                        btph -> sname,
                    830:                                                        sizeof(btph -> sname));
                    831:                        break;
                    832:                }
                    833: 
                    834:                if (!decode_res)
                    835:                        return -1; // bad options in sname/file fields
                    836: 
                    837:                // decode merged options
                    838:                if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
                    839:                        return -1; // can't decode options
                    840:                }
                    841:        }
                    842: 
                    843:        if (!opt.msg_type) {
                    844:                // It is BootP with Extensions - RFC 1497
                    845:                // retrieve conf. settings from BootP - reply
                    846:                dhcp_own_ip = htonl(btph -> yiaddr);
                    847:                dhcp_siaddr_ip = htonl(btph -> siaddr);
                    848:                if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
                    849:                        strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
                    850:                        dhcp_tftp_name[sizeof(btph -> sname)] = 0;
                    851:                }
                    852: 
                    853:                if (strlen((char *) btph -> file)) {
                    854:                        strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
                    855:                        dhcp_filename[sizeof(btph -> file)] = 0;
                    856:                }
                    857: 
                    858:                // retrieve DHCP-server IP from IP-header
                    859:                dhcp_server_ip = iph -> htonl(ip_src);
                    860: 
                    861:                dhcp_state = DHCP_STATE_SUCCESS;
                    862:        }
                    863:        else {
                    864:                // It is DHCP - RFC 2131 & RFC 2132
                    865:                // opt contains parameters from server
                    866:                switch (dhcp_state) {
                    867:                case DHCP_STATE_SELECT :
                    868:                        if (opt.msg_type == DHCPOFFER) {
                    869:                                dhcp_own_ip = htonl(btph -> yiaddr);
                    870:                                dhcp_server_ip = opt.server_ID;
                    871:                                dhcp_send_request();
                    872:                                dhcp_state = DHCP_STATE_REQUEST;
                    873:                        }
                    874:                        return 0;
                    875:                case DHCP_STATE_REQUEST :
                    876:                        switch (opt.msg_type) {
                    877:                        case DHCPNACK :
                    878:                                dhcp_own_ip = 0;
                    879:                                dhcp_server_ip = 0;
                    880:                                dhcp_state = DHCP_STATE_FAULT;
                    881:                                break;
                    882:                        case DHCPACK :
                    883:                                dhcp_own_ip = htonl(btph -> yiaddr);
                    884:                                dhcp_server_ip = opt.server_ID;
                    885:                                dhcp_siaddr_ip = htonl(btph -> siaddr);
                    886:                                if (opt.flag[DHCP_TFTP_SERVER]) {
                    887:                                        strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
                    888:                                }
                    889:                                else {
                    890:                                        strcpy((char *) dhcp_tftp_name, "");
                    891:                                        if ((opt.overload != DHCP_OVERLOAD_SNAME &&
                    892:                                             opt.overload != DHCP_OVERLOAD_BOTH) &&
                    893:                                             !dhcp_siaddr_ip) {
                    894:                                                strncpy((char *) dhcp_tftp_name,
                    895:                                                        (char *) btph->sname,
                    896:                                                        sizeof(btph -> sname));
                    897:                                                dhcp_tftp_name[sizeof(btph->sname)] = 0;
                    898:                                        }
                    899:                                }
                    900: 
                    901:                                if (opt.flag[DHCP_BOOTFILE]) {
                    902:                                        strcpy((char *) dhcp_filename, (char *) opt.bootfile);
                    903:                                }
                    904:                                else {
                    905:                                        strcpy((char *) dhcp_filename, "");
                    906:                                        if (opt.overload != DHCP_OVERLOAD_FILE &&
                    907:                                                opt.overload != DHCP_OVERLOAD_BOTH && 
                    908:                                                strlen((char *) btph -> file)) {
                    909:                                                strncpy((char *) dhcp_filename,
                    910:                                                        (char *) btph->file,
                    911:                                                        sizeof(btph->file));
                    912:                                                dhcp_filename[sizeof(btph -> file)] = 0;
                    913:                                        }
                    914:                                }
                    915: 
                    916:                                dhcp_state = DHCP_STATE_SUCCESS;
                    917:                                break;
                    918:                        default:
                    919:                                break; // Unused DHCP-message - do nothing
                    920:                        }
                    921:                        break;
                    922:                default :
                    923:                        return -1; // Illegal DHCP-client state
                    924:                }
                    925:        }
                    926: 
                    927:        if (dhcp_state == DHCP_STATE_SUCCESS) {
                    928: 
                    929:                // initialize network entity with real own_ip
                    930:                // to be able to answer for foreign requests
                    931:                set_ipv4_address(dhcp_own_ip);
                    932: 
                    933:                /* Subnet mask */
                    934:                if (opt.flag[DHCP_MASK]) {
                    935:                        /* Router */
                    936:                        if (opt.flag[DHCP_ROUTER]) {
                    937:                                set_ipv4_router(opt.router_IP);
                    938:                                set_ipv4_netmask(opt.subnet_mask);
                    939:                        }
                    940:                }
                    941: 
                    942:                /* DNS-server */
                    943:                if (opt.flag[DHCP_DNS]) {
                    944:                        dns_init(opt.dns_IP);
                    945:                }
                    946:        }
                    947: 
                    948:        return 0;
                    949: }
                    950: 
                    951: /**
                    952:  * DHCP: Converts "255.255.255.255" -> 32-bit long IP
                    953:  *
                    954:  * @param  str        string to be converted
                    955:  * @param  ip         in case of SUCCESS - 32-bit long IP
                    956:                       in case of FAULT - zero
                    957:  * @return            TRUE - IP converted successfully;
                    958:  *                    FALSE - error condition occurs (e.g. bad format)
                    959:  */
                    960: static uint8_t
                    961: strtoip(int8_t * str, uint32_t * ip) {
                    962:        int8_t ** ptr = &str;
                    963:        int16_t i = 0, res, len;
                    964:        char octet[256];
                    965: 
                    966:        * ip = 0;
                    967: 
                    968:        while (**ptr != 0) {
                    969:                if (i > 3 || !isdigit(**ptr))
                    970:                        return 0;
                    971:                if (strstr((char *) * ptr, ".") != NULL) {
                    972:                        len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") - 
                    973:                              (int8_t *) (* ptr));
                    974:                        strncpy(octet, (char *) * ptr, len); octet[len] = 0;
                    975:                        * ptr += len;
                    976:                }
                    977:                else {
                    978:                        strcpy(octet, (char *) * ptr);
                    979:                        * ptr += strlen(octet);
                    980:                }
                    981:                res = strtol(octet, NULL, 10);
                    982:                if ((res > 255) || (res < 0))
                    983:                        return 0;
                    984:                * ip = ((* ip) << 8) + res;
                    985:                i++;
                    986:                if (** ptr == '.')
                    987:                        (*ptr)++;
                    988:        }
                    989: 
                    990:        if (i != 4)
                    991:                return 0;
                    992:        return 1;
                    993: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.