123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- LUFA Library
- Copyright (C) Dean Camera, 2014.
-
- dean [at] fourwalledcubicle [dot] com
- www.lufa-lib.org
- */
-
- /*
- Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that the copyright notice and this
- permission notice and warranty disclaimer appear in supporting
- documentation, and that the name of the author not be used in
- advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
-
- The author disclaims all warranties with regard to this
- software, including all implied warranties of merchantability
- and fitness. In no event shall the author be liable for any
- special, indirect or consequential damages or any damages
- whatsoever resulting from loss of use, data or profits, whether
- in an action of contract, negligence or other tortious action,
- arising out of or in connection with the use or performance of
- this software.
- */
-
- /** \file
- *
- * DHCP Server Application. When connected to the uIP stack, this will send IP configuration settings to a
- * DHCP client on the network.
- */
-
- #define INCLUDE_FROM_DHCPSERVERAPP_C
- #include "DHCPServerApp.h"
-
- #if defined(ENABLE_DHCP_SERVER) || defined(__DOXYGEN__)
-
- struct uip_conn* BroadcastConnection;
-
- uint8_t LeasedIPs[255 / 8];
-
- /** Initialization function for the DHCP server. */
- void DHCPServerApp_Init(void)
- {
- /* Listen on port 67 for DHCP server connections from hosts */
- uip_listen(HTONS(DHCP_SERVER_PORT));
-
- /* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
- struct uip_udp_conn* BroadcastConnection = uip_udp_new(&uip_broadcast_addr, HTONS(DHCP_CLIENT_PORT));
-
- /* If the connection was successfully created, bind it to the local DHCP client port */
- if (BroadcastConnection != NULL)
- uip_udp_bind(BroadcastConnection, HTONS(DHCP_SERVER_PORT));
-
- /* Set all IP addresses as unleased */
- memset(LeasedIPs, 0x00, sizeof(LeasedIPs));
- }
-
- /** uIP stack application callback for the DHCP server. This function must be called each time the TCP/IP stack
- * needs a UDP packet to be processed.
- */
- void DHCPServerApp_Callback(void)
- {
- DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
- uint16_t AppDataSize = 0;
-
- /* Only process when new data arrives - don't retransmit lost packets */
- if (uip_newdata())
- {
- /* Get the DHCP message type (if present), otherwise early-abort */
- uint8_t DHCPMessageType;
- if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))
- return;
-
- uip_ipaddr_t Netmask, GatewayIPAddress, PreferredClientIP;
- struct uip_eth_addr RemoteMACAddress;
- uint32_t TransactionID;
-
- /* Get configured network mask, gateway IP and extract out DHCP transaction ID and remote IP */
- uip_getnetmask(&Netmask);
- uip_getdraddr(&GatewayIPAddress);
- memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));
- TransactionID = AppData->TransactionID;
-
- /* Try to extract out the client's preferred IP address if it is indicated in the packet */
- if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, &PreferredClientIP)))
- memcpy(&PreferredClientIP, &uip_all_zeroes_addr, sizeof(uip_ipaddr_t));
-
- switch (DHCPMessageType)
- {
- case DHCP_DISCOVER:
- /* If no preference was made or the preferred IP is already taken, find a new address */
- if (DHCPServerApp_CheckIfIPLeased(&PreferredClientIP))
- DHCPServerApp_GetUnleasedIP(&PreferredClientIP);
-
- /* Create a new DHCP OFFER packet with the offered IP address */
- AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, &PreferredClientIP, TransactionID);
-
- /* Add network mask and router information to the list of DHCP OFFER packet options */
- AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
- sizeof(uip_ipaddr_t), &Netmask);
- AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
- sizeof(uip_ipaddr_t), &GatewayIPAddress);
-
- /* Send the DHCP OFFER packet */
- uip_poll_conn(BroadcastConnection);
- memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
- uip_udp_send(AppDataSize);
-
- break;
- case DHCP_REQUEST:
- /* Check to see if the requested IP address has already been leased to a client */
- if (!(DHCPServerApp_CheckIfIPLeased(&PreferredClientIP)))
- {
- /* Create a new DHCP ACK packet to accept the IP address lease */
- AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, &PreferredClientIP, TransactionID);
-
- /* Add network mask and router information to the list of DHCP ACK packet options */
- AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
- sizeof(uip_ipaddr_t), &Netmask);
- AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
- sizeof(uip_ipaddr_t), &GatewayIPAddress);
-
- /* Mark the requested IP as leased to a client */
- DHCPServerApp_LeaseIP(&PreferredClientIP);
- }
- else
- {
- /* Create a new DHCP NAK packet to reject the requested allocation */
- AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, &uip_all_zeroes_addr, TransactionID);
- }
-
- /* Send the DHCP ACK or NAK packet */
- uip_poll_conn(BroadcastConnection);
- memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
- uip_udp_send(AppDataSize);
-
- break;
- case DHCP_RELEASE:
- /* Mark the IP address as released in the allocation table */
- DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);
- break;
- }
- }
- }
-
- /** Fills the DHCP packet response with the appropriate BOOTP header for DHCP. This fills out all the required
- * fields, leaving only the additional DHCP options to be added to the packet before it is sent to the DHCP client.
- *
- * \param[out] DHCPHeader Location in the packet buffer where the BOOTP header should be written to
- * \param[in] DHCPMessageType DHCP Message type, such as DHCP_DISCOVER
- * \param[in] ClientHardwareAddress Client MAC address the created transaction should be directed to
- * \param[in] PreferredClientIP Preferred IP that should be given to the client if it is unallocated
- * \param[in] TransactionID Transaction ID the created transaction should be associated with
- *
- * \return Size in bytes of the created DHCP packet
- */
- static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
- const uint8_t DHCPMessageType,
- const struct uip_eth_addr* const ClientHardwareAddress,
- const uip_ipaddr_t* const PreferredClientIP,
- const uint32_t TransactionID)
- {
- /* Erase existing packet data so that we start will all 0x00 DHCP header data */
- memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
-
- DHCPHeader->Operation = DHCPMessageType;
- DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
- DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
- DHCPHeader->Hops = 0;
- DHCPHeader->TransactionID = TransactionID;
- DHCPHeader->ElapsedSeconds = 0;
- DHCPHeader->Flags = 0;
- memcpy(&DHCPHeader->NextServerIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
- memcpy(&DHCPHeader->YourIP, PreferredClientIP, sizeof(uip_ipaddr_t));
- memcpy(&DHCPHeader->ClientHardwareAddress, ClientHardwareAddress, sizeof(struct uip_eth_addr));
- DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
-
- /* Add a DHCP message type and terminator options to the start of the DHCP options field */
- DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
- DHCPHeader->Options[1] = 1;
- DHCPHeader->Options[2] = DHCPMessageType;
- DHCPHeader->Options[3] = DHCP_OPTION_END;
-
- /* Calculate the total number of bytes added to the outgoing packet */
- return (sizeof(DHCP_Header_t) + 4);
- }
-
- /** Checks to see if the nominated IP address has already been allocated to a client.
- *
- * \param[in] IPAddress IP Address whose lease status should be checked
- *
- * \pre The IP address must be within the same /24 subnet as the virtual webserver.
- *
- * \return Boolean \c true if the IP has already been leased to a client, \c false otherwise.
- */
- static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress)
- {
- uint8_t Byte = (IPAddress->u8[3] / 8);
- uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
-
- /* Make sure that the requested IP address isn't already leased to the virtual server or another client */
- if (IPAddress->u8[3] && !(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))
- return false;
- else
- return true;
- }
-
- /** Retrieves the next unleased IP in the IP address pool.
- *
- * \param[out] NewIPAddress Location where the generated IP Address should be stored
- */
- static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress)
- {
- uip_ipaddr_copy(NewIPAddress, &uip_hostaddr);
-
- /** Look through the current subnet, skipping the broadcast and zero IP addresses */
- for (uint8_t IP = 1; IP < 254; IP++)
- {
- /* Update new IP address to lease with the current IP address to test */
- NewIPAddress->u8[3] = IP;
-
- /* If we've found an unleased IP, abort with the updated IP stored for the called */
- if (!(DHCPServerApp_CheckIfIPLeased(NewIPAddress)))
- return;
- }
- }
-
- /** Marks the given IP Address as leased in the address pool, so that it will not be
- * allocated to another client unless it is first released.
- *
- * \param[in] IPAddress IP Address to mark as leased
- *
- * \pre The IP address must be within the same /24 subnet as the virtual webserver.
- */
- static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress)
- {
- uint8_t Byte = (IPAddress->u8[3] / 8);
- uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
-
- /* Mark the IP address as leased in the allocation table */
- LeasedIPs[Byte] |= Mask;
- }
-
- /** Marks the given IP Address as not leased in the address pool, so that it can be
- * allocated to another client upon request.
- *
- * \param[in] IPAddress IP Address to mark as not leased
- *
- * \pre The IP address must be within the same /24 subnet as the virtual webserver.
- */
- static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress)
- {
- uint8_t Byte = (IPAddress->u8[3] / 8);
- uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
-
- /* Mark the IP address as unleased in the allocation table */
- LeasedIPs[Byte] &= ~Mask;
- }
- #endif
|