?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * Dynamic Host Configuration Protocol (DHCP) Client
4 * Module for Microchip TCP/IP Stack
5 * -Provides automatic IP address, subnet mask, gateway address,
6 * DNS server address, and other configuration parameters on DHCP
7 * enabled networks.
8 * -Reference: RFC 2131, 2132
9 *
10 *********************************************************************
11 * FileName: DHCP.c
12 * Dependencies: UDP
13 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
14 * Compiler: Microchip C32 v1.05 or higher
15 * Microchip C30 v3.12 or higher
16 * Microchip C18 v3.30 or higher
17 * HI-TECH PICC-18 PRO 9.63PL2 or higher
18 * Company: Microchip Technology, Inc.
19 *
20 * Software License Agreement
21 *
22 * Copyright (C) 2002-2009 Microchip Technology Inc. All rights
23 * reserved.
24 *
25 * Microchip licenses to you the right to use, modify, copy, and
26 * distribute:
27 * (i) the Software when embedded on a Microchip microcontroller or
28 * digital signal controller product ("Device") which is
29 * integrated into Licensee's product; or
30 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
31 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
32 * used in conjunction with a Microchip ethernet controller for
33 * the sole purpose of interfacing with the ethernet controller.
34 *
35 * You should refer to the license agreement accompanying this
36 * Software for additional information regarding your rights and
37 * obligations.
38 *
39 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
40 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
41 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
42 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
43 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
44 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
45 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
46 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
47 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
48 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
49 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
50 *
51 *
52 * Author Date Comment
53 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 * Nilesh Rajbharti 3/21/01 Original (Rev 1.0)
55 * Nilesh Rajbharti 7/10/02 Explicitly initialized tempIPAddress
56 * (Rev 2.11)
57 * Nilesh Rajbharti 5/16/03 Increased DHCP_TIMEOUT to 2 seconds.
58 * Nilesh Rajbharti 5/16/03 Fixed SM_DHCP_BROADCAST logic
59 * where UDPPut was called before setting
60 * active socket.
61 * Robert Sloan 5/29/03 Improved DHCP State machine to handle
62 * NAK and renew existing IP address.
63 * Nilesh Rajbharti 8/15/03 Modified _DHCPRecieve() to check for
64 * chaddr field before accpting the packet.
65 * Fixed DHCPTask() where it would not
66 * reply to first OFFER.
67 * Nilesh Rajbharti 3/1/04 Used tickDiff in DHCPTask() "bind"
68 * state to adjust for irregular TICK_SECOND
69 * Without this logic, actual lease time count
70 * down may be incorrect.
71 * Howard Schlunder 5/11/06 Fixed tickDiff usage, reducing
72 * accumulated timing error. Fixed DHCP
73 * state machine requesting IP 0.0.0.0
74 * after lease expiration.
75 * Howard Schlunder 6/01/06 Added DHCPFlags.bits.bOfferReceived flag to
76 * allow operation on networks with multiple
77 * DHCP servers offering multiple addresses
78 * Howard Schlunder 8/01/06 Added DNS server option to DHCP request,
79 * untested Host Name option to DHCP request
80 * Howard Schlunder 1/09/06 Fixed a DHCP renewal not renewing lease time bug
81 * Howard Schlunder 3/16/07 Rewrote DHCP state machine
82 ********************************************************************/
83 #define __DHCP_C
84  
85 #include "TCPIPConfig.h"
86  
87 #if defined(STACK_USE_DHCP_CLIENT)
88  
89 #include "TCPIP Stack/TCPIP.h"
90  
91 // Defines how long to wait before a DHCP request times out
92 #define DHCP_TIMEOUT (2ul*TICK_SECOND)
93  
94 // Unique variables per interface
95 typedef struct
96 {
97 UDP_SOCKET hDHCPSocket; // Handle to DHCP client socket
98 SM_DHCP smState; // DHCP client state machine variable
99 union
100 {
101 struct
102 {
103 unsigned char bIsBound : 1; // Whether or not DHCP is currently bound
104 unsigned char bEvent : 1; // Indicates to an external module that the DHCP client has been reset, has obtained new parameters via the DHCP client, or has refreshed a lease on existing ones
105 unsigned char bOfferReceived : 1; // Whether or not an offer has been received
106 unsigned char bDHCPServerDetected : 1; // Indicates if a DCHP server has been detected
107 unsigned char bUseUnicastMode : 1; // Indicates if the
108 } bits;
109 BYTE val;
110 } flags;
111 DWORD dwTimer; // Tick timer value used for triggering future events after a certain wait period.
112 DWORD dwLeaseTime; // DHCP lease time remaining, in seconds
113 DWORD dwServerID; // DHCP Server ID cache
114 IP_ADDR tempIPAddress; // Temporary IP address to use when no DHCP lease
115 IP_ADDR tempGateway; // Temporary gateway to use when no DHCP lease
116 IP_ADDR tempMask; // Temporary mask to use when no DHCP lease
117 #if defined(STACK_USE_DNS)
118 IP_ADDR tempDNS; // Temporary primary DNS server
119 IP_ADDR tempDNS2; // Temporary secondary DNS server
120 #endif
121 // Indicates which DHCP values are currently valid
122 union
123 {
124 struct
125 {
126 char IPAddress:1; // Leased IP address is valid
127 char Gateway:1; // Gateway address is valid
128 char Mask:1; // Subnet mask is valid
129 char DNS:1; // Primary DNS is valid
130 char DNS2:1; // Secondary DNS is valid
131 char HostName:1; // Host name is valid (not implemented)
132 } bits;
133 BYTE val;
134 } validValues;
135 } DHCP_CLIENT_VARS;
136  
137 BOOL DHCPClientInitializedOnce = FALSE;
138  
139 static BYTE _DHCPReceive(void);
140 static void _DHCPSend(BYTE messageType, BOOL bRenewing);
141  
142  
143 /*****************************************************************************
144 Function:
145 static void LoadState(BYTE vInterface)
146  
147 Summary:
148 Saves the DHCPClient state information structure to the appropriate
149 location and loads DHCPClient with the state information for the specified
150 interface.
151  
152 Description:
153 Saves the DHCPClient state information structure to the appropriate
154 location and loads DHCPClient with the state information for the specified
155 interface.
156  
157 Precondition:
158 None
159  
160 Parameters:
161 None
162  
163 Returns:
164 None
165  
166 Remarks:
167 This function does nothing when you only have one physical interface.
168 ***************************************************************************/
169 #if NETWORK_INTERFACES > 1
170  
171 static DHCP_CLIENT_VARS DHCPClients[NETWORK_INTERFACES];
172 static DHCP_CLIENT_VARS *SelectedDHCPClient;
173 #define DHCPClient (*SelectedDHCPClient)
174 #define LoadState(v) do(SelectedDHCPClient = &DHCPClients[v])while(0)
175  
176 #else
177  
178 static DHCP_CLIENT_VARS DHCPClient;
179 #define LoadState(v)
180  
181 #endif
182  
183  
184 /*****************************************************************************
185 Function:
186 void DHCPInit(BYTE vInterface)
187  
188 Summary:
189 Resets the DHCP client module for the specified interface.
190  
191 Description:
192 Resets the DHCP client module, giving up any current lease, knowledge of
193 DHCP servers, etc. for the specified interface.
194  
195 Precondition:
196 None
197  
198 Parameters:
199 vInterface - Interface number to initialize DHCP client state variables
200 for. If you only have one interface, specify 0x00.
201  
202 Returns:
203 None
204  
205 Remarks:
206 This function may be called multiple times throughout the life of the
207 application, if desired.
208 ***************************************************************************/
209 void DHCPInit(BYTE vInterface)
210 {
211 BYTE i;
212  
213 // Upon the first call after POR, we must reset all handles to invalid so
214 // that we don't inadvertently close someone else's handle.
215 if(!DHCPClientInitializedOnce)
216 {
217 DHCPClientInitializedOnce = TRUE;
218 for(i = 0; i < NETWORK_INTERFACES; i++)
219 {
220 LoadState(i);
221 DHCPClient.hDHCPSocket = INVALID_UDP_SOCKET;
222 }
223 }
224  
225  
226 LoadState(vInterface);
227  
228 if(DHCPClient.hDHCPSocket != INVALID_UDP_SOCKET)
229 {
230 UDPClose(DHCPClient.hDHCPSocket);
231 DHCPClient.hDHCPSocket = INVALID_UDP_SOCKET;
232 }
233  
234 // Reset state machine and flags to default values
235 DHCPClient.smState = SM_DHCP_GET_SOCKET;
236 DHCPClient.flags.val = 0;
237 DHCPClient.flags.bits.bUseUnicastMode = TRUE; // This flag toggles before use, so this statement actually means to start out using broadcast mode.
238 DHCPClient.flags.bits.bEvent = TRUE;
239 }
240  
241  
242 /*****************************************************************************
243 Function:
244 void DHCPDisable(BYTE vInterface)
245  
246 Summary:
247 Disables the DHCP Client for the specified interface.
248  
249 Description:
250 Disables the DHCP client for the specified interface by sending the state
251 machine to "SM_DHCP_DISABLED". If the interface was previously configured
252 by DHCP, the configuration will continue to be used but the module will no
253 longer preform any renewals.
254  
255 Precondition:
256 None
257  
258 Parameters:
259 vInterface - Interface number to disable the DHCP client on. If you only
260 have one interface, specify 0x00.
261  
262 Returns:
263 None
264  
265 Remarks:
266 Since the interface continues using its old configuration, it is possible
267 that the lease may expire and the DHCP server provide the IP to another
268 client. The application should replace the current IP address and other
269 configuration with static information following a call to this function.
270 ***************************************************************************/
271 void DHCPDisable(BYTE vInterface)
272 {
273 LoadState(vInterface);
274  
275 if(DHCPClient.hDHCPSocket != INVALID_UDP_SOCKET)
276 {
277 UDPClose(DHCPClient.hDHCPSocket);
278 DHCPClient.hDHCPSocket = INVALID_UDP_SOCKET;
279 }
280  
281 DHCPClient.smState = SM_DHCP_DISABLED;
282 }
283  
284  
285 /*****************************************************************************
286 Function:
287 void DHCPEnable(BYTE vInterface)
288  
289 Summary:
290 Enables the DHCP client for the specified interface.
291  
292 Description:
293 Enables the DHCP client for the specified interface, if it is disabled.
294 If it is already enabled, nothing is done.
295  
296 Precondition:
297 None
298  
299 Parameters:
300 vInterface - Interface number to enable the DHCP client on. If you only
301 have one interface, specify 0x00.
302  
303 Returns:
304 None
305 ***************************************************************************/
306 void DHCPEnable(BYTE vInterface)
307 {
308 LoadState(vInterface);
309  
310 if(DHCPClient.smState == SM_DHCP_DISABLED)
311 {
312 DHCPClient.smState = SM_DHCP_GET_SOCKET;
313 DHCPClient.flags.bits.bIsBound = FALSE;
314 }
315 }
316  
317 /*****************************************************************************
318 Function:
319 BOOL DHCPIsEnabled(BYTE vInterface)
320  
321 Summary:
322 Determins if the DHCP client is enabled on the specified interface.
323  
324 Description:
325 Determins if the DHCP client is enabled on the specified interface.
326  
327 Precondition:
328 None
329  
330 Parameters:
331 vInterface - Interface number to query. If you only have one interface,
332 specify 0x00.
333  
334 Returns:
335 None
336 ***************************************************************************/
337 BOOL DHCPIsEnabled(BYTE vInterface)
338 {
339 LoadState(vInterface);
340 return DHCPClient.smState != SM_DHCP_DISABLED;
341 }
342  
343  
344 /*****************************************************************************
345 Function:
346 BOOL DHCPIsBound(BYTE vInterface)
347  
348 Summary:
349 Determins if the DHCP client has an IP address lease on the specified
350 interface.
351  
352 Description:
353 Determins if the DHCP client has an IP address lease on the specified
354 interface.
355  
356 Precondition:
357 None
358  
359 Parameters:
360 vInterface - Interface number to query. If you only have one interface,
361 specify 0x00.
362  
363 Returns:
364 TRUE - DHCP client has obtained an IP address lease (and likely other
365 parameters) and these values are currently being used.
366 FALSE - No IP address is currently leased
367 ***************************************************************************/
368 BOOL DHCPIsBound(BYTE vInterface)
369 {
370 LoadState(vInterface);
371 return DHCPClient.flags.bits.bIsBound;
372 }
373  
374 /*****************************************************************************
375 Function:
376 BOOL DHCPStateChanged(BYTE vInterface)
377  
378 Summary:
379 Determins if the DHCP client on the specified interface has changed states
380 or refreshed its IP address lease.
381  
382 Description:
383 Determins if the DHCP client on the specified interface has changed states
384 or refreshed its IP address lease. This function can be used to determine
385 when to update an LCD or other display whenever the DHCP assigned IP
386 address has potentially changed.
387  
388 Precondition:
389 None
390  
391 Parameters:
392 vInterface - Interface number to query. If you only have one interface,
393 specify 0x00.
394  
395 Returns:
396 TRUE - The IP address lease have been reliquished (due to reinitilization),
397 obtained (first event), or renewed since the last call to
398 DHCPStateChanged().
399 FALSE - The DHCP client has not detected any changes since the last call to
400 DHCPStateChanged().
401 ***************************************************************************/
402 BOOL DHCPStateChanged(BYTE vInterface)
403 {
404 LoadState(vInterface);
405 if(DHCPClient.flags.bits.bEvent)
406 {
407 DHCPClient.flags.bits.bEvent = 0;
408 return TRUE;
409 }
410 return FALSE;
411 }
412  
413  
414 /*****************************************************************************
415 Function:
416 BOOL DHCPIsServerDetected(BYTE vInterface)
417  
418 Summary:
419 Determins if the DHCP client on the specified interface has seen a DHCP
420 server.
421  
422 Description:
423 Determins if the DHCP client on the specified interface has seen a DHCP
424 server.
425  
426 Precondition:
427 None
428  
429 Parameters:
430 vInterface - Interface number to query. If you only have one interface,
431 specify 0x00.
432  
433 Returns:
434 TRUE - At least one DHCP server is attached to the specified network
435 interface.
436 FALSE - No DHCP servers are currently detected on the specified network
437 interface.
438 ***************************************************************************/
439 BOOL DHCPIsServerDetected(BYTE vInterface)
440 {
441 LoadState(vInterface);
442 return DHCPClient.flags.bits.bDHCPServerDetected;
443 }
444  
445  
446 /*****************************************************************************
447 Function:
448 void DHCPTask(void)
449  
450 Summary:
451 Performs periodic DHCP tasks for all interfaces.
452  
453 Description:
454 This function performs any periodic tasks requied by the DHCP module,
455 such as sending and receiving messages involved with obtaining and
456 maintaining a lease.
457  
458 Precondition:
459 None
460  
461 Parameters:
462 None
463  
464 Returns:
465 None
466 ***************************************************************************/
467 void DHCPTask(void)
468 {
469 BYTE i;
470  
471 for(i = 0; i < NETWORK_INTERFACES; i++)
472 {
473 LoadState(i);
474 switch(DHCPClient.smState)
475 {
476 case SM_DHCP_DISABLED:
477 // When the module is disabled, do absolutely nothing
478 break;
479  
480 case SM_DHCP_GET_SOCKET:
481 // Open a socket to send and receive broadcast messages on
482 DHCPClient.hDHCPSocket = UDPOpen(DHCP_CLIENT_PORT, NULL, DHCP_SERVER_PORT);
483 if(DHCPClient.hDHCPSocket == INVALID_UDP_SOCKET)
484 break;
485  
486 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
487 // No break
488  
489 case SM_DHCP_SEND_DISCOVERY:
490 // Assume default IP Lease time of 60 seconds.
491 // This should be minimum possible to make sure that if the
492 // server did not specify lease time, we try again after this
493 // minimum time.
494 DHCPClient.dwLeaseTime = 60;
495 DHCPClient.validValues.val = 0x00;
496 DHCPClient.flags.bits.bIsBound = FALSE;
497 DHCPClient.flags.bits.bOfferReceived = FALSE;
498  
499 // No point in wasting time transmitting a discovery if we are
500 // unlinked. No one will see it.
501 if(!MACIsLinked())
502 break;
503  
504 // Ensure transmitter is ready to accept data
505 if(UDPIsPutReady(DHCPClient.hDHCPSocket) < 300u)
506 break;
507  
508 // Toggle the BOOTP Broadcast flag to ensure compatibility with
509 // bad DHCP servers that don't know how to handle broadcast
510 // responses. This results in the next discovery attempt to be
511 // made using the opposite mode.
512 DHCPClient.flags.bits.bUseUnicastMode ^= 1;
513  
514 // Ensure that we transmit to the broadcast IP and MAC addresses
515 // The UDP Socket remembers who it was last talking to
516 memset((void*)&UDPSocketInfo[DHCPClient.hDHCPSocket].remoteNode, 0xFF, sizeof(UDPSocketInfo[0].remoteNode));
517  
518 // Send the DHCP Discover broadcast
519 _DHCPSend(DHCP_DISCOVER_MESSAGE, FALSE);
520  
521 // Start a timer and begin looking for a response
522 DHCPClient.dwTimer = TickGet();
523 DHCPClient.smState = SM_DHCP_GET_OFFER;
524 break;
525  
526 case SM_DHCP_GET_OFFER:
527 // Check to see if a packet has arrived
528 if(UDPIsGetReady(DHCPClient.hDHCPSocket) < 250u)
529 {
530 // Go back and transmit a new discovery if we didn't get an offer after 2 seconds
531 if(TickGet() - DHCPClient.dwTimer >= DHCP_TIMEOUT)
532 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
533 break;
534 }
535  
536 // Let the DHCP server module know that there is a DHCP server
537 // on this network
538 DHCPClient.flags.bits.bDHCPServerDetected = TRUE;
539  
540 // Check to see if we received an offer
541 if(_DHCPReceive() != DHCP_OFFER_MESSAGE)
542 break;
543  
544 DHCPClient.smState = SM_DHCP_SEND_REQUEST;
545 // No break
546  
547 case SM_DHCP_SEND_REQUEST:
548 if(UDPIsPutReady(DHCPClient.hDHCPSocket) < 258u)
549 break;
550  
551 // Ensure that we transmit to the broadcast IP and MAC addresses
552 // The UDP Socket remembers who it was last talking to, so
553 // we must set this back to the broadcast address since the
554 // current socket values are the unicast addresses of the DHCP
555 // server.
556 memset((void*)&UDPSocketInfo[DHCPClient.hDHCPSocket].remoteNode, 0xFF, sizeof(UDPSocketInfo[0].remoteNode));
557  
558 // Send the DHCP request message
559 _DHCPSend(DHCP_REQUEST_MESSAGE, FALSE);
560  
561 // Start a timer and begin looking for a response
562 DHCPClient.dwTimer = TickGet();
563 DHCPClient.smState = SM_DHCP_GET_REQUEST_ACK;
564 break;
565  
566 case SM_DHCP_GET_REQUEST_ACK:
567 // Check to see if a packet has arrived
568 if(UDPIsGetReady(DHCPClient.hDHCPSocket) < 250u)
569 {
570 // Go back and transmit a new discovery if we didn't get an ACK after 2 seconds
571 if(TickGet() - DHCPClient.dwTimer >= DHCP_TIMEOUT)
572 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
573 break;
574 }
575  
576 // Check to see if we received an offer
577 switch(_DHCPReceive())
578 {
579 case DHCP_ACK_MESSAGE:
580 UDPClose(DHCPClient.hDHCPSocket);
581 DHCPClient.hDHCPSocket = INVALID_UDP_SOCKET;
582 DHCPClient.dwTimer = TickGet();
583 DHCPClient.smState = SM_DHCP_BOUND;
584 DHCPClient.flags.bits.bEvent = 1;
585 DHCPClient.flags.bits.bIsBound = TRUE;
586  
587 if(DHCPClient.validValues.bits.IPAddress)
588 AppConfig.MyIPAddr = DHCPClient.tempIPAddress;
589 if(DHCPClient.validValues.bits.Mask)
590 AppConfig.MyMask = DHCPClient.tempMask;
591 if(DHCPClient.validValues.bits.Gateway)
592 AppConfig.MyGateway = DHCPClient.tempGateway;
593 #if defined(STACK_USE_DNS)
594 if(DHCPClient.validValues.bits.DNS)
595 AppConfig.PrimaryDNSServer.Val = DHCPClient.tempDNS.Val;
596 AppConfig.SecondaryDNSServer.Val = 0x00000000ul;
597 if(DHCPClient.validValues.bits.DNS2)
598 AppConfig.SecondaryDNSServer.Val = DHCPClient.tempDNS2.Val;
599 #endif
600 //if(DHCPClient.validValues.bits.HostName)
601 // memcpy(AppConfig.NetBIOSName, (void*)DHCPClient.tempHostName, sizeof(AppConfig.NetBIOSName));
602  
603 break;
604  
605 case DHCP_NAK_MESSAGE:
606 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
607 break;
608 }
609 break;
610  
611 case SM_DHCP_BOUND:
612 if(TickGet() - DHCPClient.dwTimer < TICK_SECOND)
613 break;
614  
615 // Check to see if our lease is still valid, if so, decrement lease
616 // time
617 if(DHCPClient.dwLeaseTime >= 2ul)
618 {
619 DHCPClient.dwTimer += TICK_SECOND;
620 DHCPClient.dwLeaseTime--;
621 break;
622 }
623  
624 // Open a socket to send and receive DHCP messages on
625 DHCPClient.hDHCPSocket = UDPOpen(DHCP_CLIENT_PORT, NULL, DHCP_SERVER_PORT);
626 if(DHCPClient.hDHCPSocket == INVALID_UDP_SOCKET)
627 break;
628  
629 DHCPClient.smState = SM_DHCP_SEND_RENEW;
630 // No break
631  
632 case SM_DHCP_SEND_RENEW:
633 case SM_DHCP_SEND_RENEW2:
634 case SM_DHCP_SEND_RENEW3:
635 if(UDPIsPutReady(DHCPClient.hDHCPSocket) < 258u)
636 break;
637  
638 // Send the DHCP request message
639 _DHCPSend(DHCP_REQUEST_MESSAGE, TRUE);
640 DHCPClient.flags.bits.bOfferReceived = FALSE;
641  
642 // Start a timer and begin looking for a response
643 DHCPClient.dwTimer = TickGet();
644 DHCPClient.smState++;
645 break;
646  
647 case SM_DHCP_GET_RENEW_ACK:
648 case SM_DHCP_GET_RENEW_ACK2:
649 case SM_DHCP_GET_RENEW_ACK3:
650 // Check to see if a packet has arrived
651 if(UDPIsGetReady(DHCPClient.hDHCPSocket) < 250u)
652 {
653 // Go back and transmit a new discovery if we didn't get an ACK after 2 seconds
654 if(TickGet() - DHCPClient.dwTimer >= DHCP_TIMEOUT)
655 {
656 if(++DHCPClient.smState > SM_DHCP_GET_RENEW_ACK3)
657 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
658 }
659 break;
660 }
661  
662 // Check to see if we received an offer
663 switch(_DHCPReceive())
664 {
665 case DHCP_ACK_MESSAGE:
666 UDPClose(DHCPClient.hDHCPSocket);
667 DHCPClient.hDHCPSocket = INVALID_UDP_SOCKET;
668 DHCPClient.dwTimer = TickGet();
669 DHCPClient.smState = SM_DHCP_BOUND;
670 DHCPClient.flags.bits.bEvent = 1;
671 break;
672  
673 case DHCP_NAK_MESSAGE:
674 DHCPClient.smState = SM_DHCP_SEND_DISCOVERY;
675 break;
676 }
677 break;
678 }
679 }
680 }
681  
682  
683  
684 /*****************************************************************************
685 Function:
686 void _DHCPReceive(void)
687  
688 Description:
689 Receives and parses a DHCP message.
690  
691 Precondition:
692 A DHCP message is waiting in the UDP buffer.
693  
694 Parameters:
695 None
696  
697 Returns:
698 One of the DCHP_TYPE* contants.
699 ***************************************************************************/
700 static BYTE _DHCPReceive(void)
701 {
702 /*********************************************************************
703 DHCP PACKET FORMAT AS PER RFC 1541
704  
705  
706  
707 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
708 | op (1) | htype (1) | hlen (1) | hops (1) |
709 +---------------+---------------+---------------+---------------+
710 | xid (4) |
711 +-------------------------------+-------------------------------+
712 | secs (2) | flags (2) |
713 +-------------------------------+-------------------------------+
714 | ciaddr (4) |
715 +---------------------------------------------------------------+
716 | yiaddr (4) |
717 +---------------------------------------------------------------+
718 | siaddr (4) |
719 +---------------------------------------------------------------+
720 | giaddr (4) |
721 +---------------------------------------------------------------+
722 | |
723 | chaddr (16) |
724 | |
725 | |
726 +---------------------------------------------------------------+
727 | |
728 | sname (64) |
729 +---------------------------------------------------------------+
730 | |
731 | file (128) |
732 +---------------------------------------------------------------+
733 | |
734 | options (312) |
735 +---------------------------------------------------------------+
736  
737 ********************************************************************/
738 BYTE v;
739 BYTE i, j;
740 BYTE type;
741 BOOL lbDone;
742 DWORD tempServerID;
743  
744  
745 // Assume unknown message until proven otherwise.
746 type = DHCP_UNKNOWN_MESSAGE;
747  
748 UDPGet(&v); // op
749  
750 // Make sure this is BOOT_REPLY.
751 if ( v == BOOT_REPLY )
752 {
753 // Jump to chaddr field (Client Hardware Address -- our MAC address for
754 // Ethernet and WiFi networks) and verify that this message is directed
755 // to us before doing any other processing.
756 UDPSetRxBuffer(28); // chaddr field is at offset 28 in the UDP packet payload -- see DHCP packet format above
757 for ( i = 0; i < 6u; i++ )
758 {
759 UDPGet(&v);
760 if ( v != AppConfig.MyMACAddr.v[i])
761 goto UDPInvalid;
762 }
763  
764 // Check to see if this is the first offer. If it is, record its
765 // yiaddr value ("Your (client) IP address") so that we can REQUEST to
766 // use it later.
767 if(!DHCPClient.flags.bits.bOfferReceived)
768 {
769 UDPSetRxBuffer(16);
770 UDPGetArray((BYTE*)&DHCPClient.tempIPAddress, sizeof(DHCPClient.tempIPAddress));
771 DHCPClient.validValues.bits.IPAddress = 1;
772 }
773  
774 // Jump to DHCP options (ignore htype, hlen, hops, xid, secs, flags,
775 // ciaddr, siaddr, giaddr, padding part of chaddr, sname, file, magic
776 // cookie fields)
777 UDPSetRxBuffer(240);
778  
779 lbDone = FALSE;
780 do
781 {
782 // Get the Option number
783 // Break out eventually in case if this is a malformed
784 // DHCP message, ie: missing DHCP_END_OPTION marker
785 if(!UDPGet(&v))
786 {
787 lbDone = TRUE;
788 break;
789 }
790  
791 switch(v)
792 {
793 case DHCP_MESSAGE_TYPE:
794 UDPGet(&v); // Skip len
795 // Len must be 1.
796 if ( v == 1u )
797 {
798 UDPGet(&type); // Get type
799  
800 // Throw away the packet if we know we don't need it (ie: another offer when we already have one)
801 if(DHCPClient.flags.bits.bOfferReceived && (type == DHCP_OFFER_MESSAGE))
802 {
803 goto UDPInvalid;
804 }
805 }
806 else
807 goto UDPInvalid;
808 break;
809  
810 case DHCP_SUBNET_MASK:
811 UDPGet(&v); // Skip len
812 // Len must be 4.
813 if ( v == 4u )
814 {
815 // Check to see if this is the first offer
816 if(DHCPClient.flags.bits.bOfferReceived)
817 {
818 // Discard offered IP mask, we already have an offer
819 for ( i = 0; i < 4u; i++ )
820 UDPGet(&v);
821 }
822 else
823 {
824 UDPGetArray((BYTE*)&DHCPClient.tempMask, sizeof(DHCPClient.tempMask));
825 DHCPClient.validValues.bits.Mask = 1;
826 }
827 }
828 else
829 goto UDPInvalid;
830 break;
831  
832 case DHCP_ROUTER:
833 UDPGet(&j);
834 // Len must be >= 4.
835 if ( j >= 4u )
836 {
837 // Check to see if this is the first offer
838 if(DHCPClient.flags.bits.bOfferReceived)
839 {
840 // Discard offered Gateway address, we already have an offer
841 for ( i = 0; i < 4u; i++ )
842 UDPGet(&v);
843 }
844 else
845 {
846 UDPGetArray((BYTE*)&DHCPClient.tempGateway, sizeof(DHCPClient.tempGateway));
847 DHCPClient.validValues.bits.Gateway = 1;
848 }
849 }
850 else
851 goto UDPInvalid;
852  
853 // Discard any other router addresses.
854 j -= 4;
855 while(j--)
856 UDPGet(&v);
857 break;
858  
859 #if defined(STACK_USE_DNS)
860 case DHCP_DNS:
861 UDPGet(&j);
862 // Len must be >= 4.
863 if(j < 4u)
864 goto UDPInvalid;
865  
866 // Check to see if this is the first offer
867 if(!DHCPClient.flags.bits.bOfferReceived)
868 {
869 UDPGetArray((BYTE*)&DHCPClient.tempDNS, sizeof(DHCPClient.tempDNS));
870 DHCPClient.validValues.bits.DNS = 1;
871 j -= 4;
872 }
873  
874 // Len must be >= 4 for a secondary DNS server address
875 if(j >= 4u)
876 {
877 // Check to see if this is the first offer
878 if(!DHCPClient.flags.bits.bOfferReceived)
879 {
880 UDPGetArray((BYTE*)&DHCPClient.tempDNS2, sizeof(DHCPClient.tempDNS2));
881 DHCPClient.validValues.bits.DNS2 = 1;
882 j -= 4;
883 }
884 }
885  
886 // Discard any other DNS server addresses
887 while(j--)
888 UDPGet(&v);
889 break;
890 #endif
891  
892 // case DHCP_HOST_NAME:
893 // UDPGet(&j);
894 // // Len must be >= 4.
895 // if(j < 1u)
896 // goto UDPInvalid;
897 //
898 // // Check to see if this is the first offer
899 // if(DHCPFlags.bits.bOfferReceived)
900 // {
901 // // Discard offered host name, we already have an offer
902 // while(j--)
903 // UDPGet(&v);
904 // }
905 // else
906 // {
907 // for(i = 0; j, i < sizeof(tempHostName); i++, j--)
908 // {
909 // UDPGet(&tempHostName[i]);
910 // }
911 // while(j--)
912 // {
913 // UDPGet(&v);
914 // }
915 // ValidValues.bits.HostName = 1;
916 // }
917 //
918 // break;
919  
920 case DHCP_SERVER_IDENTIFIER:
921 UDPGet(&v); // Get len
922 // Len must be 4.
923 if ( v == 4u )
924 {
925 UDPGet(&(((BYTE*)&tempServerID)[3])); // Get the id
926 UDPGet(&(((BYTE*)&tempServerID)[2]));
927 UDPGet(&(((BYTE*)&tempServerID)[1]));
928 UDPGet(&(((BYTE*)&tempServerID)[0]));
929 }
930 else
931 goto UDPInvalid;
932 break;
933  
934 case DHCP_END_OPTION:
935 lbDone = TRUE;
936 break;
937  
938 case DHCP_IP_LEASE_TIME:
939 UDPGet(&v); // Get len
940 // Len must be 4.
941 if ( v == 4u )
942 {
943 // Check to see if this is the first offer
944 if(DHCPClient.flags.bits.bOfferReceived)
945 {
946 // Discard offered lease time, we already have an offer
947 for ( i = 0; i < 4u; i++ )
948 UDPGet(&v);
949 }
950 else
951 {
952 UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[3]));
953 UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[2]));
954 UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[1]));
955 UDPGet(&(((BYTE*)(&DHCPClient.dwLeaseTime))[0]));
956  
957 // In case if our clock is not as accurate as the remote
958 // DHCP server's clock, let's treat the lease time as only
959 // 96.875% of the value given
960 DHCPClient.dwLeaseTime -= DHCPClient.dwLeaseTime>>5;
961 }
962 }
963 else
964 goto UDPInvalid;
965 break;
966  
967 default:
968 // Ignore all unsupport tags.
969 UDPGet(&j); // Get option len
970 while( j-- ) // Ignore option values
971 UDPGet(&v);
972 }
973 } while( !lbDone );
974 }
975  
976 // If this is an OFFER message, remember current server id.
977 if ( type == DHCP_OFFER_MESSAGE )
978 {
979 DHCPClient.dwServerID = tempServerID;
980 DHCPClient.flags.bits.bOfferReceived = TRUE;
981 }
982 else
983 {
984 // For other types of messages, make sure that received
985 // server id matches with our previous one.
986 if ( DHCPClient.dwServerID != tempServerID )
987 type = DHCP_UNKNOWN_MESSAGE;
988 }
989  
990 UDPDiscard(); // We are done with this packet
991 return type;
992  
993 UDPInvalid:
994 UDPDiscard();
995 return DHCP_UNKNOWN_MESSAGE;
996 }
997  
998  
999  
1000  
1001 /*****************************************************************************
1002 Function:
1003 static void _DHCPSend(BYTE messageType, BOOL bRenewing)
1004  
1005 Description:
1006 Sends a DHCP message.
1007  
1008 Precondition:
1009 UDP is ready to write a DHCP packet.
1010  
1011 Parameters:
1012 messageType - One of the DHCP_TYPE constants
1013 bRenewing - Whether or not this is a renewal request
1014  
1015 Returns:
1016 None
1017 ***************************************************************************/
1018 static void _DHCPSend(BYTE messageType, BOOL bRenewing)
1019 {
1020 BYTE i;
1021 IP_ADDR MyIP;
1022  
1023  
1024 UDPPut(BOOT_REQUEST); // op
1025 UDPPut(BOOT_HW_TYPE); // htype
1026 UDPPut(BOOT_LEN_OF_HW_TYPE); // hlen
1027 UDPPut(0); // hops
1028 UDPPut(0x12); // xid[0]
1029 UDPPut(0x23); // xid[1]
1030 UDPPut(0x34); // xid[2]
1031 UDPPut(0x56); // xid[3]
1032 UDPPut(0); // secs[0]
1033 UDPPut(0); // secs[1]
1034 UDPPut(DHCPClient.flags.bits.bUseUnicastMode ? 0x00: 0x80);// flags[0] with Broadcast flag clear/set to correspond to bUseUnicastMode
1035 UDPPut(0); // flags[1]
1036  
1037 // If this is DHCP REQUEST message, use previously allocated IP address.
1038 if((messageType == DHCP_REQUEST_MESSAGE) && bRenewing)
1039 {
1040 UDPPutArray((BYTE*)&DHCPClient.tempIPAddress, sizeof(DHCPClient.tempIPAddress));
1041 }
1042 else
1043 {
1044 UDPPut(0x00);
1045 UDPPut(0x00);
1046 UDPPut(0x00);
1047 UDPPut(0x00);
1048 }
1049  
1050 // Set yiaddr, siaddr, giaddr as zeros,
1051 for ( i = 0; i < 12u; i++ )
1052 UDPPut(0x00);
1053  
1054 // Load chaddr - Client hardware address.
1055 UDPPutArray((BYTE*)&AppConfig.MyMACAddr, sizeof(AppConfig.MyMACAddr));
1056  
1057 // Set chaddr[6..15], sname and file as zeros.
1058 for ( i = 0; i < 202u; i++ )
1059 UDPPut(0);
1060  
1061 // Load magic cookie as per RFC 1533.
1062 UDPPut(99);
1063 UDPPut(130);
1064 UDPPut(83);
1065 UDPPut(99);
1066  
1067 // Load message type.
1068 UDPPut(DHCP_MESSAGE_TYPE);
1069 UDPPut(DHCP_MESSAGE_TYPE_LEN);
1070 UDPPut(messageType);
1071  
1072 if(messageType == DHCP_DISCOVER_MESSAGE)
1073 {
1074 // Reset offered flag so we know to act upon the next valid offer
1075 DHCPClient.flags.bits.bOfferReceived = FALSE;
1076 }
1077  
1078  
1079 if((messageType == DHCP_REQUEST_MESSAGE) && !bRenewing)
1080 {
1081 // DHCP REQUEST message must include server identifier the first time
1082 // to identify the server we are talking to.
1083 // _DHCPReceive() would populate "serverID" when it
1084 // receives DHCP OFFER message. We will simply use that
1085 // when we are replying to server.
1086 // If this is a renwal request, we must not include server id.
1087 UDPPut(DHCP_SERVER_IDENTIFIER);
1088 UDPPut(DHCP_SERVER_IDENTIFIER_LEN);
1089 UDPPut(((BYTE*)(&DHCPClient.dwServerID))[3]);
1090 UDPPut(((BYTE*)(&DHCPClient.dwServerID))[2]);
1091 UDPPut(((BYTE*)(&DHCPClient.dwServerID))[1]);
1092 UDPPut(((BYTE*)(&DHCPClient.dwServerID))[0]);
1093 }
1094  
1095 // Load our interested parameters
1096 // This is hardcoded list. If any new parameters are desired,
1097 // new lines must be added here.
1098 UDPPut(DHCP_PARAM_REQUEST_LIST);
1099 UDPPut(DHCP_PARAM_REQUEST_LIST_LEN);
1100 UDPPut(DHCP_SUBNET_MASK);
1101 UDPPut(DHCP_ROUTER);
1102 UDPPut(DHCP_DNS);
1103 UDPPut(DHCP_HOST_NAME);
1104  
1105 // Add requested IP address to DHCP Request Message
1106 if( ((messageType == DHCP_REQUEST_MESSAGE) && !bRenewing) ||
1107 ((messageType == DHCP_DISCOVER_MESSAGE) && DHCPClient.tempIPAddress.Val))
1108 {
1109 UDPPut(DHCP_PARAM_REQUEST_IP_ADDRESS);
1110 UDPPut(DHCP_PARAM_REQUEST_IP_ADDRESS_LEN);
1111 UDPPutArray((BYTE*)&DHCPClient.tempIPAddress, DHCP_PARAM_REQUEST_IP_ADDRESS_LEN);
1112 }
1113  
1114 // Add any new paramter request here.
1115  
1116 // End of Options.
1117 UDPPut(DHCP_END_OPTION);
1118  
1119 // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets)
1120 while(UDPTxCount < 300u)
1121 UDPPut(0);
1122  
1123 // Make sure we advertise a 0.0.0.0 IP address so all DHCP servers will respond. If we have a static IP outside the DHCP server's scope, it may simply ignore discover messages.
1124 MyIP.Val = AppConfig.MyIPAddr.Val;
1125 if(!bRenewing)
1126 AppConfig.MyIPAddr.Val = 0x00000000;
1127 UDPFlush();
1128 AppConfig.MyIPAddr.Val = MyIP.Val;
1129  
1130 }
1131  
1132  
1133 #endif //#if defined(STACK_USE_DHCP_CLIENT)
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3