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