23423952a83cf88e8c86cac042c4ce72c04b8e15
Stefan Schuermans header fix

Stefan Schuermans authored 12 years ago

1) /* flaneth - flash and ethernet
Stefan Schuermans change email address in hea...

Stefan Schuermans authored 12 years ago

2)    Copyright (C) 2007-2012 Stefan Schuermans <stefan@blinkenarea.org>
Stefan Schuermans header fix

Stefan Schuermans authored 12 years ago

3)    Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
4)    a BlinkenArea project - http://www.blinkenarea.org/ */
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

5) 
6) #include <string.h>
7) 
8) #include "config.h"
9) #include "checksum.h"
10) #include "debug.h"
11) #include "dhcp.h"
12) #include "ethernet.h"
13) #include "ip.h"
14) #include "macros.h"
15) #include "nethelp.h"
16) #include "random.h"
17) #include "udp.h"
18) 
19) // configuration
20) static const unsigned char DhcpRetrySecsMax = 10;       // avarage timeout
21)                                                         // after which to
22)                                                         // retry DHCP action
23) static const unsigned char DhcpRetriesMax = 5;  // maximum number of retries
24)                                                 // before aborting DHCP
25)                                                 // action
26) static const unsigned long DhcpLeaseRestMin = 300;      // when to ask to
27)                                                         // extend lease
28) static const unsigned char DhcpLeaseRenewFraction = 8;  // to renw lease when 
29)                                                         // only this fraction 
30)                                                         // of lease is left
31) 
32) // DHCP tick counter to get full seconds
33) static unsigned char DhcpTicks = 0;
34) 
35) // time of current DHCP action
36) static unsigned char DhcpInProgress = 0;        // if DHCP action is in
37)                                                 // progress
38) static unsigned char DhcpRetries = 0;   // number of retries left
39) static unsigned char DhcpRetrySecs = 0; // rest of time for current retry
40) 
41) // current XId
42) static unsigned char DhcpHaveXId = 0;   // if an XId exists at the moment
43) static unsigned long DhcpXId = 0;       // the current XId data
44) static unsigned int DhcpXIdSecs = 0;    // time of XId
45) 
46) // DHCP server and lease time
47) static unsigned char DhcpActive = 0;    // if own IP is leased from DHCP
48) static unsigned char DhcpServer[4];     // IP address of DHCP server own IP
49)                                         // is leased from
50) static unsigned long DhcpLeaseTime = 0; // total lease time
51) static unsigned long DhcpLeaseRest = 0; // rest of lease time
52) 
53) // send a DHCP packet
54) // pData must point to a struct DhcpPacket with IpHdr.Dest, DhcpHdr.XId
55) // DhcpHdr.Secs, DhcpHdr.Flags and DhcpHdr.YIAddr already initialized
56) static void DhcpSend(unsigned char *pData, unsigned short Length)       // (extern)
57) {
58)   struct DhcpPacket *pDhcpPack;
59) 
60)   // packet too short
61)   if (Length < sizeof(struct DhcpPacket))
62)     return;
63) 
64)   // convert pointer to DHCP packet
65)   // (this saves us from always casting pData)
66)   pDhcpPack = (struct DhcpPacket *)pData;
67) 
68)   debug_dhcp_printf("send xid=%08lX len=%d",
69)                     ntohl(pDhcpPack->DhcpHdr.XId), Length);
70) 
71)   // we are DHCP client
72)   // - source port must be 68
73)   // - destination port must be 67
74)   pDhcpPack->UdpHdr.SrcPort = htons(68);
75)   pDhcpPack->UdpHdr.DestPort = htons(67);
76)   // set up DHCP header fields as client
77)   pDhcpPack->DhcpHdr.Op = 1;
78)   pDhcpPack->DhcpHdr.HType = 1;
79)   pDhcpPack->DhcpHdr.HLen = 6;
80)   pDhcpPack->DhcpHdr.HOps = 0;
81)   memset(pDhcpPack->DhcpHdr.CIAddr, 0, 4);
82)   memset(pDhcpPack->DhcpHdr.SIAddr, 0, 4);
83)   memset(pDhcpPack->DhcpHdr.GIAddr, 0, 4);
84)   mac_cpy(pDhcpPack->DhcpHdr.CHAddr, ConfigMac);
85)   memset(pDhcpPack->DhcpHdr.CHAddr + 6, 0, 10);
86)   memset(pDhcpPack->DhcpHdr.SName, 0, 64);
87)   memset(pDhcpPack->DhcpHdr.File, 0, 128);
88)   pDhcpPack->DhcpHdr.MCookie = htonl(0x63825363);
89) 
90)   // send DHCP packet
91)   UdpSend(pData, Length);
92) }
93) 
94) // send a DHCP discover
95) static void DhcpDiscover(void)
96) {
97)   struct {
98)     struct DhcpPacket DhcpPack;
99)     unsigned char OptType[3];
100)     unsigned char OptEnd[2];
101)   } DhcpDiscover;
102) 
103)   debug_dhcp_printf("discover");
104) 
105)   ip_cpy(DhcpDiscover.DhcpPack.IpHdr.Dest, "\xFF\xFF\xFF\xFF"); // broadcast
106)   DhcpDiscover.DhcpPack.DhcpHdr.XId = htonl(DhcpXId);
107)   DhcpDiscover.DhcpPack.DhcpHdr.Secs = htons(DhcpXIdSecs);      // use time
108)                                                                 // of XId
109)   DhcpDiscover.DhcpPack.DhcpHdr.Flags = htons(0x8000);  // broadcast
110)   memset(DhcpDiscover.DhcpPack.DhcpHdr.YIAddr, 0, 4);
111)   DhcpDiscover.OptType[0] = 0x35;       // DHCP discover
112)   DhcpDiscover.OptType[1] = 0x01;
113)   DhcpDiscover.OptType[2] = 0x01;
114)   DhcpDiscover.OptEnd[0] = 0xFF;        // end of options
115)   DhcpDiscover.OptEnd[1] = 0x00;
116) 
117)   DhcpSend((unsigned char *)&DhcpDiscover, sizeof(DhcpDiscover));
118) }
119) 
120) // send a DHCP request
121) static void DhcpRequest(void)
122) {
123)   struct {
124)     struct DhcpPacket DhcpPack;
125)     unsigned char OptType[3];
126)     unsigned char OptReq[6];
127)     unsigned char OptServer[6];
128)     unsigned char OptEnd[2];
129)   } DhcpRequest;
130) 
131)   debug_dhcp_printf("request ip=%d.%d.%d.%d",
132)                     ConfigIp[0], ConfigIp[1], ConfigIp[2], ConfigIp[3]);
133) 
134)   ip_cpy(DhcpRequest.DhcpPack.IpHdr.Dest, DhcpServer);  // send to DHCP
135)                                                         // server
136)   DhcpRequest.DhcpPack.DhcpHdr.XId = htonl(DhcpXId);
137)   DhcpRequest.DhcpPack.DhcpHdr.Secs = htons(DhcpXIdSecs);       // use time
138)                                                                 // of XId
139)   DhcpRequest.DhcpPack.DhcpHdr.Flags = htons(0x0000);
140)   ip_cpy(DhcpRequest.DhcpPack.DhcpHdr.YIAddr, ConfigIp);
141)   DhcpRequest.OptType[0] = 0x35;        // DHCP request
142)   DhcpRequest.OptType[1] = 0x01;
143)   DhcpRequest.OptType[2] = 0x03;
144)   DhcpRequest.OptReq[0] = 0x32; // requested IP
145)   DhcpRequest.OptReq[1] = 0x04;
146)   ip_cpy(&DhcpRequest.OptReq[2], ConfigIp);
147)   DhcpRequest.OptServer[0] = 0x36;      // DHCP server
148)   DhcpRequest.OptServer[1] = 0x04;
149)   ip_cpy(&DhcpRequest.OptServer[2], DhcpServer);
150)   DhcpRequest.OptEnd[0] = 0xFF; // end of options
151)   DhcpRequest.OptEnd[1] = 0x00;
152) 
153)   DhcpSend((unsigned char *)&DhcpRequest, sizeof(DhcpRequest));
154) }
155) 
156) // abort DHCP action
157) static void DhcpAbort(void)
158) {
159)   // abort DHCP action
160)   DhcpInProgress = 0;
161)   DhcpRetries = 0;
162)   DhcpRetrySecs = 0;
163) 
164)   // forget XId
165)   DhcpHaveXId = 0;
166)   DhcpXId = 0;
167)   DhcpXIdSecs = 0;
168) 
169)   // give up IP address if it was leased
170)   if (DhcpActive) {
171)     ip_cpy(ConfigIp, "\0\0\0\0");
172)     ip_cpy(ConfigMask, "\0\0\0\0");
173)     ip_cpy(ConfigGw, "\0\0\0\0");
174)     DhcpActive = 0;
175)     DhcpLeaseTime = 0;
176)     DhcpLeaseRest = 0;
177)   }
178) }
179) 
180) // retry DHCP action
181) static void DhcpRetry(void)
182) {
183)   // DHCP lease not active ---> re-send DHCP discover
184)   if (!DhcpActive) {
185) 
186)     // get time for next try
187)     RandomGetData((unsigned char *)&DhcpRetrySecs, sizeof(DhcpRetrySecs));
188)     DhcpRetrySecs = DhcpRetrySecs % DhcpRetrySecsMax + DhcpRetrySecsMax / 2;
189)     // re-send DHCP discover
190)     DhcpDiscover();
191) 
192)   }
193)   // DHCP lease active and lease time almost over ---> re-send DHCP request
194)   if (DhcpActive && (DhcpLeaseRest < DhcpLeaseRestMin ||
195)                      DhcpLeaseRest <
196)                      DhcpLeaseTime / DhcpLeaseRenewFraction)) {
197) 
198)     // get time for next try
199)     RandomGetData((unsigned char *)&DhcpRetrySecs, sizeof(DhcpRetrySecs));
200)     DhcpRetrySecs = DhcpRetrySecs % DhcpRetrySecsMax + DhcpRetrySecsMax / 2;
201)     // re-send DHCP request
202)     DhcpRequest();
203) 
204)   }
205) }
206) 
207) // start new DHCP action
208) static void DhcpStart(void)
209) {
210)   // DHCP lease not active ---> DHCP discover
211)   if (!DhcpActive) {
212) 
213)     // DHCP operation starts
214)     DhcpInProgress = 1;
215)     DhcpRetries = DhcpRetriesMax;
216)     RandomGetData((unsigned char *)&DhcpRetrySecs, sizeof(DhcpRetrySecs));
217)     DhcpRetrySecs = DhcpRetrySecs % DhcpRetrySecsMax + DhcpRetrySecsMax / 2;
218)     // get new XId
219)     RandomGetData((unsigned char *)&DhcpXId, sizeof(DhcpXId));
220)     DhcpXIdSecs++;
221)     DhcpHaveXId = 1;
222)     // send DHCP discover
223)     DhcpDiscover();
224) 
225)   }
226)   // DHCP lease active and lease time almost over ---> DHCP request
227)   if (DhcpActive && (DhcpLeaseRest < DhcpLeaseRestMin ||
228)                      DhcpLeaseRest <
229)                      DhcpLeaseTime / DhcpLeaseRenewFraction)) {
230) 
231)     // DHCP operation starts
232)     DhcpInProgress = 1;
233)     DhcpRetries = DhcpRetriesMax;
234)     RandomGetData((unsigned char *)&DhcpRetrySecs, sizeof(DhcpRetrySecs));
235)     DhcpRetrySecs = DhcpRetrySecs % DhcpRetrySecsMax + DhcpRetrySecsMax / 2;
236)     // get new XId if none available
237)     if (!DhcpHaveXId) {
238)       RandomGetData((unsigned char *)&DhcpXId, sizeof(DhcpXId));
239)       DhcpXIdSecs++;
240)       DhcpHaveXId = 1;
241)     }
242)     // send DHCP request
243)     DhcpRequest();
244) 
245)   }
246) }
247) 
248) // tick procedure - every 1000ms
249) static void DhcpTick1000(void)
250) {
251)   // DHCP operation in progress
252)   if (DhcpInProgress) {
253) 
254)     // count down time of current try of current action
255)     DhcpRetrySecs--;
256)     if (DhcpRetrySecs <= 0) {
257) 
258)       // count down retries
259)       DhcpRetries--;
260) 
261)       // no more retries left ---> abort, retry otherwise
262)       if (DhcpRetries <= 0)
263)         DhcpAbort();
264)       else
265)         DhcpRetry();
266) 
267)     }
268) 
269)   }
270)   // increase time of XId
271)   DhcpXIdSecs++;
272) 
273)   // dcrease remaining lease time
274)   DhcpLeaseRest--;
275)   // lease timed out ---> abort DHCP (will also invalidate IP)
276)   if (DhcpLeaseRest <= 0) {
277)     debug_dhcp_printf("lease expired");
278)     DhcpAbort();
279)   }
280) }
281) 
282) // tick procedure - call every 200ms
283) void DhcpTick200(void)  // (extern)
284) {
285)   // get 1 second interval
286)   DhcpTicks++;
287)   if (DhcpTicks >= 5) {
288)     DhcpTicks = 0;
289)     DhcpTick1000();
290)   }
291)   // no DHCP operation in progress
292)   if (!DhcpInProgress) {
293)     // DHCP lease active or no IP address ---> DHCP allowed (i.e. no static
294)     // IP)
295)     if (DhcpActive || ip_eq(ConfigIp, "\0\0\0\0")) {
296)       // start new DHCP action
297)       DhcpStart();
298)     }
299)   }
300) }
301) 
302) // process a received DHCP offer
303) static void DhcpOffer(unsigned char addr[4], unsigned char mask[4],
304)                       unsigned char gateway[4], unsigned long time,
305)                       unsigned char server[4])
306) {
307)   debug_dhcp_printf("offer addr=%d.%d.%d.%d mask=%d.%d.%d.%d gw=%d.%d.%d.%d",
308)                     addr[0], addr[1], addr[2], addr[3],
309)                     mask[0], mask[1], mask[2], mask[3],
310)                     gateway[0], gateway[1], gateway[2], gateway[3]);
311)   debug_dhcp_printf("offer time=%ld server=%d.%d.%d.%d",
312)                     time, server[0], server[1], server[2], server[3]);
313) 
314)   // use this IP address, mask and gateway
315)   ip_cpy(ConfigIp, addr);
316)   ip_cpy(ConfigMask, mask);
317)   ip_cpy(ConfigGw, gateway);
318) 
319)   // store DHCP server and lease time
320)   DhcpActive = 1;
321)   ip_cpy(DhcpServer, server);
322)   DhcpLeaseTime = time;
323)   DhcpLeaseRest = DhcpLeaseRestMin;     // schedule DHCP request
324) 
325)   // DHCP action finished
326)   DhcpInProgress = 0;
327)   DhcpRetries = 0;
328)   DhcpRetrySecs = 0;
329) }
330) 
331) // process a received DHCP ack
332) static void DhcpAck(unsigned char addr[4], unsigned char mask[4],
333)                     unsigned char gateway[4], unsigned long time,
334)                     unsigned char server[4])
335) {
336)   debug_dhcp_printf("ack addr=%d.%d.%d.%d mask=%d.%d.%d.%d gw=%d.%d.%d.%d",
337)                     addr[0], addr[1], addr[2], addr[3],
338)                     mask[0], mask[1], mask[2], mask[3],
339)                     gateway[0], gateway[1], gateway[2], gateway[3]);
340)   debug_dhcp_printf("ack time=%ld server=%d.%d.%d.%d",
341)                     time, server[0], server[1], server[2], server[3]);
342) 
343)   // check if IP address, mask and gateway match
344)   if (!ip_eq(ConfigIp, addr) ||
345)       !ip_eq(ConfigMask, mask) || !ip_eq(ConfigGw, gateway)) {
346)     // mismatch ---> something is wrong, abort
347)     DhcpAbort();
348)     return;
349)   }
350)   // store DHCP server and lease time
351)   DhcpActive = 1;
352)   ip_cpy(DhcpServer, server);
353)   DhcpLeaseTime = time;
354)   DhcpLeaseRest = time;
355) 
356)   // DHCP action finished
357)   DhcpInProgress = 0;
358)   DhcpRetries = 0;
359)   DhcpRetrySecs = 0;
360) 
361)   // forget XId
362)   DhcpHaveXId = 0;
363)   DhcpXId = 0;
364)   DhcpXIdSecs = 0;
365) }
366) 
367) // process a received DHCP packet
368) void DhcpRecv(unsigned char *pData, unsigned short Length)      // (extern)
369) {
370)   struct DhcpPacket *pDhcpPack;
371)   unsigned char *opt_ptr, tag, len;
372)   unsigned short opt_len;
373)   unsigned char type;
374)   unsigned char have_mask, mask[4], have_gateway, gateway[4];
375)   unsigned char have_time, have_server, server[4];
376)   unsigned long time;
377) 
378)   // packet too short
379)   if (Length < sizeof(struct DhcpPacket))
380)     return;
381) 
382)   // convert pointer to UDP packet
383)   // (this saves us from always casting pData)
384)   pDhcpPack = (struct DhcpPacket *)pData;
385) 
386)   // we are DHCP client
387)   // - source port must be 67
388)   // - destination port must be 68
389)   if (pDhcpPack->UdpHdr.SrcPort != htons(67) ||
390)       pDhcpPack->UdpHdr.DestPort != htons(68))
391)     return;
392)   // check DHCP fields
393)   if (pDhcpPack->DhcpHdr.Op != 2 ||
394)       pDhcpPack->DhcpHdr.HType != 1 ||
395)       pDhcpPack->DhcpHdr.HLen != 6 ||
396)       pDhcpPack->DhcpHdr.HOps != 0 ||
397)       pDhcpPack->DhcpHdr.MCookie != htonl(0x63825363))
398)     return;
399) 
400)   debug_dhcp_printf("recv xid=%08lX len=%d",
401)                     ntohl(pDhcpPack->DhcpHdr.XId), Length);
402) 
403)   // check XId
404)   if (!DhcpHaveXId || ntohl(pDhcpPack->DhcpHdr.XId) != DhcpXId)
405)     return;
406) 
407)   // get options
408)   opt_ptr = pData + sizeof(struct DhcpPacket);
409)   opt_len = Length - sizeof(struct DhcpPacket);
410) 
411)   // parse options
412)   type = 0;
413)   have_mask = 0;
414)   have_gateway = 0;
415)   time = 0;
416)   have_time = 0;
417)   have_server = 0;
418)   while (opt_len > 2) {
419) 
420)     // get tag and length
421)     tag = *opt_ptr++;
422)     len = *opt_ptr++;
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

423)     if (opt_len < 2 + (unsigned short)len)