Annotation of qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c, revision 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.