Skip to content

Commit a42dc0b

Browse files
committed
Fix for issue 62, adding DHCP support. New begin() method added to EthernetClass which takes just a MAC address and gets the rest of its configuration information via DHCP. Examples updated to use the IPAddress class and some have been changed to get their config via DHCP.
1 parent 5caad5b commit a42dc0b

File tree

18 files changed

+661
-73
lines changed

18 files changed

+661
-73
lines changed

libraries/Ethernet/Client.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ uint16_t Client::_srcport = 1024;
1616
Client::Client(uint8_t sock) : _sock(sock) {
1717
}
1818

19-
Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) {
19+
Client::Client(IPAddress& ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) {
2020
}
2121

2222
uint8_t Client::connect() {
@@ -38,7 +38,7 @@ uint8_t Client::connect() {
3838
if (_srcport == 0) _srcport = 1024;
3939
socket(_sock, SnMR::TCP, _srcport, 0);
4040

41-
if (!::connect(_sock, _ip, _port)) {
41+
if (!::connect(_sock, _ip.raw_address(), _port)) {
4242
_sock = MAX_SOCK_NUM;
4343
return 0;
4444
}

libraries/Ethernet/Client.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ class Client : public Stream {
77

88
public:
99
Client();
10-
Client(uint8_t);
11-
Client(uint8_t *, uint16_t);
10+
Client(uint8_t sock);
11+
Client(IPAddress& ip, uint16_t port);
1212

1313
uint8_t status();
1414
uint8_t connect();
@@ -31,7 +31,7 @@ class Client : public Stream {
3131
private:
3232
static uint16_t _srcport;
3333
uint8_t _sock;
34-
uint8_t *_ip;
34+
IPAddress _ip;
3535
uint16_t _port;
3636
};
3737

libraries/Ethernet/Dhcp.cpp

+341
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
// DHCP Library v0.3 - April 25, 2009
2+
// Author: Jordan Terrell - blog.jordanterrell.com
3+
4+
#include "w5100.h"
5+
6+
#include <string.h>
7+
#include <stdlib.h>
8+
#include "Dhcp.h"
9+
#include "wiring.h"
10+
#include "util.h"
11+
12+
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
13+
{
14+
uint8_t dhcp_state = STATE_DHCP_START;
15+
uint8_t messageType = 0;
16+
17+
// zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
18+
memset(_dhcpMacAddr, 0, 26);
19+
20+
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
21+
22+
// Pick an initial transaction ID
23+
_dhcpTransactionId = random(1UL, 2000UL);
24+
_dhcpInitialTransactionId = _dhcpTransactionId;
25+
26+
if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
27+
{
28+
// Couldn't get a socket
29+
return 0;
30+
}
31+
32+
presend_DHCP();
33+
34+
int result = 0;
35+
36+
unsigned long startTime = millis();
37+
38+
while(dhcp_state != STATE_DHCP_LEASED)
39+
{
40+
if(dhcp_state == STATE_DHCP_START)
41+
{
42+
_dhcpTransactionId++;
43+
44+
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
45+
dhcp_state = STATE_DHCP_DISCOVER;
46+
}
47+
else if(dhcp_state == STATE_DHCP_DISCOVER)
48+
{
49+
uint32_t respId;
50+
messageType = parseDHCPResponse(responseTimeout, respId);
51+
if(messageType == DHCP_OFFER)
52+
{
53+
// We'll use the transaction ID that the offer came with,
54+
// rather than the one we were up to
55+
_dhcpTransactionId = respId;
56+
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
57+
dhcp_state = STATE_DHCP_REQUEST;
58+
}
59+
}
60+
else if(dhcp_state == STATE_DHCP_REQUEST)
61+
{
62+
uint32_t respId;
63+
messageType = parseDHCPResponse(responseTimeout, respId);
64+
if(messageType == DHCP_ACK)
65+
{
66+
dhcp_state = STATE_DHCP_LEASED;
67+
result = 1;
68+
}
69+
else if(messageType == DHCP_NAK)
70+
dhcp_state = STATE_DHCP_START;
71+
}
72+
73+
if(messageType == 255)
74+
{
75+
messageType = 0;
76+
dhcp_state = STATE_DHCP_START;
77+
}
78+
79+
if(result != 1 && ((millis() - startTime) > timeout))
80+
break;
81+
}
82+
83+
// We're done with the socket now
84+
_dhcpUdpSocket.stop();
85+
_dhcpTransactionId++;
86+
87+
return result;
88+
}
89+
90+
void DhcpClass::presend_DHCP()
91+
{
92+
}
93+
94+
void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
95+
{
96+
uint8_t buffer[32];
97+
memset(buffer, 0, 32);
98+
IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address
99+
100+
if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
101+
{
102+
// FIXME Need to return errors
103+
return;
104+
}
105+
106+
buffer[0] = DHCP_BOOTREQUEST; // op
107+
buffer[1] = DHCP_HTYPE10MB; // htype
108+
buffer[2] = DHCP_HLENETHERNET; // hlen
109+
buffer[3] = DHCP_HOPS; // hops
110+
111+
// xid
112+
unsigned long xid = htonl(_dhcpTransactionId);
113+
memcpy(buffer + 4, &(xid), 4);
114+
115+
// 8, 9 - seconds elapsed
116+
buffer[8] = ((secondsElapsed & 0xff00) >> 8);
117+
buffer[9] = (secondsElapsed & 0x00ff);
118+
119+
// flags
120+
unsigned short flags = htons(DHCP_FLAGSBROADCAST);
121+
memcpy(buffer + 10, &(flags), 2);
122+
123+
// ciaddr: already zeroed
124+
// yiaddr: already zeroed
125+
// siaddr: already zeroed
126+
// giaddr: already zeroed
127+
128+
//put data in W5100 transmit buffer
129+
_dhcpUdpSocket.write(buffer, 28);
130+
131+
memset(buffer, 0, 32); // clear local buffer
132+
133+
memcpy(buffer, _dhcpMacAddr, 6); // chaddr
134+
135+
//put data in W5100 transmit buffer
136+
_dhcpUdpSocket.write(buffer, 16);
137+
138+
memset(buffer, 0, 32); // clear local buffer
139+
140+
// leave zeroed out for sname && file
141+
// put in W5100 transmit buffer x 6 (192 bytes)
142+
143+
for(int i = 0; i < 6; i++) {
144+
_dhcpUdpSocket.write(buffer, 32);
145+
}
146+
147+
// OPT - Magic Cookie
148+
buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF);
149+
buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF);
150+
buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF);
151+
buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF);
152+
153+
// OPT - message type
154+
buffer[4] = dhcpMessageType;
155+
buffer[5] = 0x01;
156+
buffer[6] = messageType; //DHCP_REQUEST;
157+
158+
// OPT - client identifier
159+
buffer[7] = dhcpClientIdentifier;
160+
buffer[8] = 0x07;
161+
buffer[9] = 0x01;
162+
memcpy(buffer + 10, _dhcpMacAddr, 6);
163+
164+
// OPT - host name
165+
buffer[16] = hostName;
166+
buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address
167+
strcpy((char*)&(buffer[18]), HOST_NAME);
168+
169+
buffer[24] = _dhcpMacAddr[3];
170+
buffer[25] = _dhcpMacAddr[4];
171+
buffer[26] = _dhcpMacAddr[5];
172+
173+
//put data in W5100 transmit buffer
174+
_dhcpUdpSocket.write(buffer, 27);
175+
176+
if(messageType == DHCP_REQUEST)
177+
{
178+
buffer[0] = dhcpRequestedIPaddr;
179+
buffer[1] = 0x04;
180+
buffer[2] = _dhcpLocalIp[0];
181+
buffer[3] = _dhcpLocalIp[1];
182+
buffer[4] = _dhcpLocalIp[2];
183+
buffer[5] = _dhcpLocalIp[3];
184+
185+
buffer[6] = dhcpServerIdentifier;
186+
buffer[7] = 0x04;
187+
buffer[8] = _dhcpDhcpServerIp[0];
188+
buffer[9] = _dhcpDhcpServerIp[1];
189+
buffer[10] = _dhcpDhcpServerIp[2];
190+
buffer[11] = _dhcpDhcpServerIp[3];
191+
192+
//put data in W5100 transmit buffer
193+
_dhcpUdpSocket.write(buffer, 12);
194+
}
195+
196+
buffer[0] = dhcpParamRequest;
197+
buffer[1] = 0x06;
198+
buffer[2] = subnetMask;
199+
buffer[3] = routersOnSubnet;
200+
buffer[4] = dns;
201+
buffer[5] = domainName;
202+
buffer[6] = dhcpT1value;
203+
buffer[7] = dhcpT2value;
204+
buffer[8] = endOption;
205+
206+
//put data in W5100 transmit buffer
207+
_dhcpUdpSocket.write(buffer, 9);
208+
209+
_dhcpUdpSocket.endPacket();
210+
}
211+
212+
uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
213+
{
214+
uint8_t type = 0;
215+
uint8_t opt_len = 0;
216+
217+
unsigned long startTime = millis();
218+
219+
while(_dhcpUdpSocket.parsePacket() <= 0)
220+
{
221+
if((millis() - startTime) > responseTimeout)
222+
{
223+
return 255;
224+
}
225+
delay(50);
226+
}
227+
// start reading in the packet
228+
RIP_MSG_FIXED fixedMsg;
229+
_dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
230+
231+
if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
232+
{
233+
transactionId = ntohl(fixedMsg.xid);
234+
if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
235+
{
236+
// Need to read the rest of the packet here regardless
237+
_dhcpUdpSocket.flush();
238+
return 0;
239+
}
240+
241+
memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
242+
243+
// Skip to the option part
244+
// Doing this a byte at a time so we don't have to put a big buffer
245+
// on the stack (as we don't have lots of memory lying around)
246+
for (int i =0; i < (240 - sizeof(RIP_MSG_FIXED)); i++)
247+
{
248+
_dhcpUdpSocket.read(); // we don't care about the returned byte
249+
}
250+
251+
while (_dhcpUdpSocket.available() > 0)
252+
{
253+
switch (_dhcpUdpSocket.read())
254+
{
255+
case endOption :
256+
break;
257+
258+
case padOption :
259+
break;
260+
261+
case dhcpMessageType :
262+
opt_len = _dhcpUdpSocket.read();
263+
type = _dhcpUdpSocket.read();
264+
break;
265+
266+
case subnetMask :
267+
opt_len = _dhcpUdpSocket.read();
268+
_dhcpUdpSocket.read(_dhcpSubnetMask, 4);
269+
break;
270+
271+
case routersOnSubnet :
272+
opt_len = _dhcpUdpSocket.read();
273+
_dhcpUdpSocket.read(_dhcpGatewayIp, 4);
274+
break;
275+
276+
case dns :
277+
opt_len = _dhcpUdpSocket.read();
278+
_dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
279+
break;
280+
281+
case dhcpServerIdentifier :
282+
opt_len = _dhcpUdpSocket.read();
283+
if( *((uint32_t*)_dhcpDhcpServerIp) == 0 ||
284+
IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() )
285+
{
286+
_dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
287+
}
288+
else
289+
{
290+
// Skip over the rest of this option
291+
while (opt_len--)
292+
{
293+
_dhcpUdpSocket.read();
294+
}
295+
}
296+
break;
297+
298+
case dhcpIPaddrLeaseTime :
299+
default :
300+
opt_len = _dhcpUdpSocket.read();
301+
// Skip over the rest of this option
302+
while (opt_len--)
303+
{
304+
_dhcpUdpSocket.read();
305+
}
306+
break;
307+
}
308+
}
309+
}
310+
311+
// Need to skip to end of the packet regardless here
312+
_dhcpUdpSocket.flush();
313+
314+
return type;
315+
}
316+
317+
IPAddress DhcpClass::getLocalIp()
318+
{
319+
return IPAddress(_dhcpLocalIp);
320+
}
321+
322+
IPAddress DhcpClass::getSubnetMask()
323+
{
324+
return IPAddress(_dhcpSubnetMask);
325+
}
326+
327+
IPAddress DhcpClass::getGatewayIp()
328+
{
329+
return IPAddress(_dhcpGatewayIp);
330+
}
331+
332+
IPAddress DhcpClass::getDhcpServerIp()
333+
{
334+
return IPAddress(_dhcpDhcpServerIp);
335+
}
336+
337+
IPAddress DhcpClass::getDnsServerIp()
338+
{
339+
return IPAddress(_dhcpDnsServerIp);
340+
}
341+

0 commit comments

Comments
 (0)