Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 363 | johboh | 1 | /********************************************************************* |
| 2 | * |
||
| 3 | * DHCP Module for Microchip TCP/IP Stack |
||
| 4 | * |
||
| 5 | ********************************************************************* |
||
| 6 | * FileName: DHCP.c |
||
| 7 | * Dependencies: StackTsk.h |
||
| 8 | * UDP.h |
||
| 9 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F |
||
| 10 | * Complier: Microchip C18 v3.02 or higher |
||
| 11 | * Microchip C30 v2.01 or higher |
||
| 12 | * Company: Microchip Technology, Inc. |
||
| 13 | * |
||
| 14 | * Software License Agreement |
||
| 15 | * |
||
| 16 | * This software is owned by Microchip Technology Inc. ("Microchip") |
||
| 17 | * and is supplied to you for use exclusively as described in the |
||
| 18 | * associated software agreement. This software is protected by |
||
| 19 | * software and other intellectual property laws. Any use in |
||
| 20 | * violation of the software license may subject the user to criminal |
||
| 21 | * sanctions as well as civil liability. Copyright 2006 Microchip |
||
| 22 | * Technology Inc. All rights reserved. |
||
| 23 | * |
||
| 24 | * This software is provided "AS IS." MICROCHIP DISCLAIMS ALL |
||
| 25 | * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED |
||
| 26 | * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND |
||
| 27 | * INFRINGEMENT. Microchip shall in no event be liable for special, |
||
| 28 | * incidental, or consequential damages. |
||
| 29 | * |
||
| 30 | * |
||
| 31 | * Author Date Comment |
||
| 32 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
| 33 | * Nilesh Rajbharti 3/21/01 Original (Rev 1.0) |
||
| 34 | * Nilesh Rajbharti 7/10/02 Explicitly initialized tempIPAddress |
||
| 35 | * (Rev 2.11) |
||
| 36 | * Nilesh Rajbharti 5/16/03 Increased DHCP_TIMEOUT to 2 seconds. |
||
| 37 | * Nilesh Rajbharti 5/16/03 Fixed SM_DHCP_BROADCAST logic |
||
| 38 | * where UDPPut was called before setting |
||
| 39 | * active socket. |
||
| 40 | * Robert Sloan 5/29/03 Improved DHCP State machine to handle |
||
| 41 | * NAK and renew existing IP address. |
||
| 42 | * Nilesh Rajbharti 8/15/03 Modified _DHCPRecieve() to check for |
||
| 43 | * chaddr field before accpting the packet. |
||
| 44 | * Fixed DHCPTask() where it would not |
||
| 45 | * reply to first OFFER. |
||
| 46 | * Nilesh Rajbharti 3/1/04 Used tickDiff in DHCPTask() "bind" |
||
| 47 | * state to adjust for irregular TICK_SECOND |
||
| 48 | * Without this logic, actual lease time count |
||
| 49 | * down may be incorrect. |
||
| 50 | * Howard Schlunder 5/11/06 Fixed tickDiff usage, reducing |
||
| 51 | * accumulated timing error. Fixed DHCP |
||
| 52 | * state machine requesting IP 0.0.0.0 |
||
| 53 | * after lease expiration. |
||
| 54 | * Howard Schlunder 6/01/06 Added DHCPState.bits.bOfferReceived flag to |
||
| 55 | * allow operation on networks with multiple |
||
| 56 | * DHCP servers offering multiple addresses |
||
| 57 | * Howard Schlunder 8/01/06 Added DNS server option to DHCP request, |
||
| 58 | * untested Host Name option to DHCP request |
||
| 59 | ********************************************************************/ |
||
| 60 | #define THIS_IS_DHCP |
||
| 61 | |||
| 62 | #include "..\Include\StackTsk.h" |
||
| 63 | |||
| 64 | #if defined(STACK_USE_DHCP) |
||
| 65 | |||
| 66 | #include "..\Include\DHCP.h" |
||
| 67 | #include "..\Include\UDP.h" |
||
| 68 | #include "..\Include\Tick.h" |
||
| 69 | |||
| 70 | |||
| 71 | #if defined(STACK_USE_SLIP) |
||
| 72 | #error DHCP module is not available when SLIP is used. |
||
| 73 | #endif |
||
| 74 | |||
| 75 | |||
| 76 | #define DHCP_TIMEOUT (TICK)(2L * TICK_SECOND) |
||
| 77 | |||
| 78 | |||
| 79 | #define DHCP_CLIENT_PORT (68u) |
||
| 80 | #define DHCP_SERVER_PORT (67u) |
||
| 81 | |||
| 82 | #define BOOT_REQUEST (1u) |
||
| 83 | #define BOOT_REPLY (2u) |
||
| 84 | #define HW_TYPE (1u) |
||
| 85 | #define LEN_OF_HW_TYPE (6u) |
||
| 86 | |||
| 87 | #define DHCP_MESSAGE_TYPE (53u) |
||
| 88 | #define DHCP_MESSAGE_TYPE_LEN (1u) |
||
| 89 | |||
| 90 | #define DHCP_UNKNOWN_MESSAGE (0u) |
||
| 91 | |||
| 92 | #define DHCP_DISCOVER_MESSAGE (1u) |
||
| 93 | #define DHCP_OFFER_MESSAGE (2u) |
||
| 94 | #define DHCP_REQUEST_MESSAGE (3u) |
||
| 95 | #define DHCP_DECLINE_MESSAGE (4u) |
||
| 96 | #define DHCP_ACK_MESSAGE (5u) |
||
| 97 | #define DHCP_NAK_MESSAGE (6u) |
||
| 98 | #define DHCP_RELEASE_MESSAGE (7u) |
||
| 99 | |||
| 100 | #define DHCP_SERVER_IDENTIFIER (54u) |
||
| 101 | #define DHCP_SERVER_IDENTIFIER_LEN (4u) |
||
| 102 | |||
| 103 | #define DHCP_PARAM_REQUEST_LIST (55u) |
||
| 104 | #define DHCP_PARAM_REQUEST_LIST_LEN (4u) |
||
| 105 | #define DHCP_PARAM_REQUEST_IP_ADDRESS (50u) |
||
| 106 | #define DHCP_PARAM_REQUEST_IP_ADDRESS_LEN (4u) |
||
| 107 | #define DHCP_SUBNET_MASK (1u) |
||
| 108 | #define DHCP_ROUTER (3u) |
||
| 109 | #define DHCP_DNS (6u) |
||
| 110 | #define DHCP_HOST_NAME (12u) |
||
| 111 | #define DHCP_IP_LEASE_TIME (51u) |
||
| 112 | #define DHCP_END_OPTION (255u) |
||
| 113 | |||
| 114 | #define HALF_HOUR (WORD)((WORD)60 * (WORD)30) |
||
| 115 | |||
| 116 | SM_DHCP smDHCPState = SM_DHCP_INIT_FIRST_TIME; |
||
| 117 | static UDP_SOCKET DHCPSocket = INVALID_UDP_SOCKET; |
||
| 118 | |||
| 119 | |||
| 120 | DHCP_STATE DHCPState = { 0x00 }; |
||
| 121 | |||
| 122 | static DWORD_VAL DHCPServerID; |
||
| 123 | static DWORD_VAL DHCPLeaseTime; |
||
| 124 | |||
| 125 | static IP_ADDR tempIPAddress; |
||
| 126 | static IP_ADDR tempGateway; |
||
| 127 | static IP_ADDR tempMask; |
||
| 128 | #if defined(STACK_USE_DNS) |
||
| 129 | static IP_ADDR tempDNS; |
||
| 130 | #endif |
||
| 131 | //static BYTE tempHostName[16]; |
||
| 132 | |||
| 133 | static union |
||
| 134 | { |
||
| 135 | struct |
||
| 136 | { |
||
| 137 | char IPAddress:1; |
||
| 138 | char Gateway:1; |
||
| 139 | char Mask:1; |
||
| 140 | char DNS:1; |
||
| 141 | char HostName:1; |
||
| 142 | } bits; |
||
| 143 | BYTE Val; |
||
| 144 | } ValidValues; |
||
| 145 | |||
| 146 | static BYTE _DHCPReceive(void); |
||
| 147 | static void _DHCPSend(BYTE messageType); |
||
| 148 | |||
| 149 | BYTE DHCPBindCount = 0; |
||
| 150 | |||
| 151 | // Uncomment following line if DHCP transactions are to be displayed on |
||
| 152 | // RS-232 - for debug purpose only. |
||
| 153 | //#define DHCP_DEBUG_MODE |
||
| 154 | |||
| 155 | #if defined(DHCP_DEBUG_MODE) |
||
| 156 | static USARTPut(BYTE c) |
||
| 157 | { |
||
| 158 | while( !TXSTA_TRMT); |
||
| 159 | TXREG = c; |
||
| 160 | } |
||
| 161 | #else |
||
| 162 | |||
| 163 | #define USARTPut(a) |
||
| 164 | |||
| 165 | #endif |
||
| 166 | |||
| 167 | |||
| 168 | void DHCPReset(void) |
||
| 169 | { |
||
| 170 | // Do not reset DHCP if it was previously disabled. |
||
| 171 | if ( smDHCPState == SM_DHCP_DISABLED ) |
||
| 172 | return; |
||
| 173 | |||
| 174 | if ( DHCPSocket != INVALID_UDP_SOCKET ) |
||
| 175 | UDPClose(DHCPSocket); |
||
| 176 | DHCPSocket = INVALID_UDP_SOCKET; |
||
| 177 | |||
| 178 | smDHCPState = SM_DHCP_INIT_FIRST_TIME; |
||
| 179 | DHCPBindCount = 0; |
||
| 180 | |||
| 181 | DHCPState.bits.bIsBound = FALSE; |
||
| 182 | } |
||
| 183 | |||
| 184 | /********************************************************************* |
||
| 185 | * Function: void DHCPTask(void) |
||
| 186 | * |
||
| 187 | * PreCondition: DHCPInit() is already called AND |
||
| 188 | * IPGetHeader() is called with |
||
| 189 | * IPFrameType == IP_PROT_UDP |
||
| 190 | * |
||
| 191 | * Input: None |
||
| 192 | * |
||
| 193 | * Output: None |
||
| 194 | * |
||
| 195 | * Side Effects: None |
||
| 196 | * |
||
| 197 | * Overview: Fetches pending UDP packet from MAC receive buffer |
||
| 198 | * and dispatches it appropriate UDP socket. |
||
| 199 | * If not UDP socket is matched, UDP packet is |
||
| 200 | * silently discarded. |
||
| 201 | * |
||
| 202 | * Note: Caller must make sure that MAC receive buffer |
||
| 203 | * access pointer is set to begining of UDP packet. |
||
| 204 | * Required steps before calling this function is: |
||
| 205 | * |
||
| 206 | * If ( MACIsRxReady() ) |
||
| 207 | * { |
||
| 208 | * MACGetHeader() |
||
| 209 | * If MACFrameType == IP |
||
| 210 | * IPGetHeader() |
||
| 211 | * if ( IPFrameType == IP_PROT_UDP ) |
||
| 212 | * Call DHCPTask() |
||
| 213 | * ... |
||
| 214 | ********************************************************************/ |
||
| 215 | void DHCPTask(void) |
||
| 216 | { |
||
| 217 | NODE_INFO DHCPServerNode; |
||
| 218 | static TICK lastTryTick; |
||
| 219 | BYTE DHCPRecvReturnValue; |
||
| 220 | TICK tickDiff; |
||
| 221 | |||
| 222 | switch(smDHCPState) |
||
| 223 | { |
||
| 224 | case SM_DHCP_INIT_FIRST_TIME: |
||
| 225 | tempIPAddress.Val = 0x0; |
||
| 226 | // smDHCPState = SM_DHCP_INIT; // State automatically changes |
||
| 227 | /* No break */ |
||
| 228 | |||
| 229 | case SM_DHCP_INIT: |
||
| 230 | DHCPServerNode.MACAddr.v[0] = 0xff; |
||
| 231 | DHCPServerNode.MACAddr.v[1] = 0xff; |
||
| 232 | DHCPServerNode.MACAddr.v[2] = 0xff; |
||
| 233 | DHCPServerNode.MACAddr.v[3] = 0xff; |
||
| 234 | DHCPServerNode.MACAddr.v[4] = 0xff; |
||
| 235 | DHCPServerNode.MACAddr.v[5] = 0xff; |
||
| 236 | DHCPServerNode.IPAddr.Val = 0xffffffff; |
||
| 237 | DHCPSocket = UDPOpen(DHCP_CLIENT_PORT, |
||
| 238 | &DHCPServerNode, |
||
| 239 | DHCP_SERVER_PORT); |
||
| 240 | lastTryTick = TickGet(); |
||
| 241 | smDHCPState = SM_DHCP_RESET_WAIT; |
||
| 242 | /* No break */ |
||
| 243 | |||
| 244 | case SM_DHCP_RESET_WAIT: |
||
| 245 | if ( TickGetDiff(TickGet(), lastTryTick) >= (TICK_SECOND/(TICK)5) ) |
||
| 246 | smDHCPState = SM_DHCP_BROADCAST; |
||
| 247 | break; |
||
| 248 | |||
| 249 | case SM_DHCP_BROADCAST: |
||
| 250 | // Assume default IP Lease time of 60 seconds. |
||
| 251 | // This should be minimum possible to make sure that if |
||
| 252 | // server did not specify lease time, we try again after this minimum time. |
||
| 253 | DHCPLeaseTime.Val = 60; |
||
| 254 | |||
| 255 | // If we have already obtained some IP address, renew it. |
||
| 256 | if(DHCPState.bits.bIsBound) |
||
| 257 | { |
||
| 258 | smDHCPState = SM_DHCP_REQUEST; |
||
| 259 | } |
||
| 260 | else if ( UDPIsPutReady(DHCPSocket) ) |
||
| 261 | { |
||
| 262 | // To minimize code requirement, user must make sure that |
||
| 263 | // above call will be successful by making at least one |
||
| 264 | // UDP socket available. |
||
| 265 | // Usually this will be the case, given that DHCP will be |
||
| 266 | // the first one to use UDP socket. |
||
| 267 | // Also, we will not check for transmitter readiness, |
||
| 268 | // we assume it to be ready. |
||
| 269 | _DHCPSend(DHCP_DISCOVER_MESSAGE); |
||
| 270 | ValidValues.Val = 0x00; |
||
| 271 | |||
| 272 | // DEBUG |
||
| 273 | USARTPut('\n'); |
||
| 274 | USARTPut('\r'); |
||
| 275 | USARTPut('D'); |
||
| 276 | |||
| 277 | lastTryTick = TickGet(); |
||
| 278 | smDHCPState = SM_DHCP_DISCOVER; |
||
| 279 | } |
||
| 280 | |||
| 281 | break; |
||
| 282 | |||
| 283 | |||
| 284 | case SM_DHCP_DISCOVER: |
||
| 285 | if ( TickGetDiff(TickGet(), lastTryTick) >= DHCP_TIMEOUT ) |
||
| 286 | { |
||
| 287 | smDHCPState = SM_DHCP_BROADCAST; |
||
| 288 | //return; |
||
| 289 | } |
||
| 290 | |||
| 291 | if ( UDPIsGetReady(DHCPSocket) ) |
||
| 292 | { |
||
| 293 | // DEBUG |
||
| 294 | USARTPut('R'); |
||
| 295 | |||
| 296 | if ( _DHCPReceive() == DHCP_OFFER_MESSAGE ) |
||
| 297 | { |
||
| 298 | // DEBUG |
||
| 299 | USARTPut('O'); |
||
| 300 | |||
| 301 | smDHCPState = SM_DHCP_REQUEST; |
||
| 302 | } |
||
| 303 | else |
||
| 304 | break; |
||
| 305 | } |
||
| 306 | else |
||
| 307 | break; |
||
| 308 | |||
| 309 | |||
| 310 | |||
| 311 | case SM_DHCP_REQUEST: |
||
| 312 | if ( UDPIsPutReady(DHCPSocket) ) |
||
| 313 | { |
||
| 314 | _DHCPSend(DHCP_REQUEST_MESSAGE); |
||
| 315 | |||
| 316 | lastTryTick = TickGet(); |
||
| 317 | smDHCPState = SM_DHCP_BIND; |
||
| 318 | } |
||
| 319 | break; |
||
| 320 | |||
| 321 | case SM_DHCP_BIND: |
||
| 322 | if ( UDPIsGetReady(DHCPSocket) ) |
||
| 323 | { |
||
| 324 | DHCPRecvReturnValue = _DHCPReceive(); |
||
| 325 | if ( DHCPRecvReturnValue == DHCP_NAK_MESSAGE ) |
||
| 326 | { |
||
| 327 | // (RSS) NAK recieved. DHCP server didn't like our DHCP Request (format wrong/IP address allocated to someone else/outside IP pool) |
||
| 328 | USARTPut('n'); |
||
| 329 | DHCPReset(); // Start all over again |
||
| 330 | return; |
||
| 331 | } |
||
| 332 | else if ( DHCPRecvReturnValue == DHCP_ACK_MESSAGE ) |
||
| 333 | { |
||
| 334 | // DEBUG |
||
| 335 | USARTPut('B'); |
||
| 336 | |||
| 337 | // Once DCHP is successful, release the UDP socket |
||
| 338 | // This will ensure that UDP layer discards any further DHCP related packets. |
||
| 339 | UDPClose(DHCPSocket); |
||
| 340 | DHCPSocket = INVALID_UDP_SOCKET; |
||
| 341 | |||
| 342 | lastTryTick = TickGet(); |
||
| 343 | smDHCPState = SM_DHCP_BOUND; |
||
| 344 | |||
| 345 | if(ValidValues.bits.IPAddress) |
||
| 346 | AppConfig.MyIPAddr = tempIPAddress; |
||
| 347 | if(ValidValues.bits.Mask) |
||
| 348 | AppConfig.MyMask = tempMask; |
||
| 349 | if(ValidValues.bits.Gateway) |
||
| 350 | AppConfig.MyGateway = tempGateway; |
||
| 351 | #if defined(STACK_USE_DNS) |
||
| 352 | if(ValidValues.bits.DNS) |
||
| 353 | AppConfig.PrimaryDNSServer = tempDNS; |
||
| 354 | #endif |
||
| 355 | // if(ValidValues.bits.HostName) |
||
| 356 | // memcpy(AppConfig.NetBIOSName, (void*)tempHostName, sizeof(AppConfig.NetBIOSName)); |
||
| 357 | |||
| 358 | DHCPState.bits.bIsBound = TRUE; |
||
| 359 | |||
| 360 | DHCPBindCount++; |
||
| 361 | |||
| 362 | return; |
||
| 363 | } |
||
| 364 | } |
||
| 365 | else if ( TickGetDiff(TickGet(), lastTryTick) >= DHCP_TIMEOUT ) |
||
| 366 | { |
||
| 367 | USARTPut('t'); |
||
| 368 | smDHCPState = SM_DHCP_BROADCAST; |
||
| 369 | } |
||
| 370 | break; |
||
| 371 | |||
| 372 | case SM_DHCP_BOUND: |
||
| 373 | // Keep track of how long we use this IP configuration. |
||
| 374 | // When lease period expires, renew the configuration. |
||
| 375 | tickDiff = TickGetDiff(TickGet(), lastTryTick); |
||
| 376 | |||
| 377 | if(tickDiff >= TICK_SECOND) |
||
| 378 | { |
||
| 379 | do |
||
| 380 | { |
||
| 381 | DHCPLeaseTime.Val--; |
||
| 382 | tickDiff -= TICK_SECOND; |
||
| 383 | if(DHCPLeaseTime.Val == 0u) |
||
| 384 | smDHCPState = SM_DHCP_INIT; |
||
| 385 | } while(tickDiff >= TICK_SECOND); |
||
| 386 | lastTryTick = TickGet() - tickDiff; |
||
| 387 | } |
||
| 388 | } |
||
| 389 | } |
||
| 390 | |||
| 391 | |||
| 392 | |||
| 393 | /********************************************************************* |
||
| 394 | DHCP PACKET FORMAT AS PER RFC 1541 |
||
| 395 | |||
| 396 | |||
| 397 | |||
| 398 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
| 399 | | op (1) | htype (1) | hlen (1) | hops (1) | |
||
| 400 | +---------------+---------------+---------------+---------------+ |
||
| 401 | | xid (4) | |
||
| 402 | +-------------------------------+-------------------------------+ |
||
| 403 | | secs (2) | flags (2) | |
||
| 404 | +-------------------------------+-------------------------------+ |
||
| 405 | | ciaddr (4) | |
||
| 406 | +---------------------------------------------------------------+ |
||
| 407 | | yiaddr (4) | |
||
| 408 | +---------------------------------------------------------------+ |
||
| 409 | | siaddr (4) | |
||
| 410 | +---------------------------------------------------------------+ |
||
| 411 | | giaddr (4) | |
||
| 412 | +---------------------------------------------------------------+ |
||
| 413 | | | |
||
| 414 | | chaddr (16) | |
||
| 415 | | | |
||
| 416 | | | |
||
| 417 | +---------------------------------------------------------------+ |
||
| 418 | | | |
||
| 419 | | sname (64) | |
||
| 420 | +---------------------------------------------------------------+ |
||
| 421 | | | |
||
| 422 | | file (128) | |
||
| 423 | +---------------------------------------------------------------+ |
||
| 424 | | | |
||
| 425 | | options (312) | |
||
| 426 | +---------------------------------------------------------------+ |
||
| 427 | |||
| 428 | ********************************************************************/ |
||
| 429 | static BYTE _DHCPReceive(void) |
||
| 430 | { |
||
| 431 | BYTE v; |
||
| 432 | BYTE i, j; |
||
| 433 | BYTE type; |
||
| 434 | BOOL lbDone; |
||
| 435 | DWORD_VAL tempServerID; |
||
| 436 | |||
| 437 | |||
| 438 | // Assume unknown message until proven otherwise. |
||
| 439 | type = DHCP_UNKNOWN_MESSAGE; |
||
| 440 | |||
| 441 | UDPGet(&v); // op |
||
| 442 | |||
| 443 | // Make sure this is BOOT_REPLY. |
||
| 444 | if ( v == BOOT_REPLY ) |
||
| 445 | { |
||
| 446 | // Discard htype, hlen, hops, xid, secs, flags, ciaddr. |
||
| 447 | for ( i = 0; i < 15u; i++ ) |
||
| 448 | UDPGet(&v); |
||
| 449 | |||
| 450 | // Check to see if this is the first offer |
||
| 451 | if(DHCPState.bits.bOfferReceived) |
||
| 452 | { |
||
| 453 | // Discard offered IP address, we already have an offer |
||
| 454 | for ( i = 0; i < 4u; i++ ) |
||
| 455 | UDPGet(&v); |
||
| 456 | } |
||
| 457 | else |
||
| 458 | { |
||
| 459 | // Save offered IP address until we know for sure that we have it. |
||
| 460 | UDPGet(&tempIPAddress.v[0]); |
||
| 461 | UDPGet(&tempIPAddress.v[1]); |
||
| 462 | UDPGet(&tempIPAddress.v[2]); |
||
| 463 | UDPGet(&tempIPAddress.v[3]); |
||
| 464 | ValidValues.bits.IPAddress = 1; |
||
| 465 | } |
||
| 466 | |||
| 467 | // Ignore siaddr, giaddr |
||
| 468 | for ( i = 0; i < 8u; i++ ) |
||
| 469 | UDPGet(&v); |
||
| 470 | |||
| 471 | // Check to see if chaddr (Client Hardware Address) belongs to us. |
||
| 472 | for ( i = 0; i < 6u; i++ ) |
||
| 473 | { |
||
| 474 | UDPGet(&v); |
||
| 475 | if ( v != AppConfig.MyMACAddr.v[i]) |
||
| 476 | goto UDPInvalid; |
||
| 477 | } |
||
| 478 | |||
| 479 | |||
| 480 | // Ignore part of chaddr, sname, file, magic cookie. |
||
| 481 | for ( i = 0; i < 206u; i++ ) |
||
| 482 | UDPGet(&v); |
||
| 483 | |||
| 484 | lbDone = FALSE; |
||
| 485 | do |
||
| 486 | { |
||
| 487 | // Get the Option number |
||
| 488 | // Break out eventually in case if this is a malformed |
||
| 489 | // DHCP message, ie: missing DHCP_END_OPTION marker |
||
| 490 | if(!UDPGet(&v)) |
||
| 491 | { |
||
| 492 | lbDone = TRUE; |
||
| 493 | break; |
||
| 494 | } |
||
| 495 | |||
| 496 | switch(v) |
||
| 497 | { |
||
| 498 | case DHCP_MESSAGE_TYPE: |
||
| 499 | UDPGet(&v); // Skip len |
||
| 500 | // Len must be 1. |
||
| 501 | if ( v == 1u ) |
||
| 502 | { |
||
| 503 | UDPGet(&type); // Get type |
||
| 504 | |||
| 505 | // Throw away the packet if we know we don't need it (ie: another offer when we already have one) |
||
| 506 | if(DHCPState.bits.bOfferReceived && (type == DHCP_OFFER_MESSAGE)) |
||
| 507 | { |
||
| 508 | goto UDPInvalid; |
||
| 509 | } |
||
| 510 | } |
||
| 511 | else |
||
| 512 | goto UDPInvalid; |
||
| 513 | break; |
||
| 514 | |||
| 515 | case DHCP_SUBNET_MASK: |
||
| 516 | UDPGet(&v); // Skip len |
||
| 517 | // Len must be 4. |
||
| 518 | if ( v == 4u ) |
||
| 519 | { |
||
| 520 | // Check to see if this is the first offer |
||
| 521 | if(DHCPState.bits.bOfferReceived) |
||
| 522 | { |
||
| 523 | // Discard offered IP mask, we already have an offer |
||
| 524 | for ( i = 0; i < 4u; i++ ) |
||
| 525 | UDPGet(&v); |
||
| 526 | } |
||
| 527 | else |
||
| 528 | { |
||
| 529 | UDPGet(&tempMask.v[0]); |
||
| 530 | UDPGet(&tempMask.v[1]); |
||
| 531 | UDPGet(&tempMask.v[2]); |
||
| 532 | UDPGet(&tempMask.v[3]); |
||
| 533 | ValidValues.bits.Mask = 1; |
||
| 534 | } |
||
| 535 | } |
||
| 536 | else |
||
| 537 | goto UDPInvalid; |
||
| 538 | break; |
||
| 539 | |||
| 540 | case DHCP_ROUTER: |
||
| 541 | UDPGet(&j); |
||
| 542 | // Len must be >= 4. |
||
| 543 | if ( j >= 4u ) |
||
| 544 | { |
||
| 545 | // Check to see if this is the first offer |
||
| 546 | if(DHCPState.bits.bOfferReceived) |
||
| 547 | { |
||
| 548 | // Discard offered Gateway address, we already have an offer |
||
| 549 | for ( i = 0; i < 4u; i++ ) |
||
| 550 | UDPGet(&v); |
||
| 551 | } |
||
| 552 | else |
||
| 553 | { |
||
| 554 | UDPGet(&tempGateway.v[0]); |
||
| 555 | UDPGet(&tempGateway.v[1]); |
||
| 556 | UDPGet(&tempGateway.v[2]); |
||
| 557 | UDPGet(&tempGateway.v[3]); |
||
| 558 | ValidValues.bits.Gateway = 1; |
||
| 559 | } |
||
| 560 | } |
||
| 561 | else |
||
| 562 | goto UDPInvalid; |
||
| 563 | |||
| 564 | // Discard any other router addresses. |
||
| 565 | j -= 4; |
||
| 566 | while(j--) |
||
| 567 | UDPGet(&v); |
||
| 568 | break; |
||
| 569 | |||
| 570 | #if defined(STACK_USE_DNS) |
||
| 571 | case DHCP_DNS: |
||
| 572 | UDPGet(&j); |
||
| 573 | // Len must be >= 4. |
||
| 574 | if ( j >= 4u ) |
||
| 575 | { |
||
| 576 | // Check to see if this is the first offer |
||
| 577 | if(DHCPState.bits.bOfferReceived) |
||
| 578 | { |
||
| 579 | // Discard offered DNS server address, we already have an offer |
||
| 580 | for ( i = 0; i < 4u; i++ ) |
||
| 581 | UDPGet(&v); |
||
| 582 | } |
||
| 583 | else |
||
| 584 | { |
||
| 585 | UDPGet(&tempDNS.v[0]); |
||
| 586 | UDPGet(&tempDNS.v[1]); |
||
| 587 | UDPGet(&tempDNS.v[2]); |
||
| 588 | UDPGet(&tempDNS.v[3]); |
||
| 589 | ValidValues.bits.DNS = 1; |
||
| 590 | } |
||
| 591 | } |
||
| 592 | else |
||
| 593 | goto UDPInvalid; |
||
| 594 | |||
| 595 | // Discard any other DNS server addresses |
||
| 596 | j -= 4; |
||
| 597 | while(j--) |
||
| 598 | UDPGet(&v); |
||
| 599 | break; |
||
| 600 | #endif |
||
| 601 | |||
| 602 | // case DHCP_HOST_NAME: |
||
| 603 | // UDPGet(&j); |
||
| 604 | // // Len must be >= 4. |
||
| 605 | // if(j < 1u) |
||
| 606 | // goto UDPInvalid; |
||
| 607 | // |
||
| 608 | // // Check to see if this is the first offer |
||
| 609 | // if(DHCPState.bits.bOfferReceived) |
||
| 610 | // { |
||
| 611 | // // Discard offered host name, we already have an offer |
||
| 612 | // while(j--) |
||
| 613 | // UDPGet(&v); |
||
| 614 | // } |
||
| 615 | // else |
||
| 616 | // { |
||
| 617 | // for(i = 0; j, i < sizeof(tempHostName); i++, j--) |
||
| 618 | // { |
||
| 619 | // UDPGet(&tempHostName[i]); |
||
| 620 | // } |
||
| 621 | // while(j--) |
||
| 622 | // { |
||
| 623 | // UDPGet(&v); |
||
| 624 | // } |
||
| 625 | // ValidValues.bits.HostName = 1; |
||
| 626 | // } |
||
| 627 | // |
||
| 628 | // break; |
||
| 629 | |||
| 630 | case DHCP_SERVER_IDENTIFIER: |
||
| 631 | UDPGet(&v); // Get len |
||
| 632 | // Len must be 4. |
||
| 633 | if ( v == 4u ) |
||
| 634 | { |
||
| 635 | UDPGet(&tempServerID.v[3]); // Get the id |
||
| 636 | UDPGet(&tempServerID.v[2]); |
||
| 637 | UDPGet(&tempServerID.v[1]); |
||
| 638 | UDPGet(&tempServerID.v[0]); |
||
| 639 | } |
||
| 640 | else |
||
| 641 | goto UDPInvalid; |
||
| 642 | break; |
||
| 643 | |||
| 644 | case DHCP_END_OPTION: |
||
| 645 | lbDone = TRUE; |
||
| 646 | break; |
||
| 647 | |||
| 648 | case DHCP_IP_LEASE_TIME: |
||
| 649 | UDPGet(&v); // Get len |
||
| 650 | // Len must be 4. |
||
| 651 | if ( v == 4u ) |
||
| 652 | { |
||
| 653 | // Check to see if this is the first offer |
||
| 654 | if(DHCPState.bits.bOfferReceived) |
||
| 655 | { |
||
| 656 | // Discard offered lease time, we already have an offer |
||
| 657 | for ( i = 0; i < 4u; i++ ) |
||
| 658 | UDPGet(&v); |
||
| 659 | } |
||
| 660 | else |
||
| 661 | { |
||
| 662 | UDPGet(&DHCPLeaseTime.v[3]); |
||
| 663 | UDPGet(&DHCPLeaseTime.v[2]); |
||
| 664 | UDPGet(&DHCPLeaseTime.v[1]); |
||
| 665 | UDPGet(&DHCPLeaseTime.v[0]); |
||
| 666 | |||
| 667 | // Due to possible timing delays, consider actual lease |
||
| 668 | // time less by half hour. |
||
| 669 | if ( DHCPLeaseTime.Val > HALF_HOUR ) |
||
| 670 | DHCPLeaseTime.Val = DHCPLeaseTime.Val - HALF_HOUR; |
||
| 671 | } |
||
| 672 | } |
||
| 673 | else |
||
| 674 | goto UDPInvalid; |
||
| 675 | break; |
||
| 676 | |||
| 677 | default: |
||
| 678 | // Ignore all unsupport tags. |
||
| 679 | UDPGet(&j); // Get option len |
||
| 680 | while( j-- ) // Ignore option values |
||
| 681 | UDPGet(&v); |
||
| 682 | } |
||
| 683 | } while( !lbDone ); |
||
| 684 | } |
||
| 685 | |||
| 686 | // If this is an OFFER message, remember current server id. |
||
| 687 | if ( type == DHCP_OFFER_MESSAGE ) |
||
| 688 | { |
||
| 689 | DHCPServerID.Val = tempServerID.Val; |
||
| 690 | DHCPState.bits.bOfferReceived = TRUE; |
||
| 691 | } |
||
| 692 | else |
||
| 693 | { |
||
| 694 | // For other types of messages, make sure that received |
||
| 695 | // server id matches with our previous one. |
||
| 696 | if ( DHCPServerID.Val != tempServerID.Val ) |
||
| 697 | type = DHCP_UNKNOWN_MESSAGE; |
||
| 698 | } |
||
| 699 | |||
| 700 | UDPDiscard(); // We are done with this packet |
||
| 701 | return type; |
||
| 702 | |||
| 703 | UDPInvalid: |
||
| 704 | UDPDiscard(); |
||
| 705 | return DHCP_UNKNOWN_MESSAGE; |
||
| 706 | |||
| 707 | } |
||
| 708 | |||
| 709 | |||
| 710 | |||
| 711 | |||
| 712 | |||
| 713 | static void _DHCPSend(BYTE messageType) |
||
| 714 | { |
||
| 715 | BYTE i; |
||
| 716 | |||
| 717 | |||
| 718 | UDPPut(BOOT_REQUEST); // op |
||
| 719 | UDPPut(HW_TYPE); // htype |
||
| 720 | UDPPut(LEN_OF_HW_TYPE); // hlen |
||
| 721 | UDPPut(0); // hops |
||
| 722 | UDPPut(0x12); // xid[0] |
||
| 723 | UDPPut(0x23); // xid[1] |
||
| 724 | UDPPut(0x34); // xid[2] |
||
| 725 | UDPPut(0x56); // xid[3] |
||
| 726 | UDPPut(0); // secs[0] |
||
| 727 | UDPPut(0); // secs[1] |
||
| 728 | UDPPut(0x80); // flags[0] with BF set |
||
| 729 | UDPPut(0); // flags[1] |
||
| 730 | |||
| 731 | // If this is DHCP REQUEST message, use previously allocated IP address. |
||
| 732 | #if 0 |
||
| 733 | if ( messageType == DHCP_REQUEST_MESSAGE ) |
||
| 734 | { |
||
| 735 | UDPPut(tempIPAddress.v[0]); |
||
| 736 | UDPPut(tempIPAddress.v[1]); |
||
| 737 | UDPPut(tempIPAddress.v[2]); |
||
| 738 | UDPPut(tempIPAddress.v[3]); |
||
| 739 | } |
||
| 740 | else |
||
| 741 | #endif |
||
| 742 | { |
||
| 743 | UDPPut(0x00); |
||
| 744 | UDPPut(0x00); |
||
| 745 | UDPPut(0x00); |
||
| 746 | UDPPut(0x00); |
||
| 747 | } |
||
| 748 | |||
| 749 | // Set yiaddr, siaddr, giaddr as zeros, |
||
| 750 | for ( i = 0; i < 12u; i++ ) |
||
| 751 | UDPPut(0x00); |
||
| 752 | |||
| 753 | // Load chaddr - Client hardware address. |
||
| 754 | UDPPut(AppConfig.MyMACAddr.v[0]); |
||
| 755 | UDPPut(AppConfig.MyMACAddr.v[1]); |
||
| 756 | UDPPut(AppConfig.MyMACAddr.v[2]); |
||
| 757 | UDPPut(AppConfig.MyMACAddr.v[3]); |
||
| 758 | UDPPut(AppConfig.MyMACAddr.v[4]); |
||
| 759 | UDPPut(AppConfig.MyMACAddr.v[5]); |
||
| 760 | |||
| 761 | // Set chaddr[6..15], sname and file as zeros. |
||
| 762 | for ( i = 0; i < 202u; i++ ) |
||
| 763 | UDPPut(0); |
||
| 764 | |||
| 765 | // Load magic cookie as per RFC 1533. |
||
| 766 | UDPPut(99); |
||
| 767 | UDPPut(130); |
||
| 768 | UDPPut(83); |
||
| 769 | UDPPut(99); |
||
| 770 | |||
| 771 | // Load message type. |
||
| 772 | UDPPut(DHCP_MESSAGE_TYPE); |
||
| 773 | UDPPut(DHCP_MESSAGE_TYPE_LEN); |
||
| 774 | UDPPut(messageType); |
||
| 775 | |||
| 776 | if(messageType == DHCP_DISCOVER_MESSAGE) |
||
| 777 | { |
||
| 778 | // Reset offered flag so we know to act upon the next valid offer |
||
| 779 | DHCPState.bits.bOfferReceived = FALSE; |
||
| 780 | } |
||
| 781 | |||
| 782 | |||
| 783 | if ( messageType != DHCP_DISCOVER_MESSAGE && tempIPAddress.Val != 0x0000u ) |
||
| 784 | { |
||
| 785 | // DHCP REQUEST message may include server identifier, |
||
| 786 | // to identify the server we are talking to. |
||
| 787 | // DHCP ACK may include it too. To simplify logic, |
||
| 788 | // we will include server identifier in DHCP ACK message too. |
||
| 789 | // _DHCPReceive() would populate "serverID" when it |
||
| 790 | // receives DHCP OFFER message. We will simply use that |
||
| 791 | // when we are replying to server. |
||
| 792 | // If this is a renwal request, do not include server id. |
||
| 793 | UDPPut(DHCP_SERVER_IDENTIFIER); |
||
| 794 | UDPPut(DHCP_SERVER_IDENTIFIER_LEN); |
||
| 795 | UDPPut(DHCPServerID.v[3]); |
||
| 796 | UDPPut(DHCPServerID.v[2]); |
||
| 797 | UDPPut(DHCPServerID.v[1]); |
||
| 798 | UDPPut(DHCPServerID.v[0]); |
||
| 799 | } |
||
| 800 | |||
| 801 | // Load our interested parameters |
||
| 802 | // This is hardcoded list. If any new parameters are desired, |
||
| 803 | // new lines must be added here. |
||
| 804 | UDPPut(DHCP_PARAM_REQUEST_LIST); |
||
| 805 | UDPPut(DHCP_PARAM_REQUEST_LIST_LEN); |
||
| 806 | UDPPut(DHCP_SUBNET_MASK); |
||
| 807 | UDPPut(DHCP_ROUTER); |
||
| 808 | UDPPut(DHCP_DNS); |
||
| 809 | UDPPut(DHCP_HOST_NAME); |
||
| 810 | |||
| 811 | // Add requested IP address to DHCP Request Message |
||
| 812 | if ( messageType == DHCP_REQUEST_MESSAGE ) |
||
| 813 | { |
||
| 814 | UDPPut(DHCP_PARAM_REQUEST_IP_ADDRESS); |
||
| 815 | UDPPut(DHCP_PARAM_REQUEST_IP_ADDRESS_LEN); |
||
| 816 | |||
| 817 | UDPPut(tempIPAddress.v[0]); |
||
| 818 | UDPPut(tempIPAddress.v[1]); |
||
| 819 | UDPPut(tempIPAddress.v[2]); |
||
| 820 | UDPPut(tempIPAddress.v[3]); |
||
| 821 | } |
||
| 822 | |||
| 823 | // Add any new paramter request here. |
||
| 824 | |||
| 825 | // End of Options. |
||
| 826 | UDPPut(DHCP_END_OPTION); |
||
| 827 | |||
| 828 | UDPFlush(); |
||
| 829 | } |
||
| 830 | |||
| 831 | |||
| 832 | #endif //#if defined(STACK_USE_DHCP) |