1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * DHCP Client File: net_dhcp.c 5 * 6 * This module contains a DHCP client. 7 * 8 * Author: Mitch Lichtenberg (mpl@broadcom.com) 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47#include "lib_types.h" 48#include "lib_string.h" 49#include "lib_queue.h" 50#include "lib_malloc.h" 51#include "lib_printf.h" 52 53#include "env_subr.h" 54 55#include "cfe_iocb.h" 56#include "cfe_devfuncs.h" 57#include "cfe_ioctl.h" 58#include "cfe_timer.h" 59#include "cfe_error.h" 60 61#include "net_ebuf.h" 62#include "net_ether.h" 63 64#include "cfe.h" 65 66#include "net_api.h" 67 68/* ********************************************************************* 69 * Constants 70 ********************************************************************* */ 71 72 73#define UDP_PORT_BOOTPS 67 74#define UDP_PORT_BOOTPC 68 75 76#define DHCP_REQ_TIMEOUT (1*CFE_HZ) 77#define DHCP_NUM_RETRIES 8 78 79#define DHCP_OP_BOOTREQUEST 1 80#define DHCP_OP_BOOTREPLY 2 81 82#define DHCP_HWTYPE_ETHERNET 1 83 84#define DHCP_TAG_FUNCTION 53 85#define DHCP_FUNCTION_DISCOVER 1 86#define DHCP_FUNCTION_OFFER 2 87#define DHCP_FUNCTION_REQUEST 3 88#define DHCP_FUNCTION_ACK 5 89 90#define DHCP_TAG_NETMASK 1 91#define DHCP_TAG_DOMAINNAME 0x0F 92#define DHCP_TAG_GATEWAY 0x03 93#define DHCP_TAG_NAMESERVER 0x06 94#define DHCP_TAG_SWAPSERVER 0x10 95#define DHCP_TAG_ROOTPATH 0x11 96#define DHCP_TAG_EXTENSIONS 0x12 97#define DHCP_TAG_SERVERIDENT 54 98#define DHCP_TAG_PARAMLIST 55 99#define DHCP_TAG_CLIENTID 61 100#define DHCP_TAG_CLASSID 60 101#define DHCP_TAG_REQADDR 50 102#define DHCP_TAG_LEASE_TIME 51 103#define DHCP_TAG_SCRIPT 130 /* CFE extended option */ 104#define DHCP_TAG_OPTIONS 131 /* CFE extended option */ 105 106#define DHCP_TAG_END 0xFF 107 108#define DHCP_MAGIC_NUMBER 0x63825363 109 110/*#define _DEBUG_*/ 111 112 113/* ********************************************************************* 114 * dhcp_set_envvars(reply) 115 * 116 * Using the supplied DHCP reply data, set environment variables 117 * to contain data from the reply. 118 * 119 * Input parameters: 120 * reply - dhcp reply 121 * 122 * Return value: 123 * nothing 124 ********************************************************************* */ 125 126void dhcp_set_envvars(dhcpreply_t *reply) 127{ 128 char buffer[50]; 129 130 env_delenv("BOOT_SERVER"); 131 env_delenv("BOOT_FILE"); 132 env_delenv("BOOT_SCRIPT"); 133 env_delenv("BOOT_OPTIONS"); 134 135 if (reply->dr_bootserver[0] | reply->dr_bootserver[1] | 136 reply->dr_bootserver[2] | reply->dr_bootserver[3]) { 137 sprintf(buffer,"%I",reply->dr_bootserver); 138 env_setenv("BOOT_SERVER",buffer,ENV_FLG_BUILTIN); 139 } 140 141 if (reply->dr_bootfile && reply->dr_bootfile[0]) { 142 env_setenv("BOOT_FILE",reply->dr_bootfile,ENV_FLG_BUILTIN); 143 } 144 145 if (reply->dr_script && reply->dr_script[0]) { 146 env_setenv("BOOT_SCRIPT",reply->dr_script,ENV_FLG_BUILTIN); 147 } 148 149 if (reply->dr_options && reply->dr_options[0]) { 150 env_setenv("BOOT_OPTIONS",reply->dr_options,ENV_FLG_BUILTIN); 151 } 152} 153 154/* ********************************************************************* 155 * dhcp_dumptag(tag,len,buf) 156 * 157 * Dump out information from a DHCP tag 158 * 159 * Input parameters: 160 * tag - tag ID 161 * len - length of data 162 * buf - data 163 * 164 * Return value: 165 * nothing 166 ********************************************************************* */ 167 168#ifdef _DEBUG_ 169static void dhcp_dumptag(uint8_t tag,uint8_t len,uint8_t *buf) 170{ 171 unsigned int idx; 172 173 xprintf("DHCP: "); 174 175 switch (tag) { 176 case DHCP_TAG_FUNCTION: 177 xprintf("DHCP Function: %d\n",buf[0]); 178 break; 179 case DHCP_TAG_LEASE_TIME: 180 idx = (((unsigned int) buf[0]) << 24) | 181 (((unsigned int) buf[1]) << 16) | 182 (((unsigned int) buf[2]) << 8) | 183 (((unsigned int) buf[3]) << 0); 184 xprintf("Lease Time: %d seconds\n",idx); 185 break; 186 case DHCP_TAG_SERVERIDENT: 187 xprintf("DHCP Server ID: %d.%d.%d.%d\n", 188 buf[0],buf[1],buf[2],buf[3]); 189 break; 190 case DHCP_TAG_NETMASK: 191 xprintf("Netmask: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); 192 break; 193 case DHCP_TAG_DOMAINNAME: 194 buf[len] = 0; 195 xprintf("Domain: %s\n",buf); 196 break; 197 case DHCP_TAG_GATEWAY: 198 xprintf("Gateway: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); 199 break; 200 case DHCP_TAG_NAMESERVER: 201 xprintf("Nameserver: %d.%d.%d.%d\n",buf[0],buf[1],buf[2],buf[3]); 202 break; 203 case DHCP_TAG_SWAPSERVER: 204 buf[len] = 0; 205 xprintf("Swapserver: %s\n",buf); 206 break; 207 case DHCP_TAG_ROOTPATH: 208 buf[len] = 0; 209 xprintf("Rootpath: %s\n",buf); 210 break; 211 case DHCP_TAG_SCRIPT: 212 buf[len] = 0; 213 xprintf("CFE Script: %s\n",buf); 214 break; 215 case DHCP_TAG_OPTIONS: 216 buf[len] = 0; 217 xprintf("CFE Boot Options: %s\n",buf); 218 break; 219 default: 220 xprintf("Tag %d len %d [",tag,len); 221 for (idx = 0; idx < len; idx++) { 222 if ((buf[idx] >= 32) && (buf[idx] < 127)) xprintf("%c",buf[idx]); 223 } 224 xprintf("]\n"); 225 break; 226 227 } 228} 229#endif 230 231/* ********************************************************************* 232 * dhcp_free_reply(reply) 233 * 234 * Free memory associated with a DHCP reply. 235 * 236 * Input parameters: 237 * reply - pointer to DHCP reply 238 * 239 * Return value: 240 * nothing 241 ********************************************************************* */ 242 243void dhcp_free_reply(dhcpreply_t *reply) 244{ 245 if (reply->dr_hostname) KFREE(reply->dr_hostname); 246 if (reply->dr_domainname) KFREE(reply->dr_domainname); 247 if (reply->dr_bootfile) KFREE(reply->dr_bootfile); 248 if (reply->dr_rootpath) KFREE(reply->dr_rootpath); 249 if (reply->dr_swapserver) KFREE(reply->dr_swapserver); 250 if (reply->dr_script) KFREE(reply->dr_script); 251 if (reply->dr_options) KFREE(reply->dr_options); 252 KFREE(reply); 253} 254 255/* ********************************************************************* 256 * dhcp_build_discover() 257 * 258 * Build a DHCP DISCOVER packet 259 * 260 * Input parameters: 261 * hwaddr - our hardware address 262 * idptr - pointer to int to receive the DHCP packet ID 263 * serveraddr - pointer to server address (REQUEST) or 264 * NULL (DISCOVER) 265 * ebufptr - receives pointer to ebuf 266 * 267 * Return value: 268 * 0 if ok, else error code 269 ********************************************************************* */ 270 271static int dhcp_build_discover(uint8_t *hwaddr, 272 uint32_t id, 273 ebuf_t **ebufptr) 274{ 275 uint8_t ipaddr[IP_ADDR_LEN]; 276 ebuf_t *buf; 277 uint8_t junk[128]; 278 279 /* 280 * Get a buffer and fill it in. 281 */ 282 283 ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0; 284 memset(junk,0,sizeof(junk)); 285 286 buf = udp_alloc(); 287 288 if (buf == NULL) { 289 return CFE_ERR_NOMEM; 290 } 291 292 memset(buf->eb_ptr,0,548); 293 294 ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST); 295 ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET); 296 ebuf_append_u8(buf,ENET_ADDR_LEN); 297 ebuf_append_u8(buf,0); /* hops */ 298 ebuf_append_u32_be(buf,id); 299 ebuf_append_u16_be(buf,0); /* sec since boot */ 300 ebuf_append_u16_be(buf,0); /* flags */ 301 302 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */ 303 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */ 304 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */ 305 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */ 306 307 ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */ 308 ebuf_append_bytes(buf,junk,10); /* rest of chaddr */ 309 ebuf_append_bytes(buf,junk,64); /* sname */ 310 ebuf_append_bytes(buf,junk,128); /* file */ 311 312 ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER); 313 314 ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */ 315 ebuf_append_u8(buf,1); 316 ebuf_append_u8(buf,DHCP_FUNCTION_DISCOVER); 317 318 ebuf_append_u8(buf,DHCP_TAG_PARAMLIST); 319 ebuf_append_u8(buf,8); /* count of tags that follow */ 320 ebuf_append_u8(buf,DHCP_TAG_NETMASK); 321 ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME); 322 ebuf_append_u8(buf,DHCP_TAG_GATEWAY); 323 ebuf_append_u8(buf,DHCP_TAG_NAMESERVER); 324 ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER); 325 ebuf_append_u8(buf,DHCP_TAG_ROOTPATH); 326 ebuf_append_u8(buf,DHCP_TAG_SCRIPT); 327 ebuf_append_u8(buf,DHCP_TAG_OPTIONS); 328 329 330 ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */ 331 332 /* 333 * Return the packet 334 */ 335 336 *ebufptr = buf; 337 338 return 0; 339} 340 341/* ********************************************************************* 342 * dhcp_build_request() 343 * 344 * Build a DHCP DISCOVER or REQUEST packet 345 * 346 * Input parameters: 347 * hwaddr - our hardware address 348 * idptr - pointer to int to receive the DHCP packet ID 349 * serveraddr - pointer to server address (REQUEST) or 350 * NULL (DISCOVER) 351 * ebufptr - receives pointer to ebuf 352 * 353 * Return value: 354 * 0 if ok, else error code 355 ********************************************************************* */ 356 357static int dhcp_build_request(uint8_t *hwaddr, 358 uint32_t id, 359 uint8_t *serveraddr, 360 uint8_t *reqip, 361 ebuf_t **ebufptr) 362{ 363 uint8_t ipaddr[IP_ADDR_LEN]; 364 ebuf_t *buf; 365 uint8_t junk[128]; 366 367 /* 368 * Get a buffer and fill it in. 369 */ 370 371 ipaddr[0] = 0; ipaddr[1] = 0; ipaddr[2] = 0; ipaddr[3] = 0; 372 memset(junk,0,sizeof(junk)); 373 374 buf = udp_alloc(); 375 376 if (buf == NULL) { 377 return CFE_ERR_NOMEM; 378 } 379 380 memset(buf->eb_ptr,0,548); 381 382 ebuf_append_u8(buf,DHCP_OP_BOOTREQUEST); 383 ebuf_append_u8(buf,DHCP_HWTYPE_ETHERNET); 384 ebuf_append_u8(buf,ENET_ADDR_LEN); 385 ebuf_append_u8(buf,0); /* hops */ 386 ebuf_append_u32_be(buf,id); 387 ebuf_append_u16_be(buf,0); /* sec since boot */ 388 ebuf_append_u16_be(buf,0); /* flags */ 389 390 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* ciaddr */ 391 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* yiaddr */ 392 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* siaddr */ 393 ebuf_append_bytes(buf,ipaddr,IP_ADDR_LEN); /* giaddr */ 394 395 ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); /* chaddr */ 396 ebuf_append_bytes(buf,junk,10); /* rest of chaddr */ 397 398 ebuf_append_bytes(buf,junk,64); /* sname */ 399 400 ebuf_append_bytes(buf,junk,128); /* file */ 401 402 ebuf_append_u32_be(buf,DHCP_MAGIC_NUMBER); 403 404 ebuf_append_u8(buf,DHCP_TAG_FUNCTION); /* function code */ 405 ebuf_append_u8(buf,1); 406 407 ebuf_append_u8(buf,DHCP_FUNCTION_REQUEST); 408 409 ebuf_append_u8(buf,DHCP_TAG_REQADDR); 410 ebuf_append_u8(buf,IP_ADDR_LEN); 411 ebuf_append_bytes(buf,reqip,IP_ADDR_LEN); 412 413 ebuf_append_u8(buf,DHCP_TAG_SERVERIDENT); /* server ID */ 414 ebuf_append_u8(buf,IP_ADDR_LEN); 415 ebuf_append_bytes(buf,serveraddr,IP_ADDR_LEN); 416 417 ebuf_append_u8(buf,DHCP_TAG_CLIENTID); /* client ID */ 418 ebuf_append_u8(buf,7); 419 ebuf_append_u8(buf,1); 420 ebuf_append_bytes(buf,hwaddr,ENET_ADDR_LEN); 421 422 ebuf_append_u8(buf,DHCP_TAG_PARAMLIST); 423 ebuf_append_u8(buf,8); /* count of tags that follow */ 424 ebuf_append_u8(buf,DHCP_TAG_NETMASK); 425 ebuf_append_u8(buf,DHCP_TAG_DOMAINNAME); 426 ebuf_append_u8(buf,DHCP_TAG_GATEWAY); 427 ebuf_append_u8(buf,DHCP_TAG_NAMESERVER); 428 ebuf_append_u8(buf,DHCP_TAG_SWAPSERVER); 429 ebuf_append_u8(buf,DHCP_TAG_ROOTPATH); 430 ebuf_append_u8(buf,DHCP_TAG_SCRIPT); 431 ebuf_append_u8(buf,DHCP_TAG_OPTIONS); 432 433 434 ebuf_append_u8(buf,DHCP_TAG_END); /* terminator */ 435 436 /* 437 * Return the packet 438 */ 439 440 *ebufptr = buf; 441 442 return 0; 443} 444 445 446/* ********************************************************************* 447 * dhcp_wait_reply(s,id,reply,serveraddr) 448 * 449 * Wait for a reply from the DHCP server 450 * 451 * Input parameters: 452 * s - socket 453 * id - ID of request we sent 454 * reply - structure to store results in 455 * expfcode - expected DHCP_FUNCTION tag value 456 * 457 * Return value: 458 * 0 if ok (reply found) 459 * else error 460 ********************************************************************* */ 461 462static int dhcp_wait_reply(int s,uint32_t id,dhcpreply_t *reply,int expfcode) 463{ 464 uint32_t tmpd; 465 uint8_t tmpb; 466 int64_t timer; 467 int nres = 0; 468 uint8_t ciaddr[IP_ADDR_LEN]; 469 uint8_t yiaddr[IP_ADDR_LEN]; 470 uint8_t siaddr[IP_ADDR_LEN]; 471 uint8_t giaddr[IP_ADDR_LEN]; 472 uint8_t junk[128]; 473 char *hostname; 474 char *bootfile; 475 ebuf_t *buf; 476 int fcode = -1; 477 478 /* 479 * Set a timer for the response 480 */ 481 482 TIMER_SET(timer,DHCP_REQ_TIMEOUT); 483 484 /* 485 * Start waiting... 486 */ 487 488 while (!TIMER_EXPIRED(timer)) { 489 POLL(); 490 491 buf = udp_recv(s); 492 if (!buf) continue; 493 494 ebuf_get_u8(buf,tmpb); 495 if (tmpb != DHCP_OP_BOOTREPLY) { 496 goto drop; 497 } 498 499 ebuf_get_u8(buf,tmpb); 500 if (tmpb != DHCP_HWTYPE_ETHERNET) { 501 goto drop; 502 } 503 504 ebuf_get_u8(buf,tmpb); 505 if (tmpb != ENET_ADDR_LEN) { 506 goto drop; 507 } 508 509 ebuf_skip(buf,1); /* hops */ 510 511 ebuf_get_u32_be(buf,tmpd); /* check ID */ 512 if (tmpd != id) { 513 goto drop; 514 } 515 516 ebuf_skip(buf,2); /* seconds since boot */ 517 ebuf_skip(buf,2); /* flags */ 518 519 ebuf_get_bytes(buf,ciaddr,IP_ADDR_LEN); 520 ebuf_get_bytes(buf,yiaddr,IP_ADDR_LEN); 521 ebuf_get_bytes(buf,siaddr,IP_ADDR_LEN); 522 ebuf_get_bytes(buf,giaddr,IP_ADDR_LEN); 523 524 ebuf_skip(buf,16); /* hardware address */ 525 hostname = ebuf_ptr(buf); 526 ebuf_skip(buf,64); 527 bootfile = ebuf_ptr(buf); 528 529 ebuf_skip(buf,128); 530 531#ifdef _DEBUG_ 532 xprintf("Client IP: %d.%d.%d.%d\n",ciaddr[0],ciaddr[1],ciaddr[2],ciaddr[3]); 533 xprintf("Your IP: %d.%d.%d.%d\n",yiaddr[0],yiaddr[1],yiaddr[2],yiaddr[3]); 534 xprintf("Server IP: %d.%d.%d.%d\n",siaddr[0],siaddr[1],siaddr[2],siaddr[3]); 535 xprintf("Gateway IP: %d.%d.%d.%d\n",giaddr[0],giaddr[1],giaddr[2],giaddr[3]); 536 xprintf("hostname: %s\n",hostname); 537 xprintf("boot file: %s\n",bootfile); 538#endif 539 540 memcpy(reply->dr_ipaddr,yiaddr,IP_ADDR_LEN); 541 memcpy(reply->dr_gateway,giaddr,IP_ADDR_LEN); 542 memcpy(reply->dr_bootserver,siaddr,IP_ADDR_LEN); 543 if (*hostname) reply->dr_hostname = strdup(hostname); 544 if (*bootfile) reply->dr_bootfile = strdup(bootfile); 545 546 /* 547 * Test for options - look for magic number 548 */ 549 550 ebuf_get_u32_be(buf,tmpd); 551 552 memcpy(reply->dr_dhcpserver,buf->eb_usrptr,IP_ADDR_LEN); 553 554 if (tmpd == DHCP_MAGIC_NUMBER) { 555 uint8_t tag; 556 uint8_t len; 557 558 while (buf->eb_length > 0) { 559 ebuf_get_u8(buf,tag); 560 if (tag == DHCP_TAG_END) break; 561 ebuf_get_u8(buf,len); 562 ebuf_get_bytes(buf,junk,len); 563 564#ifdef _DEBUG_ 565 dhcp_dumptag(tag,len,junk); 566#endif 567 568 switch (tag) { 569 case DHCP_TAG_FUNCTION: 570 fcode = (uint8_t) junk[0]; 571 break; 572 case DHCP_TAG_NETMASK: 573 memcpy(reply->dr_netmask,junk,IP_ADDR_LEN); 574 break; 575 case DHCP_TAG_GATEWAY: 576 memcpy(reply->dr_gateway,junk,IP_ADDR_LEN); 577 break; 578 case DHCP_TAG_NAMESERVER: 579 memcpy(reply->dr_nameserver,junk,IP_ADDR_LEN); 580 break; 581 case DHCP_TAG_DOMAINNAME: 582 junk[len] = 0; 583 if (len) reply->dr_domainname = strdup(junk); 584 break; 585 case DHCP_TAG_SWAPSERVER: 586 junk[len] = 0; 587 if (len) reply->dr_swapserver = strdup(junk); 588 break; 589 case DHCP_TAG_SERVERIDENT: 590 if (len == IP_ADDR_LEN) { 591 memcpy(reply->dr_dhcpserver,junk,len); 592 } 593 break; 594 case DHCP_TAG_ROOTPATH: 595 junk[len] = 0; 596 if (len) reply->dr_rootpath = strdup(junk); 597 break; 598 case DHCP_TAG_SCRIPT: 599 junk[len] = 0; 600 if (len) reply->dr_script = strdup(junk); 601 break; 602 case DHCP_TAG_OPTIONS: 603 junk[len] = 0; 604 if (len) reply->dr_options = strdup(junk); 605 break; 606 } 607 } 608 } 609 610 if (fcode != expfcode) { 611 goto drop; 612 } 613 614 udp_free(buf); 615 nres++; 616 break; 617 618 drop: 619 udp_free(buf); 620 } 621 622 if (nres > 0) return 0; 623 else return CFE_ERR_TIMEOUT; 624} 625 626 627/* ********************************************************************* 628 * dhcp_do_dhcpdiscover(s,hwaddr,reply) 629 * 630 * Request an IP address from the DHCP server. On success, the 631 * dhcpreply_t structure will be filled in 632 * 633 * Input parameters: 634 * s - udp socket 635 * hwaddr - our hardware address 636 * reply - pointer to reply buffer. 637 * 638 * Return value: 639 * 0 if a response was received 640 * else error code 641 ********************************************************************* */ 642 643static int dhcp_do_dhcpdiscover(int s,uint8_t *hwaddr,dhcpreply_t *reply) 644{ 645 ebuf_t *buf; 646 uint32_t id; 647 uint8_t ipaddr[IP_ADDR_LEN]; 648 int res; 649 650 /* 651 * Packet ID is the current time 652 */ 653 654 id = (uint32_t)cfe_ticks; 655 656 /* 657 * Build the DISCOVER request 658 */ 659 660 res = dhcp_build_discover(hwaddr,id,&buf); 661 if (res != 0) return res; 662 663 /* 664 * Send the packet to the IP broadcast (255.255.255.255) 665 */ 666 667 ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF; 668 udp_send(s,buf,ipaddr); 669 670 /* 671 * Wait for a reply 672 */ 673 674 res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_OFFER); 675 676 return res; 677} 678 679 680/* ********************************************************************* 681 * dhcp_do_dhcprequest(s,hwaddr,reply,discover_reply) 682 * 683 * Request an IP address from the DHCP server. On success, the 684 * dhcpreply_t structure will be filled in 685 * 686 * Input parameters: 687 * s - udp socket 688 * hwaddr - our hardware address 689 * reply - pointer to reply buffer. 690 * discover_reply - pointer to previously received DISCOVER data 691 * 692 * Return value: 693 * 0 if a response was received 694 * else error code 695 ********************************************************************* */ 696 697static int dhcp_do_dhcprequest(int s,uint8_t *hwaddr, 698 dhcpreply_t *reply, 699 dhcpreply_t *discover_reply) 700{ 701 ebuf_t *buf; 702 uint32_t id; 703 uint8_t ipaddr[IP_ADDR_LEN]; 704 int res; 705 706 /* 707 * Packet ID is the current time 708 */ 709 710 id = (uint32_t)cfe_ticks; 711 712 /* 713 * Build the DHCP REQUEST request 714 */ 715 716 res = dhcp_build_request(hwaddr, 717 id, 718 discover_reply->dr_dhcpserver, 719 discover_reply->dr_ipaddr, 720 &buf); 721 722 if (res != 0) return res; 723 724 /* 725 * Send the packet to the IP broadcast (255.255.255.255) 726 */ 727 728 ipaddr[0] = 0xFF; ipaddr[1] = 0xFF; ipaddr[2] = 0xFF; ipaddr[3] = 0xFF; 729 udp_send(s,buf,ipaddr); 730 731 /* 732 * Wait for a reply 733 */ 734 735 res = dhcp_wait_reply(s,id,reply,DHCP_FUNCTION_ACK); 736 737 return res; 738} 739 740 741/* ********************************************************************* 742 * dhcp_bootrequest(reply) 743 * 744 * Request an IP address from the DHCP server. On success, the 745 * dhcpreply_t structure will be allocated. 746 * 747 * Input parameters: 748 * reply - pointer to pointer to reply. 749 * 750 * Return value: 751 * 0 if no responses received 752 * >0 for some responses received 753 * else error code 754 ********************************************************************* */ 755 756int dhcp_bootrequest(dhcpreply_t **rep) 757{ 758 uint8_t *hwaddr; 759 int s; 760 dhcpreply_t *discover_reply; 761 dhcpreply_t *request_reply; 762 int nres = 0; 763 int retries; 764 uint32_t id; 765 766 id = (uint32_t) cfe_ticks; 767 768 /* 769 * Start with empty reply buffers. Since we use a portion of the 770 * discover reply in the request, we'll keep two of them. 771 */ 772 773 discover_reply = KMALLOC(sizeof(dhcpreply_t),0); 774 if (discover_reply == NULL) { 775 return CFE_ERR_NOMEM; 776 } 777 memset(discover_reply,0,sizeof(dhcpreply_t)); 778 779 request_reply = KMALLOC(sizeof(dhcpreply_t),0); 780 if (request_reply == NULL) { 781 KFREE(discover_reply); 782 return CFE_ERR_NOMEM; 783 } 784 memset(request_reply,0,sizeof(dhcpreply_t)); 785 786 787 /* 788 * Get our hw addr 789 */ 790 791 hwaddr = net_getparam(NET_HWADDR); 792 if (!hwaddr) { 793 KFREE(discover_reply); 794 KFREE(request_reply); 795 return CFE_ERR_NETDOWN; 796 } 797 798 /* 799 * Open UDP port 800 */ 801 802 s = udp_socket(UDP_PORT_BOOTPS); 803 if (s < 0) { 804 KFREE(discover_reply); 805 KFREE(request_reply); 806 return CFE_ERR_NOHANDLES; 807 } 808 809 udp_bind(s,UDP_PORT_BOOTPC); 810 811 /* 812 * Do the boot request. Start by sending the OFFER message 813 */ 814 815 nres = CFE_ERR_TIMEOUT; 816 for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) { 817 nres = dhcp_do_dhcpdiscover(s,hwaddr,discover_reply); 818 if (nres == 0) break; 819 if (nres == CFE_ERR_TIMEOUT) continue; 820 break; 821 } 822 823 /* 824 * If someone sent us a response, send the REQUEST message 825 * to get a lease. 826 */ 827 828 if (nres == 0) { 829 830 /* 831 * Now, send the REQUEST message and get a response. 832 */ 833 834 for (retries = 0; retries < DHCP_NUM_RETRIES; retries++) { 835 nres = dhcp_do_dhcprequest(s,hwaddr, 836 request_reply, 837 discover_reply); 838 if (nres == 0) break; 839 if (nres == CFE_ERR_TIMEOUT) continue; 840 break; 841 } 842 } 843 844 /* 845 * All done with the discover reply. 846 */ 847 848 dhcp_free_reply(discover_reply); 849 850 /* 851 * All done with UDP 852 */ 853 854 udp_close(s); 855 856 /* 857 * Return the reply info. 858 */ 859 860 if (nres == 0) { 861 *rep = request_reply; 862 } 863 else { 864 *rep = NULL; 865 dhcp_free_reply(request_reply); 866 } 867 868 return nres; 869} 870