embkernel
 All Classes Functions Variables Typedefs Groups Pages
NetClientDhcp.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "Net.hpp"
7 #include "NetUdp.hpp"
8 #include "LibEndian.hpp"
9 #include "NetClientDhcp.hpp"
10 
11 #include <string.h>
12 
13 NetClientDhcp::STATE NetClientDhcp::sState = STATE_DISABLED;
14 uint32_t NetClientDhcp::sTransactionId = 0xabcdef01;
15 NetDefs::IP_ADDR NetClientDhcp::sOfferedYourIpAddr;
16 NetDefs::IP_ADDR NetClientDhcp::sOfferedMask;
17 NetDefs::IP_ADDR NetClientDhcp::sOfferedServerIpAddr;
18 NetDefs::IP_ADDR NetClientDhcp::sOfferedGatewayIpAddr;
19 NetDefs::IP_ADDR NetClientDhcp::sOfferedDnsIpAddr;
20 uint32_t NetClientDhcp::sLeaseTime = 0;
21 uint32_t NetClientDhcp::sTimeout = 0;
22 
23 void NetClientDhcp::processFrame(NetDefs::FRAME& frame, NetDefs::DHCP_HEADER& header, int len) {
24  swapHeader(header);
25 
26  MSG_TYPE msgType;
27 
28  if (sState == STATE_DISABLED) {
29  Net::freeFrame(frame);
30  return;
31  }
32 
33  if (parseMsg(frame, header, msgType, len)) {
34  Net::freeFrame(frame);
35 
36  switch (sState) {
37  case STATE_WAIT_OFFER:
38  if (msgType == MSG_OFFER) {
39  if (!sendMessage(MSG_REQUEST)) {
40  break;
41  }
42  sTimeout = 5;
43  sState = STATE_WAIT_ACK;
44  }
45  break;
46  case STATE_WAIT_ACK:
47  if (msgType == MSG_ACK) {
48  Net::sConfig.ipAddr = sOfferedYourIpAddr;
49  Net::sConfig.mask = sOfferedMask;
50  Net::sConfig.gatewayIpAddr = sOfferedGatewayIpAddr;
51  if (sOfferedDnsIpAddr.val != 0) {
52  Net::sConfig.dnsIpAddr = sOfferedDnsIpAddr;
53  }
54  else {
55  Net::sConfig.dnsIpAddr = sOfferedGatewayIpAddr;
56  }
57  sTimeout = sLeaseTime - 60;
58  sState = STATE_BOUND;
59  }
60  break;
61  default:
62  sState = STATE_INIT;
63  break;
64  }
65  }
66  else {
67  Net::freeFrame(frame);
68  }
69 }
70 
71 //1s tick
72 void NetClientDhcp::tick() {
73 
74  if (!Net::sConfig.dhcpEnabled) {
75  sState = STATE_DISABLED;
76  return;
77  }
78 
79  switch (sState) {
80  case STATE_DISABLED:
81  sState = STATE_INIT;
82  break;
83  case STATE_INIT: {
84  if (sTimeout == 0) {
85  sTransactionId++;
86  if (!sendMessage(MSG_DISCOVER)) {
87  break;
88  }
89  sTimeout = 5;
90  sState = STATE_WAIT_OFFER;
91  }
92  break;
93  }
94  case STATE_WAIT_OFFER:
95  if (sTimeout == 0) {
96  sState = STATE_INIT;
97  }
98  break;
99  case STATE_WAIT_ACK:
100  if (sTimeout == 0) {
101  sState = STATE_INIT;
102  }
103  break;
104  case STATE_BOUND:
105  if (sTimeout == 0) {
106  sTransactionId++;
107  if (!sendMessage(MSG_REQUEST)) {
108  break;
109  }
110  sTimeout = 5;
111  sState = STATE_WAIT_ACK;
112  }
113  break;
114  }
115 
116  if (sTimeout) {
117  sTimeout--;
118  }
119 }
120 
121 bool NetClientDhcp::sendMessage(MSG_TYPE type) {
122 
123  int optLen;
124  switch (type) {
125  case MSG_DISCOVER:
126  optLen = 4 //Magic cookie
127  + 3 //Msg type
128  + 5 // Parameters request list
129  + 6 //Host name
130  + 1; //end
131  break;
132  case MSG_REQUEST:
133  optLen = 4 //Magic cookie
134  + 3 //Msg type
135  + 6 //Requested ip addr
136  + 6 //Server identifier
137  + 6 //Host name
138  + 1; //end
139  break;
140  default:
141  return false;
142  }
143 
144  NetDefs::FRAME * sendFrame = Net::allocFrame(
145  sizeof(NetDefs::MAC_HEADER) + sizeof(NetDefs::IP_HEADER) + sizeof(NetDefs::UDP_HEADER) + sizeof(NetDefs::DHCP_HEADER) + optLen);
146  if (!sendFrame) {
147  return false;
148  }
149 
150  NetDefs::DHCP_HEADER& dhcpHeader = sendFrame->types.dhcp.dhcpHeader;
151 
152  dhcpHeader.opCode = NetDefs::DHCP_OPCODE_BOOT_REQUEST;
153  dhcpHeader.hardwareType = 1;
154  dhcpHeader.macAddrLen = 6;
155  dhcpHeader.hopCount = 0;
156  dhcpHeader.transactionID = sTransactionId;
157  dhcpHeader.numberOfSeconds = 0x0000;
158  dhcpHeader.flags = LibEndian::hwToBe((uint16_t) 0x8000); //Broadcast flag
159  dhcpHeader.clientIpAddr = Net::sConfig.ipAddr;
160 
161  dhcpHeader.yourIPAddr.val = dhcpHeader.serverIpAddr.val = dhcpHeader.gatewayIpAddr.val = 0;
162 
163  memset(&dhcpHeader.clientHwAddr, 0, sizeof(dhcpHeader.clientHwAddr));
164  *((NetDefs::MAC_ADDR*) &dhcpHeader.clientHwAddr) = Net::sMacAddr;
165 
166  memset(&dhcpHeader.serverHostName, 0, sizeof(dhcpHeader.serverHostName));
167  memset(&dhcpHeader.bootFileName, 0, sizeof(dhcpHeader.bootFileName));
168 
169  swapHeader(dhcpHeader);
170 
171  uint8_t* p = (uint8_t*) sendFrame->types.dhcp.data;
172  //Magic cookie
173  memcpy(p, NetDefs::DHCP_MAGIC_COOKIE, 4);
174  p += 4;
175 
176  p = writeOption(p, OPT_DHCP_MESSAGE_TYPE, (uint8_t*) &type, 1);
177 
178  if (type == MSG_REQUEST) {
179  p = writeOption(p, OPT_REQUESTED_IP_ADDRESS, (uint8_t*) &sOfferedYourIpAddr, 4);
180  p = writeOption(p, OPT_SERVER_IDENTIFIER, (uint8_t*) &sOfferedServerIpAddr, 4);
181  }
182  else {
183  uint8_t optList[] = {
184  OPT_SUBNET_MASK, OPT_ROUTER, OPT_DNS };
185  p = writeOption(p, OPT_PARAM_REQUEST_LIST, optList, 3);
186  }
187 
188  p = writeOption(p, OPT_HOST_NAME, (uint8_t*) "emb", 3);
189 
190  *p++ = OPT_END;
191 
192  NetUdp::putHeader(*sendFrame, NetDefs::MAC_BROADCAST, NetDefs::IP_BROADCAST, NetDefs::UDP_PORT_DHCP_CLIENT, NetDefs::UDP_PORT_DHCP_SERVER,
193  sizeof(NetDefs::DHCP_HEADER) + optLen);
194 
195  NetUdp::flush(*sendFrame, sizeof(NetDefs::DHCP_HEADER) + optLen, true);
196 
197  return true;
198 }
199 
200 bool NetClientDhcp::parseMsg(NetDefs::FRAME& frame, NetDefs::DHCP_HEADER& header, MSG_TYPE& msgType, int len) {
201  if (header.transactionID != sTransactionId) {
202  return false;
203  }
204  if (header.opCode != NetDefs::DHCP_OPCODE_BOOT_REPLY) {
205  return false;
206  }
207  if (*((NetDefs::MAC_ADDR*) &header.clientHwAddr) != Net::sMacAddr) {
208  return false;
209  }
210 
211  uint8_t* p = ((uint8_t*) &header) + sizeof(header);
212 
213  if (memcmp(p, &NetDefs::DHCP_MAGIC_COOKIE, 4)) {
214  return false;
215  }
216 
217  p += 4;
218 
219  sOfferedYourIpAddr = header.yourIPAddr;
220  sOfferedDnsIpAddr.val = 0;
221 
222  sLeaseTime = 60;
223 
224  uint8_t* end = ((uint8_t*) &header) + len;
225 
226  //Parse options
227  while ((uint32_t) p < (uint32_t) end) {
228  if (*p == OPT_END) {
229  return true;
230  }
231 
232  const MSG_OPT opt = (const MSG_OPT) *p++;
233  const uint8_t parLen = *p++;
234 
235  switch (opt) {
236  case OPT_DHCP_MESSAGE_TYPE:
237  if (parLen == 1) {
238  msgType = (MSG_TYPE) *p;
239  }
240  break;
241  case OPT_SUBNET_MASK:
242  if (parLen == 4) {
243  sOfferedMask.v[0] = p[0];
244  sOfferedMask.v[1] = p[1];
245  sOfferedMask.v[2] = p[2];
246  sOfferedMask.v[3] = p[3];
247  }
248  break;
249  case OPT_ROUTER:
250  if (parLen == 4) {
251  sOfferedGatewayIpAddr.v[0] = p[0];
252  sOfferedGatewayIpAddr.v[1] = p[1];
253  sOfferedGatewayIpAddr.v[2] = p[2];
254  sOfferedGatewayIpAddr.v[3] = p[3];
255  }
256  break;
257  case OPT_SERVER_IDENTIFIER:
258  if (parLen == 4) {
259  sOfferedServerIpAddr.v[0] = p[0];
260  sOfferedServerIpAddr.v[1] = p[1];
261  sOfferedServerIpAddr.v[2] = p[2];
262  sOfferedServerIpAddr.v[3] = p[3];
263  }
264  break;
265  case OPT_DNS:
266  if (parLen == 4) {
267  sOfferedDnsIpAddr.v[0] = p[0];
268  sOfferedDnsIpAddr.v[1] = p[1];
269  sOfferedDnsIpAddr.v[2] = p[2];
270  sOfferedDnsIpAddr.v[3] = p[3];
271  }
272  break;
273  case OPT_IP_LEASE_TIME:
274  if (parLen == 4) {
275  sLeaseTime = ((uint32_t) p[0] << 24) + ((uint32_t) p[1] << 16) + ((uint32_t) p[2] << 8) + ((uint32_t) p[0]);
276  }
277  break;
278  default:
279  break;
280  }
281 
282  p += parLen;
283  }
284 
285  return false;
286 }
287 
288 uint8_t* NetClientDhcp::writeOption(uint8_t* dst, MSG_OPT option, const uint8_t* parameters, int len) {
289  *dst++ = option;
290  *dst++ = len;
291  while (len--) {
292  *dst++ = *parameters++;
293  }
294  return dst;
295 }
296 
297 void NetClientDhcp::swapHeader(NetDefs::DHCP_HEADER& header) {
298  header.transactionID = LibEndian::hwToBe(header.transactionID);
299 }