dhcp_server_misc.c
Go to the documentation of this file.
1 /**
2  * @file dhcp_server_misc.c
3  * @brief Helper functions for DHCP server
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DHCP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "dhcp/dhcp_server.h"
37 #include "dhcp/dhcp_server_misc.h"
38 #include "dhcp/dhcp_common.h"
39 #include "dhcp/dhcp_debug.h"
40 #include "date_time.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (IPV4_SUPPORT == ENABLED && DHCP_SERVER_SUPPORT == ENABLED)
45 
46 //Tick counter to handle periodic operations
48 
49 
50 /**
51  * @brief DHCP server timer handler
52  *
53  * This routine must be periodically called by the TCP/IP stack to
54  * manage DHCP server operation
55  *
56  * @param[in] context Pointer to the DHCP server context
57  **/
58 
60 {
61  uint_t i;
63  systime_t leaseTime;
64  DhcpServerBinding *binding;
65 
66  //Make sure the DHCP server has been properly instantiated
67  if(context == NULL)
68  return;
69 
70  //Get current time
72 
73  //Convert the lease time to milliseconds
74  if(context->settings.leaseTime < (MAX_DELAY / 1000))
75  {
76  leaseTime = context->settings.leaseTime * 1000;
77  }
78  else
79  {
80  leaseTime = MAX_DELAY;
81  }
82 
83  //Loop through the list of bindings
84  for(i = 0; i < DHCP_SERVER_MAX_CLIENTS; i++)
85  {
86  //Point to the current binding
87  binding = &context->clientBinding[i];
88 
89  //Valid binding?
90  if(!macCompAddr(&binding->macAddr, &MAC_UNSPECIFIED_ADDR))
91  {
92  //Check whether the network address has been committed
93  if(binding->validLease)
94  {
95  //Check whether the lease has expired
96  if(timeCompare(time, binding->timestamp + leaseTime) >= 0)
97  {
98  //The address lease is not more valid
99  binding->validLease = FALSE;
100  }
101  }
102  }
103  }
104 }
105 
106 
107 /**
108  * @brief Process incoming DHCP message
109  * @param[in] interface Underlying network interface
110  * @param[in] pseudoHeader UDP pseudo header
111  * @param[in] udpHeader UDP header
112  * @param[in] buffer Multi-part buffer containing the incoming DHCP message
113  * @param[in] offset Offset to the first byte of the DHCP message
114  * @param[in] ancillary Additional options passed to the stack along with
115  * the packet
116  * @param[in] param Pointer to the DHCP server context
117  **/
118 
120  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
121  const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary,
122  void *param)
123 {
124  error_t error;
125  size_t length;
126  DhcpServerContext *context;
128  DhcpOption *option;
130 
131  //Point to the DHCP server context
132  context = (DhcpServerContext *) param;
133 
134  //Retrieve the length of the DHCP message
135  length = netBufferGetLength(buffer) - offset;
136 
137  //Make sure the DHCP message is valid
138  if(length < sizeof(DhcpMessage))
139  return;
141  return;
142 
143  //Point to the beginning of the DHCP message
144  message = netBufferAt(buffer, offset);
145  //Sanity check
146  if(message == NULL)
147  return;
148 
149  //Debug message
150  TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
152 
153  //Dump the contents of the message for debugging purpose
155 
156  //Check opcode
158  return;
159  //Enforce hardware type
160  if(message->htype != DHCP_HARDWARE_TYPE_ETH)
161  return;
162  //Check the length of the hardware address
163  if(message->hlen != sizeof(MacAddr))
164  return;
165  //Check magic cookie
166  if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
167  return;
168 
169  //Retrieve DHCP Message Type option
171 
172  //Failed to retrieve specified option?
173  if(option == NULL || option->length != 1)
174  return;
175 
176  //Retrieve message type
177  type = (DhcpMessageType) option->value[0];
178 
179  //Any registered callback?
180  if(context->settings.parseOptionsCallback != NULL)
181  {
182  //Invoke user callback function
183  error = context->settings.parseOptionsCallback(context, message, length,
184  type);
185  //Check status code
186  if(error)
187  return;
188  }
189 
190  //Check message type
191  switch(type)
192  {
194  //Parse DHCPDISCOVER message
196  break;
197 
199  //Parse DHCPREQUEST message
201  break;
202 
204  //Parse DHCPDECLINE message
206  break;
207 
209  //Parse DHCPRELEASE message
211  break;
212 
214  //Parse DHCPINFORM message
216  break;
217 
218  default:
219  //Silently drop incoming message
220  break;
221  }
222 }
223 
224 
225 /**
226  * @brief Parse DHCPDISCOVER message
227  * @param[in] context Pointer to the DHCP server context
228  * @param[in] message Pointer to the incoming DHCP message
229  * @param[in] length Length of the incoming message to parse
230  **/
231 
233  const DhcpMessage *message, size_t length)
234 {
235  error_t error;
236  uint_t i;
237  NetInterface *interface;
238  Ipv4Addr requestedIpAddr;
239  DhcpOption *option;
240  DhcpServerBinding *binding;
241 
242  //Point to the underlying network interface
243  interface = context->settings.interface;
244  //Index of the IP address assigned to the DHCP server
245  i = context->settings.ipAddrIndex;
246 
247  //Retrieve Server Identifier option
249 
250  //Option found?
251  if(option != NULL && option->length == 4)
252  {
253  //Unexpected server identifier?
254  if(!ipv4CompAddr(option->value, &interface->ipv4Context.addrList[i].addr))
255  return;
256  }
257 
258  //Retrieve Requested IP Address option
260 
261  //The client may include the 'requested IP address' option to suggest
262  //that a particular IP address be assigned
263  if(option != NULL && option->length == 4)
264  {
265  ipv4CopyAddr(&requestedIpAddr, option->value);
266  }
267  else
268  {
269  requestedIpAddr = IPV4_UNSPECIFIED_ADDR;
270  }
271 
272  //Search the list for a matching binding
273  binding = dhcpServerFindBindingByMacAddr(context, &message->chaddr);
274 
275  //Matching binding found?
276  if(binding != NULL)
277  {
278  //Different IP address than cached?
279  if(requestedIpAddr != binding->ipAddr)
280  {
281  //Ensure the IP address is in the server's pool of available addresses
282  if(ntohl(requestedIpAddr) >= ntohl(context->settings.ipAddrRangeMin) &&
283  ntohl(requestedIpAddr) <= ntohl(context->settings.ipAddrRangeMax))
284  {
285  //Make sure the IP address is not already allocated
286  if(!dhcpServerFindBindingByIpAddr(context, requestedIpAddr))
287  {
288  //Record IP address
289  binding->ipAddr = requestedIpAddr;
290  //Get current time
291  binding->timestamp = osGetSystemTime();
292  }
293  }
294  }
295 
296  //Successful processing
297  error = NO_ERROR;
298  }
299  else
300  {
301  //Create a new binding
302  binding = dhcpServerCreateBinding(context);
303 
304  //Binding successfully created
305  if(binding != NULL)
306  {
307  //Ensure the IP address is in the server's pool of available addresses
308  if(ntohl(requestedIpAddr) >= ntohl(context->settings.ipAddrRangeMin) &&
309  ntohl(requestedIpAddr) <= ntohl(context->settings.ipAddrRangeMax))
310  {
311  //Make sure the IP address is not already allocated
312  if(!dhcpServerFindBindingByIpAddr(context, requestedIpAddr))
313  {
314  //Record IP address
315  binding->ipAddr = requestedIpAddr;
316  //Successful processing
317  error = NO_ERROR;
318  }
319  else
320  {
321  //Retrieve the next available IP address from the pool of addresses
322  error = dhcpServerGetNextIpAddr(context, &binding->ipAddr);
323  }
324  }
325  else
326  {
327  //Retrieve the next available IP address from the pool of addresses
328  error = dhcpServerGetNextIpAddr(context, &binding->ipAddr);
329  }
330 
331  //Check status code
332  if(!error)
333  {
334  //Record MAC address
335  binding->macAddr = message->chaddr;
336  //Get current time
337  binding->timestamp = osGetSystemTime();
338  }
339  }
340  else
341  {
342  //Failed to create a new binding
343  error = ERROR_FAILURE;
344  }
345  }
346 
347  //Check status code
348  if(!error)
349  {
350  //The server responds with a DHCPOFFER message that includes an
351  //available network address in the 'yiaddr' field (and other
352  //configuration parameters in DHCP options)
354  message, length);
355  }
356 }
357 
358 
359 /**
360  * @brief Parse DHCPREQUEST message
361  * @param[in] context Pointer to the DHCP server context
362  * @param[in] message Pointer to the incoming DHCP message
363  * @param[in] length Length of the incoming message to parse
364  **/
365 
367  const DhcpMessage *message, size_t length)
368 {
369  uint_t i;
370  NetInterface *interface;
371  Ipv4Addr clientIpAddr;
372  DhcpOption *option;
373  DhcpServerBinding *binding;
374 
375  //Point to the underlying network interface
376  interface = context->settings.interface;
377  //Index of the IP address assigned to the DHCP server
378  i = context->settings.ipAddrIndex;
379 
380  //Retrieve Server Identifier option
382 
383  //Option found?
384  if(option != NULL && option->length == 4)
385  {
386  //Unexpected server identifier?
387  if(!ipv4CompAddr(option->value, &interface->ipv4Context.addrList[i].addr))
388  return;
389  }
390 
391  //Check the 'ciaddr' field
392  if(message->ciaddr != IPV4_UNSPECIFIED_ADDR)
393  {
394  //Save client's network address
395  clientIpAddr = message->ciaddr;
396  }
397  else
398  {
399  //Retrieve Requested IP Address option
401 
402  //Option found?
403  if(option != NULL && option->length == 4)
404  {
405  ipv4CopyAddr(&clientIpAddr, option->value);
406  }
407  else
408  {
409  clientIpAddr = IPV4_UNSPECIFIED_ADDR;
410  }
411  }
412 
413  //Valid client IP address?
414  if(clientIpAddr != IPV4_UNSPECIFIED_ADDR)
415  {
416  //Search the list for a matching binding
417  binding = dhcpServerFindBindingByMacAddr(context, &message->chaddr);
418 
419  //Matching binding found?
420  if(binding != NULL)
421  {
422  //Make sure the client's IP address is valid
423  if(clientIpAddr == binding->ipAddr)
424  {
425  //Commit network address
426  binding->validLease = TRUE;
427  //Save lease start time
428  binding->timestamp = osGetSystemTime();
429 
430  //The server responds with a DHCPACK message containing the
431  //configuration parameters for the requesting client
433  binding->ipAddr, message, length);
434 
435  //Exit immediately
436  return;
437  }
438  }
439  else
440  {
441  //Ensure the IP address is in the server's pool of available addresses
442  if(ntohl(clientIpAddr) >= ntohl(context->settings.ipAddrRangeMin) &&
443  ntohl(clientIpAddr) <= ntohl(context->settings.ipAddrRangeMax))
444  {
445  //Make sure the IP address is not already allocated
446  if(!dhcpServerFindBindingByIpAddr(context, clientIpAddr))
447  {
448  //Create a new binding
449  binding = dhcpServerCreateBinding(context);
450 
451  //Binding successfully created
452  if(binding != NULL)
453  {
454  //Record MAC address
455  binding->macAddr = message->chaddr;
456  //Record IP address
457  binding->ipAddr = clientIpAddr;
458  //Commit network address
459  binding->validLease = TRUE;
460  //Get current time
461  binding->timestamp = osGetSystemTime();
462 
463  //The server responds with a DHCPACK message containing the
464  //configuration parameters for the requesting client
466  binding->ipAddr, message, length);
467 
468  //Exit immediately
469  return;
470  }
471  }
472  }
473  }
474  }
475 
476  //If the server is unable to satisfy the DHCPREQUEST message, the
477  //server should respond with a DHCPNAK message
479  message, length);
480 }
481 
482 
483 /**
484  * @brief Parse DHCPDECLINE message
485  * @param[in] context Pointer to the DHCP server context
486  * @param[in] message Pointer to the incoming DHCP message
487  * @param[in] length Length of the incoming message to parse
488  **/
489 
491  const DhcpMessage *message, size_t length)
492 {
493  DhcpOption *option;
494  DhcpServerBinding *binding;
495  Ipv4Addr requestedIpAddr;
496 
497  //Retrieve Requested IP Address option
499 
500  //Option found?
501  if(option != NULL && option->length == 4)
502  {
503  //Copy the requested IP address
504  ipv4CopyAddr(&requestedIpAddr, option->value);
505 
506  //Search the list for a matching binding
507  binding = dhcpServerFindBindingByMacAddr(context, &message->chaddr);
508 
509  //Matching binding found?
510  if(binding != NULL)
511  {
512  //Check the IP address against the requested IP address
513  if(binding->ipAddr == requestedIpAddr)
514  {
515  //Remote the binding from the list
516  osMemset(binding, 0, sizeof(DhcpServerBinding));
517  }
518  }
519  }
520 }
521 
522 
523 /**
524  * @brief Parse DHCPRELEASE message
525  * @param[in] context Pointer to the DHCP server context
526  * @param[in] message Pointer to the incoming DHCP message
527  * @param[in] length Length of the incoming message to parse
528  **/
529 
531  const DhcpMessage *message, size_t length)
532 {
533  DhcpServerBinding *binding;
534 
535  //Search the list for a matching binding
536  binding = dhcpServerFindBindingByMacAddr(context, &message->chaddr);
537 
538  //Matching binding found?
539  if(binding != NULL)
540  {
541  //Check the IP address against the client IP address
542  if(binding->ipAddr == message->ciaddr)
543  {
544  //Release the network address and cancel remaining lease
545  binding->validLease = FALSE;
546  }
547  }
548 }
549 
550 
551 /**
552  * @brief Parse DHCPINFORM message
553  * @param[in] context Pointer to the DHCP server context
554  * @param[in] message Pointer to the incoming DHCP message
555  * @param[in] length Length of the incoming message to parse
556  **/
557 
559  const DhcpMessage *message, size_t length)
560 {
561  //Make sure the client IP address is valid
562  if(message->ciaddr != IPV4_UNSPECIFIED_ADDR)
563  {
564  //Servers receiving a DHCPINFORM message construct a DHCPACK message
565  //with any local configuration parameters appropriate for the client
567  message, length);
568  }
569 }
570 
571 
572 /**
573  * @brief Send DHCP reply message
574  * @param[in] context Pointer to the DHCP server context
575  * @param[in] type DHCP message type (DHCPOFFER, DHCPACK or DHCPNAK)
576  * @param[in] yourIpAddr The IP address to be placed in the 'yiaddr' field
577  * @param[in] request Pointer to DHCP message received from the client
578  * @param[in] requestLen Length of the DHCP message received from the client
579  * @return Error code
580  **/
581 
583  Ipv4Addr yourIpAddr, const DhcpMessage *request, size_t requestLen)
584 {
585  error_t error;
586  uint_t i;
587  uint_t n;
588  uint32_t value;
589  size_t offset;
590  size_t replyLen;
591  NetBuffer *buffer;
592  NetInterface *interface;
593  DhcpMessage *reply;
596  uint16_t destPort;
597  NetTxAncillary ancillary;
598 
599  //Point to the underlying network interface
600  interface = context->settings.interface;
601  //Index of the IP address assigned to the DHCP server
602  i = context->settings.ipAddrIndex;
603 
604  //Allocate a memory buffer to hold the DHCP message
605  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
606  //Failed to allocate buffer?
607  if(buffer == NULL)
608  return ERROR_OUT_OF_MEMORY;
609 
610  //Point to the beginning of the DHCP message
611  reply = netBufferAt(buffer, offset);
612  //Clear memory buffer contents
613  osMemset(reply, 0, DHCP_MAX_MSG_SIZE);
614 
615  //Format DHCP reply message
616  reply->op = DHCP_OPCODE_BOOTREPLY;
617  reply->htype = DHCP_HARDWARE_TYPE_ETH;
618  reply->hlen = sizeof(MacAddr);
619  reply->xid = request->xid;
620  reply->secs = 0;
621  reply->flags = request->flags;
622  reply->ciaddr = IPV4_UNSPECIFIED_ADDR;
623  reply->yiaddr = yourIpAddr;
624  reply->siaddr = IPV4_UNSPECIFIED_ADDR;
625  reply->giaddr = request->giaddr;
626  reply->chaddr = request->chaddr;
627 
628  //Write magic cookie before setting any option
629  reply->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
630  //Properly terminate options field
631  reply->options[0] = DHCP_OPT_END;
632 
633  //Total length of the DHCP message
634  replyLen = sizeof(DhcpMessage) + sizeof(uint8_t);
635 
636  //Add DHCP Message Type option
637  dhcpAddOption(reply, &replyLen, DHCP_OPT_DHCP_MESSAGE_TYPE,
638  &type, sizeof(type));
639 
640  //Add Server Identifier option
641  dhcpAddOption(reply, &replyLen, DHCP_OPT_SERVER_ID,
642  &interface->ipv4Context.addrList[i].addr, sizeof(Ipv4Addr));
643 
644  //DHCPOFFER or DHCPACK message?
646  {
647  //Convert the lease time to network byte order
648  value = htonl(context->settings.leaseTime);
649 
650  //When responding to a DHCPINFORM message, the server must not
651  //send a lease expiration time to the client
652  if(yourIpAddr != IPV4_UNSPECIFIED_ADDR)
653  {
654  //Add IP Address Lease Time option
656  &value, sizeof(value));
657  }
658 
659  //Add Subnet Mask option
660  if(context->settings.subnetMask != IPV4_UNSPECIFIED_ADDR)
661  {
662  dhcpAddOption(reply, &replyLen, DHCP_OPT_SUBNET_MASK,
663  &context->settings.subnetMask, sizeof(Ipv4Addr));
664  }
665 
666  //Add Router option
667  if(context->settings.defaultGateway != IPV4_UNSPECIFIED_ADDR)
668  {
669  dhcpAddOption(reply, &replyLen, DHCP_OPT_ROUTER,
670  &context->settings.defaultGateway, sizeof(Ipv4Addr));
671  }
672 
673  //Retrieve the number of DNS servers
674  for(n = 0; n < DHCP_SERVER_MAX_DNS_SERVERS; n++)
675  {
676  //Check whether the current DNS server is valid
677  if(context->settings.dnsServer[n] == IPV4_UNSPECIFIED_ADDR)
678  break;
679  }
680 
681  //Add DNS Server option
682  if(n > 0)
683  {
684  dhcpAddOption(reply, &replyLen, DHCP_OPT_DNS_SERVER,
685  context->settings.dnsServer, n * sizeof(Ipv4Addr));
686  }
687  }
688 
689  //Any registered callback?
690  if(context->settings.addOptionsCallback != NULL)
691  {
692  //Invoke user callback function
693  context->settings.addOptionsCallback(context, reply, &replyLen,
695  }
696 
697  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
698  //section 3)
699  replyLen = MAX(replyLen, DHCP_MIN_MSG_SIZE);
700 
701  //Adjust the length of the multi-part buffer
702  netBufferSetLength(buffer, offset + replyLen);
703 
704  //Additional options can be passed to the stack along with the packet
705  ancillary = NET_DEFAULT_TX_ANCILLARY;
706 
707  //A server with multiple network address (e.g. a multi-homed host) may
708  //use any of its network addresses in outgoing DHCP messages (refer to
709  //RFC 2131, section 4.1)
710  srcIpAddr.length = sizeof(Ipv4Addr);
711  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
712 
713  //Check whether the 'giaddr' field is non-zero
714  if(request->giaddr != IPV4_UNSPECIFIED_ADDR)
715  {
716  //If the 'giaddr' field in a DHCP message from a client is non-zero,
717  //the server sends any return messages to the 'DHCP server' port
719 
720  //The DHCP message is sent to the BOOTP relay agent whose address
721  //appears in 'giaddr'
722  destIpAddr.length = sizeof(Ipv4Addr);
723  destIpAddr.ipv4Addr = request->giaddr;
724  }
725  else
726  {
727  //If the 'giaddr' field in a DHCP message from a client is zero,
728  //the server sends any return messages to the 'DHCP client'
730 
731  //DHCPOFFER or DHCPACK message?
733  {
734  //Check whether the 'ciaddr' field is non-zero
735  if(request->ciaddr != IPV4_UNSPECIFIED_ADDR)
736  {
737  //If the 'giaddr' field is zero and the 'ciaddr' field is nonzero,
738  //then the server unicasts DHCPOFFER and DHCPACK messages to the
739  //address in 'ciaddr'
740  destIpAddr.length = sizeof(Ipv4Addr);
741  destIpAddr.ipv4Addr = request->ciaddr;
742  }
743  else
744  {
745  //Check whether the broadcast bit is set
746  if(ntohs(request->flags) & DHCP_FLAG_BROADCAST)
747  {
748  //If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
749  //set, then the server broadcasts DHCPOFFER and DHCPACK messages
750  destIpAddr.length = sizeof(Ipv4Addr);
751  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
752  }
753  else
754  {
755  //If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
756  //not set, then the server unicasts DHCPOFFER and DHCPACK messages
757  //to the client's hardware address and 'yiaddr' address
758  ancillary.destMacAddr = request->chaddr;
759  destIpAddr.length = sizeof(Ipv4Addr);
760  destIpAddr.ipv4Addr = yourIpAddr;
761  }
762  }
763  }
764  //DHCPNAK message?
765  else
766  {
767  //In all cases, when 'giaddr' is zero, the server broadcasts any
768  //DHCPNAK messages
769  destIpAddr.length = sizeof(Ipv4Addr);
770  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
771  }
772  }
773 
774  //Debug message
775  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
776  formatSystemTime(osGetSystemTime(), NULL), replyLen);
777 
778  //Dump the contents of the message for debugging purpose
779  dhcpDumpMessage(reply, replyLen);
780 
781  //Send DHCP reply
782  error = udpSendBuffer(interface, &srcIpAddr, DHCP_SERVER_PORT, &destIpAddr,
783  destPort, buffer, offset, &ancillary);
784 
785  //Free previously allocated memory
786  netBufferFree(buffer);
787  //Return status code
788  return error;
789 }
790 
791 
792 /**
793  * @brief Create a new binding
794  * @param[in] context Pointer to the DHCP server context
795  * @return Pointer to the newly created binding
796  **/
797 
799 {
800  uint_t i;
801  systime_t time;
802  DhcpServerBinding *binding;
803  DhcpServerBinding *oldestBinding;
804 
805  //Get current time
806  time = osGetSystemTime();
807 
808  //Keep track of the oldest binding
809  oldestBinding = NULL;
810 
811  //Loop through the list of bindings
812  for(i = 0; i < DHCP_SERVER_MAX_CLIENTS; i++)
813  {
814  //Point to the current binding
815  binding = &context->clientBinding[i];
816 
817  //Check whether the binding is available
818  if(macCompAddr(&binding->macAddr, &MAC_UNSPECIFIED_ADDR))
819  {
820  //Erase contents
821  osMemset(binding, 0, sizeof(DhcpServerBinding));
822  //Return a pointer to the newly created binding
823  return binding;
824  }
825  else
826  {
827  //Bindings that have been committed cannot be removed
828  if(!binding->validLease)
829  {
830  //Keep track of the oldest binding in the list
831  if(oldestBinding == NULL)
832  {
833  oldestBinding = binding;
834  }
835  else if((time - binding->timestamp) > (time - oldestBinding->timestamp))
836  {
837  oldestBinding = binding;
838  }
839  }
840  }
841  }
842 
843  //Any binding available in the list?
844  if(oldestBinding != NULL)
845  {
846  //Erase contents
847  osMemset(oldestBinding, 0, sizeof(DhcpServerBinding));
848  }
849 
850  //Return a pointer to the oldest binding
851  return oldestBinding;
852 }
853 
854 
855 /**
856  * @brief Search the list of bindings for a given MAC address
857  * @param[in] context Pointer to the DHCP server context
858  * @param[in] macAddr MAC address
859  * @return Pointer to the corresponding DHCP binding
860  **/
861 
863  const MacAddr *macAddr)
864 {
865  uint_t i;
866  DhcpServerBinding *binding;
867 
868  //Loop through the list of bindings
869  for(i = 0; i < DHCP_SERVER_MAX_CLIENTS; i++)
870  {
871  //Point to the current binding
872  binding = &context->clientBinding[i];
873 
874  //Valid binding?
875  if(!macCompAddr(&binding->macAddr, &MAC_UNSPECIFIED_ADDR))
876  {
877  //Check whether the current binding matches the specified MAC address
878  if(macCompAddr(&binding->macAddr, macAddr))
879  {
880  //Return the pointer to the corresponding binding
881  return binding;
882  }
883  }
884  }
885 
886  //No matching binding...
887  return NULL;
888 }
889 
890 
891 /**
892  * @brief Search the list of bindings for a given IP address
893  * @param[in] context Pointer to the DHCP server context
894  * @param[in] ipAddr IP address
895  * @return Pointer to the corresponding DHCP binding
896  **/
897 
900 {
901  uint_t i;
902  DhcpServerBinding *binding;
903 
904  //Loop through the list of bindings
905  for(i = 0; i < DHCP_SERVER_MAX_CLIENTS; i++)
906  {
907  //Point to the current binding
908  binding = &context->clientBinding[i];
909 
910  //Valid binding?
911  if(!macCompAddr(&binding->macAddr, &MAC_UNSPECIFIED_ADDR))
912  {
913  //Check whether the current binding matches the specified IP address
914  if(binding->ipAddr == ipAddr)
915  {
916  //Return the pointer to the corresponding binding
917  return binding;
918  }
919  }
920  }
921 
922  //No matching binding...
923  return NULL;
924 }
925 
926 
927 /**
928  * @brief Retrieve the next IP address to be used
929  * @param[in] context Pointer to the DHCP server context
930  * @param[out] ipAddr Next IP address to be used
931  * @return Error code
932  **/
933 
935 {
936  uint_t i;
937  DhcpServerBinding *binding;
938 
939  //Search the pool for any available IP address
940  for(i = 0; i < DHCP_SERVER_MAX_CLIENTS; i++)
941  {
942  //Check whether the current IP address is already allocated
943  binding = dhcpServerFindBindingByIpAddr(context, context->nextIpAddr);
944 
945  //If the IP address is available, then it can be assigned to a new client
946  if(binding == NULL)
947  *ipAddr = context->nextIpAddr;
948 
949  //Compute the next IP address that will be assigned by the DHCP server
950  if(ntohl(context->nextIpAddr) >= ntohl(context->settings.ipAddrRangeMax))
951  {
952  //Wrap around to the beginning of the pool
953  context->nextIpAddr = context->settings.ipAddrRangeMin;
954  }
955  else
956  {
957  //Increment IP address
958  context->nextIpAddr = htonl(ntohl(context->nextIpAddr) + 1);
959  }
960 
961  //If the IP address is available, we are done
962  if(binding == NULL)
963  return NO_ERROR;
964  }
965 
966  //No available addresses in the pool...
967  return ERROR_NO_ADDRESS;
968 }
969 
970 #endif
uint8_t message[]
Definition: chap.h:154
uint8_t type
Definition: coap_common.h:176
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
#define ntohl(value)
Definition: cpu_endian.h:422
#define htonl(value)
Definition: cpu_endian.h:414
#define ntohs(value)
Definition: cpu_endian.h:421
#define HTONL(value)
Definition: cpu_endian.h:411
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:77
Date and time management.
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
error_t dhcpAddOption(DhcpMessage *message, size_t *messageLen, uint8_t optionCode, const void *optionValue, size_t optionLen)
Append an option to a DHCP message.
Definition: dhcp_common.c:56
DhcpOption * dhcpGetOption(const DhcpMessage *message, size_t length, uint8_t optionCode)
Search a DHCP message for a given option.
Definition: dhcp_common.c:118
Definitions common to DHCP client and server.
DhcpMessage
Definition: dhcp_common.h:226
@ DHCP_OPCODE_BOOTREPLY
Definition: dhcp_common.h:68
@ DHCP_OPCODE_BOOTREQUEST
Definition: dhcp_common.h:67
#define DHCP_CLIENT_PORT
Definition: dhcp_common.h:41
#define DHCP_MIN_MSG_SIZE
Definition: dhcp_common.h:44
@ DHCP_OPT_END
Definition: dhcp_common.h:191
@ DHCP_OPT_DHCP_MESSAGE_TYPE
Definition: dhcp_common.h:159
@ DHCP_OPT_IP_ADDRESS_LEASE_TIME
Definition: dhcp_common.h:157
@ DHCP_OPT_SERVER_ID
Definition: dhcp_common.h:160
@ DHCP_OPT_DNS_SERVER
Definition: dhcp_common.h:112
@ DHCP_OPT_SUBNET_MASK
Definition: dhcp_common.h:107
@ DHCP_OPT_ROUTER
Definition: dhcp_common.h:109
@ DHCP_OPT_REQUESTED_IP_ADDR
Definition: dhcp_common.h:156
#define DHCP_SERVER_PORT
Definition: dhcp_common.h:40
@ DHCP_FLAG_BROADCAST
Definition: dhcp_common.h:79
#define DHCP_HARDWARE_TYPE_ETH
Definition: dhcp_common.h:49
DhcpMessageType
DHCP message types.
Definition: dhcp_common.h:88
@ DHCP_MSG_TYPE_RELEASE
Definition: dhcp_common.h:95
@ DHCP_MSG_TYPE_OFFER
Definition: dhcp_common.h:90
@ DHCP_MSG_TYPE_REQUEST
Definition: dhcp_common.h:91
@ DHCP_MSG_TYPE_DISCOVER
Definition: dhcp_common.h:89
@ DHCP_MSG_TYPE_ACK
Definition: dhcp_common.h:93
@ DHCP_MSG_TYPE_INFORM
Definition: dhcp_common.h:96
@ DHCP_MSG_TYPE_NAK
Definition: dhcp_common.h:94
@ DHCP_MSG_TYPE_DECLINE
Definition: dhcp_common.h:92
DhcpOption
Definition: dhcp_common.h:238
#define DHCP_MAGIC_COOKIE
Definition: dhcp_common.h:51
#define DHCP_MAX_MSG_SIZE
Definition: dhcp_common.h:46
error_t dhcpDumpMessage(const DhcpMessage *message, size_t length)
Dump DHCP message for debugging purpose.
Definition: dhcp_debug.c:158
Data logging functions for debugging purpose (DHCP)
DHCP server (Dynamic Host Configuration Protocol)
#define DhcpServerContext
Definition: dhcp_server.h:79
#define DHCP_SERVER_MAX_DNS_SERVERS
Definition: dhcp_server.h:67
#define DHCP_SERVER_MAX_CLIENTS
Definition: dhcp_server.h:53
DhcpServerBinding * dhcpServerFindBindingByMacAddr(DhcpServerContext *context, const MacAddr *macAddr)
Search the list of bindings for a given MAC address.
systime_t dhcpServerTickCounter
error_t dhcpServerSendReply(DhcpServerContext *context, uint8_t type, Ipv4Addr yourIpAddr, const DhcpMessage *request, size_t requestLen)
Send DHCP reply message.
void dhcpServerTick(DhcpServerContext *context)
DHCP server timer handler.
void dhcpServerParseRequest(DhcpServerContext *context, const DhcpMessage *message, size_t length)
Parse DHCPREQUEST message.
void dhcpServerParseRelease(DhcpServerContext *context, const DhcpMessage *message, size_t length)
Parse DHCPRELEASE message.
error_t dhcpServerGetNextIpAddr(DhcpServerContext *context, Ipv4Addr *ipAddr)
Retrieve the next IP address to be used.
void dhcpServerParseDiscover(DhcpServerContext *context, const DhcpMessage *message, size_t length)
Parse DHCPDISCOVER message.
void dhcpServerProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary, void *param)
Process incoming DHCP message.
void dhcpServerParseInform(DhcpServerContext *context, const DhcpMessage *message, size_t length)
Parse DHCPINFORM message.
DhcpServerBinding * dhcpServerCreateBinding(DhcpServerContext *context)
Create a new binding.
void dhcpServerParseDecline(DhcpServerContext *context, const DhcpMessage *message, size_t length)
Parse DHCPDECLINE message.
DhcpServerBinding * dhcpServerFindBindingByIpAddr(DhcpServerContext *context, Ipv4Addr ipAddr)
Search the list of bindings for a given IP address.
Helper functions for DHCP server.
uint8_t n
uint32_t time
error_t
Error codes.
Definition: error.h:43
@ ERROR_NO_ADDRESS
Definition: error.h:199
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
MacAddr
Definition: ethernet.h:195
Ipv4Addr ipAddr
Definition: ipcp.h:105
Ipv4Addr destIpAddr
Definition: ipcp.h:80
Ipv4Addr srcIpAddr
Definition: ipcp.h:79
#define IPV4_BROADCAST_ADDR
Definition: ipv4.h:112
#define ipv4CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv4.h:148
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:267
#define ipv4CompAddr(ipAddr1, ipAddr2)
Definition: ipv4.h:152
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:110
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:415
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
#define osMemset(p, value, length)
Definition: os_port.h:135
#define MAX_DELAY
Definition: os_port.h:77
#define timeCompare(t1, t2)
Definition: os_port.h:40
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define MAX(a, b)
Definition: os_port.h:67
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t systime_t
System time.
DHCP binding.
Definition: dhcp_server.h:112
systime_t timestamp
Timestamp.
Definition: dhcp_server.h:116
Ipv4Addr ipAddr
Client's IPv4 address.
Definition: dhcp_server.h:114
MacAddr macAddr
Client's MAC address.
Definition: dhcp_server.h:113
bool_t validLease
Valid lease.
Definition: dhcp_server.h:115
IP network address.
Definition: ip.h:79
IP pseudo header.
Definition: ip.h:99
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369
uint16_t destPort
Definition: tcp.h:340
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:905
error_t udpSendBuffer(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a UDP datagram.
Definition: udp.c:627
UdpHeader
Definition: udp.h:85