|
|
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 *) (ðer_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(ðer_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 *) (ðer_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(ðer_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 *) (ðer_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(ðer_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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.