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