QuakeGod
2022-10-17 448d6c050697a6bb7f4b7b02f08ef8fc8e5cd027
提交 | 用户 | age
a7db3c 1 //*****************************************************************************
Q 2 //
3 //! \file dhcp.c
4 //! \brief DHCP APIs implement file.
5 //! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE.
6 //! \version 1.1.0
7 //! \date 2013/11/18
8 //! \par  Revision history
9 //!       <2013/11/18> 1st Release
10 //!       <2012/12/20> V1.1.0
11 //!         1. Optimize code
12 //!         2. Add reg_dhcp_cbfunc()
13 //!         3. Add DHCP_stop() 
14 //!         4. Integrate check_DHCP_state() & DHCP_run() to DHCP_run()
15 //!         5. Don't care system endian
16 //!         6. Add comments
17 //!       <2012/12/26> V1.1.1
18 //!         1. Modify variable declaration: dhcp_tick_1s is declared volatile for code optimization
19 //! \author Eric Jung & MidnightCow
20 //! \copyright
21 //!
22 //! Copyright (c)  2013, WIZnet Co., LTD.
23 //! All rights reserved.
24 //! 
25 //! Redistribution and use in source and binary forms, with or without 
26 //! modification, are permitted provided that the following conditions 
27 //! are met: 
28 //! 
29 //!     * Redistributions of source code must retain the above copyright 
30 //! notice, this list of conditions and the following disclaimer. 
31 //!     * Redistributions in binary form must reproduce the above copyright
32 //! notice, this list of conditions and the following disclaimer in the
33 //! documentation and/or other materials provided with the distribution. 
34 //!     * Neither the name of the <ORGANIZATION> nor the names of its 
35 //! contributors may be used to endorse or promote products derived 
36 //! from this software without specific prior written permission. 
37 //! 
38 //! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39 //! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
40 //! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 //! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
42 //! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
43 //! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
44 //! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45 //! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
46 //! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
47 //! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
48 //! THE POSSIBILITY OF SUCH DAMAGE.
49 //
50 //*****************************************************************************
51
52 #include "Ethernet/socket.h"
53 #include "Internet/DHCP/dhcp.h"
54
55 /* If you want to display debug & procssing message, Define _DHCP_DEBUG_ in dhcp.h */
56
57 #ifdef _DHCP_DEBUG_
58    #include <stdio.h>
59 #endif   
60
61 /* DHCP state machine. */
62 #define STATE_DHCP_INIT          0        ///< Initialize
63 #define STATE_DHCP_DISCOVER      1        ///< send DISCOVER and wait OFFER
64 #define STATE_DHCP_REQUEST       2        ///< send REQEUST and wait ACK or NACK
65 #define STATE_DHCP_LEASED        3        ///< ReceiveD ACK and IP leased
66 #define STATE_DHCP_REREQUEST     4        ///< send REQUEST for maintaining leased IP
67 #define STATE_DHCP_RELEASE       5        ///< No use
68 #define STATE_DHCP_STOP          6        ///< Stop procssing DHCP
69
70 #define DHCP_FLAGSBROADCAST      0x8000   ///< The broadcast value of flags in @ref RIP_MSG 
71 #define DHCP_FLAGSUNICAST        0x0000   ///< The unicast   value of flags in @ref RIP_MSG
72
73 /* DHCP message OP code */
74 #define DHCP_BOOTREQUEST         1        ///< Request Message used in op of @ref RIP_MSG
75 #define DHCP_BOOTREPLY           2        ///< Reply Message used i op of @ref RIP_MSG
76
77 /* DHCP message type */
78 #define DHCP_DISCOVER            1        ///< DISCOVER message in OPT of @ref RIP_MSG
79 #define DHCP_OFFER               2        ///< OFFER message in OPT of @ref RIP_MSG
80 #define DHCP_REQUEST             3        ///< REQUEST message in OPT of @ref RIP_MSG
81 #define DHCP_DECLINE             4        ///< DECLINE message in OPT of @ref RIP_MSG
82 #define DHCP_ACK                 5        ///< ACK message in OPT of @ref RIP_MSG
83 #define DHCP_NAK                 6        ///< NACK message in OPT of @ref RIP_MSG
84 #define DHCP_RELEASE             7        ///< RELEASE message in OPT of @ref RIP_MSG. No use
85 #define DHCP_INFORM              8        ///< INFORM message in OPT of @ref RIP_MSG. No use
86
87 #define DHCP_HTYPE10MB           1        ///< Used in type of @ref RIP_MSG
88 #define DHCP_HTYPE100MB          2        ///< Used in type of @ref RIP_MSG
89
90 #define DHCP_HLENETHERNET        6        ///< Used in hlen of @ref RIP_MSG
91 #define DHCP_HOPS                0        ///< Used in hops of @ref RIP_MSG
92 #define DHCP_SECS                0        ///< Used in secs of @ref RIP_MSG
93
94 #define INFINITE_LEASETIME       0xffffffff    ///< Infinite lease time
95
96 #define OPT_SIZE                 312               /// Max OPT size of @ref RIP_MSG
97 #define RIP_MSG_SIZE             (236+OPT_SIZE)    /// Max size of @ref RIP_MSG
98
99 /* 
100  * @brief DHCP option and value (cf. RFC1533)
101  */
102 enum
103 {
104    padOption               = 0,
105    subnetMask              = 1,
106    timerOffset             = 2,
107    routersOnSubnet         = 3,
108    timeServer              = 4,
109    nameServer              = 5,
110    dns                     = 6,
111    logServer               = 7,
112    cookieServer            = 8,
113    lprServer               = 9,
114    impressServer           = 10,
115    resourceLocationServer    = 11,
116    hostName                = 12,
117    bootFileSize            = 13,
118    meritDumpFile           = 14,
119    domainName              = 15,
120    swapServer              = 16,
121    rootPath                = 17,
122    extentionsPath          = 18,
123    IPforwarding            = 19,
124    nonLocalSourceRouting   = 20,
125    policyFilter            = 21,
126    maxDgramReasmSize       = 22,
127    defaultIPTTL            = 23,
128    pathMTUagingTimeout     = 24,
129    pathMTUplateauTable     = 25,
130    ifMTU                   = 26,
131    allSubnetsLocal         = 27,
132    broadcastAddr           = 28,
133    performMaskDiscovery    = 29,
134    maskSupplier            = 30,
135    performRouterDiscovery  = 31,
136    routerSolicitationAddr  = 32,
137    staticRoute             = 33,
138    trailerEncapsulation    = 34,
139    arpCacheTimeout         = 35,
140    ethernetEncapsulation   = 36,
141    tcpDefaultTTL           = 37,
142    tcpKeepaliveInterval    = 38,
143    tcpKeepaliveGarbage     = 39,
144    nisDomainName           = 40,
145    nisServers              = 41,
146    ntpServers              = 42,
147    vendorSpecificInfo      = 43,
148    netBIOSnameServer       = 44,
149    netBIOSdgramDistServer    = 45,
150    netBIOSnodeType         = 46,
151    netBIOSscope            = 47,
152    xFontServer             = 48,
153    xDisplayManager         = 49,
154    dhcpRequestedIPaddr     = 50,
155    dhcpIPaddrLeaseTime     = 51,
156    dhcpOptionOverload      = 52,
157    dhcpMessageType         = 53,
158    dhcpServerIdentifier    = 54,
159    dhcpParamRequest        = 55,
160    dhcpMsg                 = 56,
161    dhcpMaxMsgSize          = 57,
162    dhcpT1value             = 58,
163    dhcpT2value             = 59,
164    dhcpClassIdentifier     = 60,
165    dhcpClientIdentifier    = 61,
166    endOption               = 255
167 };
168
169 /*
170  * @brief DHCP message format
171  */ 
172 typedef struct {
173     uint8_t  op;            ///< @ref DHCP_BOOTREQUEST or @ref DHCP_BOOTREPLY
174     uint8_t  htype;         ///< @ref DHCP_HTYPE10MB or @ref DHCP_HTYPE100MB
175     uint8_t  hlen;          ///< @ref DHCP_HLENETHERNET
176     uint8_t  hops;          ///< @ref DHCP_HOPS
177     uint32_t xid;           ///< @ref DHCP_XID  This increase one every DHCP transaction.
178     uint16_t secs;          ///< @ref DHCP_SECS
179     uint16_t flags;         ///< @ref DHCP_FLAGSBROADCAST or @ref DHCP_FLAGSUNICAST
180     uint8_t  ciaddr[4];     ///< @ref Request IP to DHCP sever
181     uint8_t  yiaddr[4];     ///< @ref Offered IP from DHCP server
182     uint8_t  siaddr[4];     ///< No use 
183     uint8_t  giaddr[4];     ///< No use
184     uint8_t  chaddr[16];    ///< DHCP client 6bytes MAC address. Others is filled to zero
185     uint8_t  sname[64];     ///< No use
186     uint8_t  file[128];     ///< No use
187     uint8_t  OPT[OPT_SIZE]; ///< Option
188 } RIP_MSG;
189
190
191
192 uint8_t DHCP_SOCKET;                      // Socket number for DHCP
193
194 uint8_t DHCP_SIP[4];                      // DHCP Server IP address
195
196 // Network information from DHCP Server
197 uint8_t OLD_allocated_ip[4]   = {0, };    // Previous IP address
198 uint8_t DHCP_allocated_ip[4]  = {0, };    // IP address from DHCP
199 uint8_t DHCP_allocated_gw[4]  = {0, };    // Gateway address from DHCP
200 uint8_t DHCP_allocated_sn[4]  = {0, };    // Subnet mask from DHCP
201 uint8_t DHCP_allocated_dns[4] = {0, };    // DNS address from DHCP
202
203
204 int8_t   dhcp_state        = STATE_DHCP_INIT;   // DHCP state
205 int8_t   dhcp_retry_count  = 0;                 
206
207 uint32_t dhcp_lease_time               = INFINITE_LEASETIME;
208 volatile uint32_t dhcp_tick_1s      = 0;                 // unit 1 second
209 uint32_t dhcp_tick_next                = DHCP_WAIT_TIME ;
210
211 uint32_t DHCP_XID;      // Any number
212
213 RIP_MSG* pDHCPMSG;      // Buffer pointer for DHCP processing
214
215 uint8_t HOST_NAME[] = DCHP_HOST_NAME;  
216
217 uint8_t DHCP_CHADDR[6]; // DHCP Client MAC address.
218
219 /* The default callback function */
220 void default_ip_assign(void);
221 void default_ip_update(void);
222 void default_ip_conflict(void);
223
224 /* Callback handler */
225 void (*dhcp_ip_assign)(void)   = default_ip_assign;     /* handler to be called when the IP address from DHCP server is first assigned */
226 void (*dhcp_ip_update)(void)   = default_ip_update;     /* handler to be called when the IP address from DHCP server is updated */
227 void (*dhcp_ip_conflict)(void) = default_ip_conflict;   /* handler to be called when the IP address from DHCP server is conflict */
228
229 void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void));
230
231
232 /* send DISCOVER message to DHCP server */
233 void     send_DHCP_DISCOVER(void);
234
235 /* send REQEUST message to DHCP server */
236 void     send_DHCP_REQUEST(void);
237
238 /* send DECLINE message to DHCP server */
239 void     send_DHCP_DECLINE(void);
240
241 /* IP conflict check by sending ARP-request to leased IP and wait ARP-response. */
242 int8_t   check_DHCP_leasedIP(void);
243
244 /* check the timeout in DHCP process */
245 uint8_t  check_DHCP_timeout(void);
246
247 /* Intialize to timeout process.  */
248 void     reset_DHCP_timeout(void);
249
250 /* Parse message as OFFER and ACK and NACK from DHCP server.*/
251 int8_t   parseDHCPCMSG(void);
252
253 /* The default handler of ip assign first */
254 void default_ip_assign(void)
255 {
256    setSIPR(DHCP_allocated_ip);
257    setSUBR(DHCP_allocated_sn);
258    setGAR (DHCP_allocated_gw);
259 }
260
261 /* The default handler of ip chaged */
262 void default_ip_update(void)
263 {
264     /* WIZchip Software Reset */
265    setMR(MR_RST);
266    getMR(); // for delay
267    default_ip_assign();
268    setSHAR(DHCP_CHADDR);
269 }
270
271 /* The default handler of ip chaged */
272 void default_ip_conflict(void)
273 {
274     // WIZchip Software Reset
275     setMR(MR_RST);
276     getMR(); // for delay
277     setSHAR(DHCP_CHADDR);
278 }
279
280 /* register the call back func. */
281 void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void))
282 {
283    dhcp_ip_assign   = default_ip_assign;
284    dhcp_ip_update   = default_ip_update;
285    dhcp_ip_conflict = default_ip_conflict;
286    if(ip_assign)   dhcp_ip_assign = ip_assign;
287    if(ip_update)   dhcp_ip_update = ip_update;
288    if(ip_conflict) dhcp_ip_conflict = ip_conflict;
289 }
290
291 /* make the common DHCP message */
292 void makeDHCPMSG(void)
293 {
294    uint8_t  bk_mac[6];
295    uint8_t* ptmp;
296    uint8_t  i;
297    getSHAR(bk_mac);
298     pDHCPMSG->op      = DHCP_BOOTREQUEST;
299     pDHCPMSG->htype   = DHCP_HTYPE10MB;
300     pDHCPMSG->hlen    = DHCP_HLENETHERNET;
301     pDHCPMSG->hops    = DHCP_HOPS;
302     ptmp              = (uint8_t*)(&pDHCPMSG->xid);
303     *(ptmp+0)         = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
304     *(ptmp+1)         = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
305    *(ptmp+2)         = (uint8_t)((DHCP_XID & 0x0000FF00) >>  8);
306     *(ptmp+3)         = (uint8_t)((DHCP_XID & 0x000000FF) >>  0);   
307     pDHCPMSG->secs    = DHCP_SECS;
308     ptmp              = (uint8_t*)(&pDHCPMSG->flags);    
309     *(ptmp+0)         = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
310     *(ptmp+1)         = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
311
312     pDHCPMSG->ciaddr[0] = 0;
313     pDHCPMSG->ciaddr[1] = 0;
314     pDHCPMSG->ciaddr[2] = 0;
315     pDHCPMSG->ciaddr[3] = 0;
316
317     pDHCPMSG->yiaddr[0] = 0;
318     pDHCPMSG->yiaddr[1] = 0;
319     pDHCPMSG->yiaddr[2] = 0;
320     pDHCPMSG->yiaddr[3] = 0;
321
322     pDHCPMSG->siaddr[0] = 0;
323     pDHCPMSG->siaddr[1] = 0;
324     pDHCPMSG->siaddr[2] = 0;
325     pDHCPMSG->siaddr[3] = 0;
326
327     pDHCPMSG->giaddr[0] = 0;
328     pDHCPMSG->giaddr[1] = 0;
329     pDHCPMSG->giaddr[2] = 0;
330     pDHCPMSG->giaddr[3] = 0;
331
332     pDHCPMSG->chaddr[0] = DHCP_CHADDR[0];
333     pDHCPMSG->chaddr[1] = DHCP_CHADDR[1];
334     pDHCPMSG->chaddr[2] = DHCP_CHADDR[2];
335     pDHCPMSG->chaddr[3] = DHCP_CHADDR[3];
336     pDHCPMSG->chaddr[4] = DHCP_CHADDR[4];
337     pDHCPMSG->chaddr[5] = DHCP_CHADDR[5];
338
339     for (i = 6; i < 16; i++)  pDHCPMSG->chaddr[i] = 0;
340     for (i = 0; i < 64; i++)  pDHCPMSG->sname[i]  = 0;
341     for (i = 0; i < 128; i++) pDHCPMSG->file[i]   = 0;
342
343     // MAGIC_COOKIE
344     pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
345     pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
346     pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >>  8);
347     pDHCPMSG->OPT[3] = (uint8_t) (MAGIC_COOKIE & 0x000000FF) >>  0;
348 }
349
350 /* SEND DHCP DISCOVER */
351 void send_DHCP_DISCOVER(void)
352 {
353     uint16_t i;
354     uint8_t ip[4];
355     uint16_t k = 0;
356    
357    makeDHCPMSG();
358
359    k = 4;     // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
360    
361     // Option Request Param
362     pDHCPMSG->OPT[k++] = dhcpMessageType;
363     pDHCPMSG->OPT[k++] = 0x01;
364     pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
365     
366     // Client identifier
367     pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
368     pDHCPMSG->OPT[k++] = 0x07;
369     pDHCPMSG->OPT[k++] = 0x01;
370     pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
371     pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
372     pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
373     pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
374     pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
375     pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
376     
377     // host name
378     pDHCPMSG->OPT[k++] = hostName;
379     pDHCPMSG->OPT[k++] = 0;          // fill zero length of hostname 
380     for(i = 0 ; HOST_NAME[i] != 0; i++)
381        pDHCPMSG->OPT[k++] = HOST_NAME[i];
382     pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
383     pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
384     pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
385     pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname
386
387     pDHCPMSG->OPT[k++] = dhcpParamRequest;
388     pDHCPMSG->OPT[k++] = 0x06;    // length of request
389     pDHCPMSG->OPT[k++] = subnetMask;
390     pDHCPMSG->OPT[k++] = routersOnSubnet;
391     pDHCPMSG->OPT[k++] = dns;
392     pDHCPMSG->OPT[k++] = domainName;
393     pDHCPMSG->OPT[k++] = dhcpT1value;
394     pDHCPMSG->OPT[k++] = dhcpT2value;
395     pDHCPMSG->OPT[k++] = endOption;
396
397     for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
398
399     // send broadcasting packet
400     ip[0] = 255;
401     ip[1] = 255;
402     ip[2] = 255;
403     ip[3] = 255;
404
405 #ifdef _DHCP_DEBUG_
406     printf("> Send DHCP_DISCOVER\r\n");
407 #endif
408
409     sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
410 }
411
412 /* SEND DHCP REQUEST */
413 void send_DHCP_REQUEST(void)
414 {
415     int i;
416     uint8_t ip[4];
417     uint16_t k = 0;
418
419    makeDHCPMSG();
420
421    if(dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
422    {
423        *((uint8_t*)(&pDHCPMSG->flags))   = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
424        *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
425        pDHCPMSG->ciaddr[0] = DHCP_allocated_ip[0];
426        pDHCPMSG->ciaddr[1] = DHCP_allocated_ip[1];
427        pDHCPMSG->ciaddr[2] = DHCP_allocated_ip[2];
428        pDHCPMSG->ciaddr[3] = DHCP_allocated_ip[3];
429        ip[0] = DHCP_SIP[0];
430        ip[1] = DHCP_SIP[1];
431        ip[2] = DHCP_SIP[2];
432        ip[3] = DHCP_SIP[3];                     
433    }
434    else
435    {
436        ip[0] = 255;
437        ip[1] = 255;
438        ip[2] = 255;
439        ip[3] = 255;                     
440    }
441    
442    k = 4;      // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
443     
444     // Option Request Param.
445     pDHCPMSG->OPT[k++] = dhcpMessageType;
446     pDHCPMSG->OPT[k++] = 0x01;
447     pDHCPMSG->OPT[k++] = DHCP_REQUEST;
448
449     pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
450     pDHCPMSG->OPT[k++] = 0x07;
451     pDHCPMSG->OPT[k++] = 0x01;
452     pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
453     pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
454     pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
455     pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
456     pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
457     pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
458
459    if(ip[3] == 255)  // if(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
460    {
461         pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
462         pDHCPMSG->OPT[k++] = 0x04;
463         pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
464         pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
465         pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
466         pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
467     
468         pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
469         pDHCPMSG->OPT[k++] = 0x04;
470         pDHCPMSG->OPT[k++] = DHCP_SIP[0];
471         pDHCPMSG->OPT[k++] = DHCP_SIP[1];
472         pDHCPMSG->OPT[k++] = DHCP_SIP[2];
473         pDHCPMSG->OPT[k++] = DHCP_SIP[3];
474     }
475
476     // host name
477     pDHCPMSG->OPT[k++] = hostName;
478     pDHCPMSG->OPT[k++] = 0; // length of hostname
479     for(i = 0 ; HOST_NAME[i] != 0; i++)
480        pDHCPMSG->OPT[k++] = HOST_NAME[i];
481     pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
482     pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
483     pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
484     pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname
485     
486     pDHCPMSG->OPT[k++] = dhcpParamRequest;
487     pDHCPMSG->OPT[k++] = 0x08;
488     pDHCPMSG->OPT[k++] = subnetMask;
489     pDHCPMSG->OPT[k++] = routersOnSubnet;
490     pDHCPMSG->OPT[k++] = dns;
491     pDHCPMSG->OPT[k++] = domainName;
492     pDHCPMSG->OPT[k++] = dhcpT1value;
493     pDHCPMSG->OPT[k++] = dhcpT2value;
494     pDHCPMSG->OPT[k++] = performRouterDiscovery;
495     pDHCPMSG->OPT[k++] = staticRoute;
496     pDHCPMSG->OPT[k++] = endOption;
497
498     for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
499
500 #ifdef _DHCP_DEBUG_
501     printf("> Send DHCP_REQUEST\r\n");
502 #endif
503     
504     sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
505
506 }
507
508 /* SEND DHCP DHCPDECLINE */
509 void send_DHCP_DECLINE(void)
510 {
511     int i;
512     uint8_t ip[4];
513     uint16_t k = 0;
514     
515     makeDHCPMSG();
516
517    k = 4;      // beacaue MAGIC_COOKIE already made by makeDHCPMSG()
518    
519     *((uint8_t*)(&pDHCPMSG->flags))   = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
520     *((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
521
522     // Option Request Param.
523     pDHCPMSG->OPT[k++] = dhcpMessageType;
524     pDHCPMSG->OPT[k++] = 0x01;
525     pDHCPMSG->OPT[k++] = DHCP_DECLINE;
526
527     pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
528     pDHCPMSG->OPT[k++] = 0x07;
529     pDHCPMSG->OPT[k++] = 0x01;
530     pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
531     pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
532     pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
533     pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
534     pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
535     pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
536
537     pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
538     pDHCPMSG->OPT[k++] = 0x04;
539     pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
540     pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
541     pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
542     pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
543
544     pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
545     pDHCPMSG->OPT[k++] = 0x04;
546     pDHCPMSG->OPT[k++] = DHCP_SIP[0];
547     pDHCPMSG->OPT[k++] = DHCP_SIP[1];
548     pDHCPMSG->OPT[k++] = DHCP_SIP[2];
549     pDHCPMSG->OPT[k++] = DHCP_SIP[3];
550
551     pDHCPMSG->OPT[k++] = endOption;
552
553     for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
554
555     //send broadcasting packet
556     ip[0] = 0xFF;
557     ip[1] = 0xFF;
558     ip[2] = 0xFF;
559     ip[3] = 0xFF;
560
561 #ifdef _DHCP_DEBUG_
562     printf("\r\n> Send DHCP_DECLINE\r\n");
563 #endif
564
565     sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
566 }
567
568 /* PARSE REPLY pDHCPMSG */
569 int8_t parseDHCPMSG(void)
570 {
571     uint8_t svr_addr[6];
572     uint16_t  svr_port;
573     uint16_t len;
574
575     uint8_t * p;
576     uint8_t * e;
577     uint8_t type;
578     uint8_t opt_len;
579    
580    if((len = getSn_RX_RSR(DHCP_SOCKET)) > 0)
581    {
582        len = recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
583    #ifdef _DHCP_DEBUG_   
584       printf("DHCP message : %d.%d.%d.%d(%d) %d received. \r\n",svr_addr[0],svr_addr[1],svr_addr[2], svr_addr[3],svr_port, len);
585    #endif   
586    }
587    else return 0;
588     if (svr_port == DHCP_SERVER_PORT) {
589       // compare mac address
590         if ( (pDHCPMSG->chaddr[0] != DHCP_CHADDR[0]) || (pDHCPMSG->chaddr[1] != DHCP_CHADDR[1]) ||
591              (pDHCPMSG->chaddr[2] != DHCP_CHADDR[2]) || (pDHCPMSG->chaddr[3] != DHCP_CHADDR[3]) ||
592              (pDHCPMSG->chaddr[4] != DHCP_CHADDR[4]) || (pDHCPMSG->chaddr[5] != DHCP_CHADDR[5])   )
593          return 0;
594       type = 0;
595         p = (uint8_t *)(&pDHCPMSG->op);
596         p = p + 240;      // 240 = sizeof(RIP_MSG) + MAGIC_COOKIE size in RIP_MSG.opt - sizeof(RIP_MSG.opt)
597         e = p + (len - 240);
598
599         while ( p < e ) {
600
601             switch ( *p ) {
602
603                case endOption :
604                   p = e;   // for break while(p < e)
605                    break;
606             case padOption :
607                    p++;
608                    break;
609                case dhcpMessageType :
610                    p++;
611                    p++;
612                    type = *p++;
613                    break;
614                case subnetMask :
615                    p++;
616                    p++;
617                    DHCP_allocated_sn[0] = *p++;
618                    DHCP_allocated_sn[1] = *p++;
619                    DHCP_allocated_sn[2] = *p++;
620                    DHCP_allocated_sn[3] = *p++;
621                    break;
622                case routersOnSubnet :
623                    p++;
624                    opt_len = *p++;       
625                    DHCP_allocated_gw[0] = *p++;
626                    DHCP_allocated_gw[1] = *p++;
627                    DHCP_allocated_gw[2] = *p++;
628                    DHCP_allocated_gw[3] = *p++;
629                    p = p + (opt_len - 4);
630                    break;
631                case dns :
632                    p++;                  
633                    opt_len = *p++;       
634                    DHCP_allocated_dns[0] = *p++;
635                    DHCP_allocated_dns[1] = *p++;
636                    DHCP_allocated_dns[2] = *p++;
637                    DHCP_allocated_dns[3] = *p++;
638                    p = p + (opt_len - 4);
639                    break;
640                case dhcpIPaddrLeaseTime :
641                    p++;
642                    opt_len = *p++;
643                    dhcp_lease_time  = *p++;
644                    dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
645                    dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
646                    dhcp_lease_time  = (dhcp_lease_time << 8) + *p++;
647             #ifdef _DHCP_DEBUG_  
648                dhcp_lease_time = 10;
649                  #endif
650                    break;
651                case dhcpServerIdentifier :
652                    p++;
653                    opt_len = *p++;
654                    DHCP_SIP[0] = *p++;
655                    DHCP_SIP[1] = *p++;
656                    DHCP_SIP[2] = *p++;
657                    DHCP_SIP[3] = *p++;
658                    break;
659                default :
660                    p++;
661                    opt_len = *p++;
662                    p += opt_len;
663                    break;
664             } // switch
665         } // while
666     } // if
667     return    type;
668 }
669
670 uint8_t DHCP_run(void)
671 {
672     uint8_t  type;
673     uint8_t  ret;
674
675     if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;
676
677     if(getSn_SR(DHCP_SOCKET) != SOCK_UDP)
678        socket(DHCP_SOCKET, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);
679
680     ret = DHCP_RUNNING;
681     type = parseDHCPMSG();
682
683     switch ( dhcp_state ) {
684        case STATE_DHCP_INIT     :
685          DHCP_allocated_ip[0] = 0;
686          DHCP_allocated_ip[1] = 0;
687          DHCP_allocated_ip[2] = 0;
688          DHCP_allocated_ip[3] = 0;
689            send_DHCP_DISCOVER();
690            dhcp_state = STATE_DHCP_DISCOVER;
691            break;
692         case STATE_DHCP_DISCOVER :
693             if (type == DHCP_OFFER){
694 #ifdef _DHCP_DEBUG_
695                 printf("> Receive DHCP_OFFER\r\n");
696 #endif
697             DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
698             DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
699             DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
700             DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];
701
702                 send_DHCP_REQUEST();
703                 dhcp_state = STATE_DHCP_REQUEST;
704             } else ret = check_DHCP_timeout();
705          break;
706
707         case STATE_DHCP_REQUEST :
708             if (type == DHCP_ACK) {
709
710 #ifdef _DHCP_DEBUG_
711                 printf("> Receive DHCP_ACK\r\n");
712 #endif
713                 if (check_DHCP_leasedIP()) {
714                     // Network info assignment from DHCP
715                     dhcp_ip_assign();
716                     reset_DHCP_timeout();
717
718                     dhcp_state = STATE_DHCP_LEASED;
719                 } else {
720                     // IP address conflict occurred
721                     reset_DHCP_timeout();
722                     dhcp_ip_conflict();
723                     dhcp_state = STATE_DHCP_INIT;
724                 }
725             } else if (type == DHCP_NAK) {
726
727 #ifdef _DHCP_DEBUG_
728                 printf("> Receive DHCP_NACK\r\n");
729 #endif
730
731                 reset_DHCP_timeout();
732
733                 dhcp_state = STATE_DHCP_DISCOVER;
734             } else ret = check_DHCP_timeout();
735         break;
736
737         case STATE_DHCP_LEASED :
738            ret = DHCP_IP_LEASED;
739             if ((dhcp_lease_time != INFINITE_LEASETIME) && ((dhcp_lease_time/2) < dhcp_tick_1s)) {
740                 
741 #ifdef _DHCP_DEBUG_
742                  printf("> Maintains the IP address \r\n");
743 #endif
744
745                 type = 0;
746                 OLD_allocated_ip[0] = DHCP_allocated_ip[0];
747                 OLD_allocated_ip[1] = DHCP_allocated_ip[1];
748                 OLD_allocated_ip[2] = DHCP_allocated_ip[2];
749                 OLD_allocated_ip[3] = DHCP_allocated_ip[3];
750                 
751                 DHCP_XID++;
752
753                 send_DHCP_REQUEST();
754
755                 reset_DHCP_timeout();
756
757                 dhcp_state = STATE_DHCP_REREQUEST;
758             }
759         break;
760
761         case STATE_DHCP_REREQUEST :
762            ret = DHCP_IP_LEASED;
763             if (type == DHCP_ACK) {
764                 dhcp_retry_count = 0;
765                 if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || 
766                     OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
767                     OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
768                     OLD_allocated_ip[3] != DHCP_allocated_ip[3]) 
769                 {
770                     ret = DHCP_IP_CHANGED;
771                     dhcp_ip_update();
772                #ifdef _DHCP_DEBUG_
773                   printf(">IP changed.\r\n");
774                #endif
775                     
776                 }
777          #ifdef _DHCP_DEBUG_
778             else printf(">IP is continued.\r\n");
779          #endif                            
780                 reset_DHCP_timeout();
781                 dhcp_state = STATE_DHCP_LEASED;
782             } else if (type == DHCP_NAK) {
783
784 #ifdef _DHCP_DEBUG_
785                 printf("> Receive DHCP_NACK, Failed to maintain ip\r\n");
786 #endif
787
788                 reset_DHCP_timeout();
789
790                 dhcp_state = STATE_DHCP_DISCOVER;
791             } else ret = check_DHCP_timeout();
792            break;
793         default :
794            break;
795     }
796
797     return ret;
798 }
799
800 void    DHCP_stop(void)
801 {
802    close(DHCP_SOCKET);
803    dhcp_state = STATE_DHCP_STOP;
804 }
805
806 uint8_t check_DHCP_timeout(void)
807 {
808     uint8_t ret = DHCP_RUNNING;
809     
810     if (dhcp_retry_count < MAX_DHCP_RETRY) {
811         if (dhcp_tick_next < dhcp_tick_1s) {
812
813             switch ( dhcp_state ) {
814                 case STATE_DHCP_DISCOVER :
815 //                    printf("<<timeout>> state : STATE_DHCP_DISCOVER\r\n");
816                     send_DHCP_DISCOVER();
817                 break;
818         
819                 case STATE_DHCP_REQUEST :
820 //                    printf("<<timeout>> state : STATE_DHCP_REQUEST\r\n");
821
822                     send_DHCP_REQUEST();
823                 break;
824
825                 case STATE_DHCP_REREQUEST :
826 //                    printf("<<timeout>> state : STATE_DHCP_REREQUEST\r\n");
827                     
828                     send_DHCP_REQUEST();
829                 break;
830         
831                 default :
832                 break;
833             }
834
835             dhcp_tick_1s = 0;
836             dhcp_tick_next = dhcp_tick_1s + DHCP_WAIT_TIME;
837             dhcp_retry_count++;
838         }
839     } else { // timeout occurred
840
841         switch(dhcp_state) {
842             case STATE_DHCP_DISCOVER:
843                 dhcp_state = STATE_DHCP_INIT;
844                 ret = DHCP_FAILED;
845                 break;
846             case STATE_DHCP_REQUEST:
847             case STATE_DHCP_REREQUEST:
848                 send_DHCP_DISCOVER();
849                 dhcp_state = STATE_DHCP_DISCOVER;
850                 break;
851             default :
852                 break;
853         }
854         reset_DHCP_timeout();
855     }
856     return ret;
857 }
858
859 int8_t check_DHCP_leasedIP(void)
860 {
861     uint8_t tmp;
862     int32_t ret;
863
864     //WIZchip RCR value changed for ARP Timeout count control
865     tmp = getRCR();
866     setRCR(0x03);
867
868     // IP conflict detection : ARP request - ARP reply
869     // Broadcasting ARP Request for check the IP conflict using UDP sendto() function
870     ret = sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000);
871
872     // RCR value restore
873     setRCR(tmp);
874
875     if(ret == SOCKERR_TIMEOUT) {
876         // UDP send Timeout occurred : allocated IP address is unique, DHCP Success
877
878 #ifdef _DHCP_DEBUG_
879         printf("\r\n> Check leased IP - OK\r\n");
880 #endif
881
882         return 1;
883     } else {
884         // Received ARP reply or etc : IP address conflict occur, DHCP Failed
885         send_DHCP_DECLINE();
886
887         ret = dhcp_tick_1s;
888         while((dhcp_tick_1s - ret) < 2) ;   // wait for 1s over; wait to complete to send DECLINE message;
889
890         return 0;
891     }
892 }    
893
894 void DHCP_init(uint8_t s, uint8_t * buf)
895 {
896    uint8_t zeroip[4] = {0,0,0,0};
897    getSHAR(DHCP_CHADDR);
898    if((DHCP_CHADDR[0] | DHCP_CHADDR[1]  | DHCP_CHADDR[2] | DHCP_CHADDR[3] | DHCP_CHADDR[4] | DHCP_CHADDR[5]) == 0x00)
899    {
900       // assing temporary mac address, you should be set SHAR before call this function. 
901       DHCP_CHADDR[0] = 0x00;
902       DHCP_CHADDR[1] = 0x08;
903       DHCP_CHADDR[2] = 0xdc;      
904       DHCP_CHADDR[3] = 0x00;
905       DHCP_CHADDR[4] = 0x00;
906       DHCP_CHADDR[5] = 0x00; 
907       setSHAR(DHCP_CHADDR);     
908    }
909
910     DHCP_SOCKET = s; // SOCK_DHCP
911     pDHCPMSG = (RIP_MSG*)buf;
912     DHCP_XID = 0x12345678;
913
914     // WIZchip Netinfo Clear
915     setSIPR(zeroip);
916     setSIPR(zeroip);
917     setGAR(zeroip);
918
919     reset_DHCP_timeout();
920     dhcp_state = STATE_DHCP_INIT;
921 }
922
923
924 /* Rset the DHCP timeout count and retry count. */
925 void reset_DHCP_timeout(void)
926 {
927     dhcp_tick_1s = 0;
928     dhcp_tick_next = DHCP_WAIT_TIME;
929     dhcp_retry_count = 0;
930 }
931
932 void DHCP_time_handler(void)
933 {
934     dhcp_tick_1s++;
935 }
936
937 void getIPfromDHCP(uint8_t* ip)
938 {
939     ip[0] = DHCP_allocated_ip[0];
940     ip[1] = DHCP_allocated_ip[1];
941     ip[2] = DHCP_allocated_ip[2];    
942     ip[3] = DHCP_allocated_ip[3];
943 }
944
945 void getGWfromDHCP(uint8_t* ip)
946 {
947     ip[0] =DHCP_allocated_gw[0];
948     ip[1] =DHCP_allocated_gw[1];
949     ip[2] =DHCP_allocated_gw[2];
950     ip[3] =DHCP_allocated_gw[3];            
951 }
952
953 void getSNfromDHCP(uint8_t* ip)
954 {
955    ip[0] = DHCP_allocated_sn[0];
956    ip[1] = DHCP_allocated_sn[1];
957    ip[2] = DHCP_allocated_sn[2];
958    ip[3] = DHCP_allocated_sn[3];         
959 }
960
961 void getDNSfromDHCP(uint8_t* ip)
962 {
963    ip[0] = DHCP_allocated_dns[0];
964    ip[1] = DHCP_allocated_dns[1];
965    ip[2] = DHCP_allocated_dns[2];
966    ip[3] = DHCP_allocated_dns[3];         
967 }
968
969 uint32_t getDHCPLeasetime(void)
970 {
971     return dhcp_lease_time;
972 }
973
974
975
976