Update UC3 platform driver support to use the bitmasks defined in the header files...
[pub/USBasp.git] / Projects / Webserver / Lib / DHCPServerApp.c
index 84c57d0..4399e9a 100644 (file)
@@ -68,62 +68,83 @@ void DHCPServerApp_Callback(void)
        DHCP_Header_t* const AppData     = (DHCP_Header_t*)uip_appdata;\r
        uint16_t             AppDataSize = 0;\r
 \r
-       uint8_t DHCPMessageType;\r
-       if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))\r
-               return;\r
-\r
-       uip_ipaddr_t Netmask, GatewayIPAddress;\r
-       struct uip_eth_addr RemoteMACAddress;\r
-       uint32_t            TransactionID;\r
+       /* Only process when new data arrives - don't retransmit lost packets */\r
+       if (uip_newdata())\r
+       {\r
+               /* Get the DHCP message type (if present), otherwise early-abort */\r
+               uint8_t DHCPMessageType;\r
+               if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))\r
+                       return;\r
 \r
-       memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));\r
-       uip_getnetmask(&Netmask);\r
-       uip_getdraddr(&GatewayIPAddress);       \r
-       TransactionID = AppData->TransactionID;\r
+               uip_ipaddr_t        Netmask, GatewayIPAddress, PreferredClientIP;\r
+               struct uip_eth_addr RemoteMACAddress;\r
+               uint32_t            TransactionID;\r
 \r
-       switch (DHCPMessageType)\r
-       {\r
-               case DHCP_DISCOVER:\r
-                       AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, TransactionID);\r
+               /* Get configured network mask, gateway IP and extract out DHCP transaction ID and remote IP */\r
+               uip_getnetmask(&Netmask);\r
+               uip_getdraddr(&GatewayIPAddress);\r
+               memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));\r
+               TransactionID = AppData->TransactionID;\r
 \r
-                       AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,\r
-                                                           sizeof(uip_ipaddr_t), &Netmask);\r
-                       AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,\r
-                                                           sizeof(uip_ipaddr_t), &GatewayIPAddress);\r
-                       \r
-                       /* Send the DHCP OFFER packet */\r
-                       uip_poll_conn(BroadcastConnection);\r
-                       memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));\r
-                       uip_udp_send(AppDataSize);\r
+               /* Try to extract out the client's preferred IP address if it is indicated in the packet */\r
+               if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, &PreferredClientIP)))\r
+                 memcpy(&PreferredClientIP, &uip_all_zeroes_addr, sizeof(uip_ipaddr_t));       \r
+               \r
+               switch (DHCPMessageType)\r
+               {\r
+                       case DHCP_DISCOVER:\r
+                               /* If no preference was made or the preferred IP is already taken, find a new address */\r
+                               if (DHCPServerApp_CheckIfIPLeased(&PreferredClientIP))\r
+                                 DHCPServerApp_GetUnleasedIP(&PreferredClientIP);\r
 \r
-                       break;\r
-               case DHCP_REQUEST:\r
-                       if (!(DHCPServerApp_CheckIfIPLeased(&AppData->YourIP)))\r
-                       {\r
-                               AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, TransactionID);\r
+                               /* Create a new DHCP OFFER packet with the offered IP address */\r
+                               AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, &PreferredClientIP, TransactionID);\r
 \r
+                               /* Add network mask and router information to the list of DHCP OFFER packet options */\r
                                AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,\r
                                                                                                        sizeof(uip_ipaddr_t), &Netmask);\r
                                AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,\r
-                                                                                                       sizeof(uip_ipaddr_t), &GatewayIPAddress);\r
-\r
-                               DHCPServerApp_LeaseIP(&AppData->YourIP);\r
-                       }\r
-                       else\r
-                       {\r
-                               AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, TransactionID);                       \r
-                       }\r
+                                                                       sizeof(uip_ipaddr_t), &GatewayIPAddress);\r
+\r
+                               /* Send the DHCP OFFER packet */\r
+                               uip_poll_conn(BroadcastConnection);\r
+                               memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));\r
+                               uip_udp_send(AppDataSize);\r
+\r
+                               break;\r
+                       case DHCP_REQUEST:\r
+                               /* Check to see if the requested IP address has already been leased to a client */\r
+                               if (!(DHCPServerApp_CheckIfIPLeased(&PreferredClientIP)))\r
+                               {\r
+                                       /* Create a new DHCP ACK packet to accept the IP address lease */                                       \r
+                                       AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, &PreferredClientIP, TransactionID);\r
+\r
+                                       /* Add network mask and router information to the list of DHCP ACK packet options */\r
+                                       AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,\r
+                                                                                                               sizeof(uip_ipaddr_t), &Netmask);\r
+                                       AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,\r
+                                                                           sizeof(uip_ipaddr_t), &GatewayIPAddress);\r
+\r
+                                       /* Mark the requested IP as leased to a client */\r
+                                       DHCPServerApp_LeaseIP(&PreferredClientIP);\r
+                               }\r
+                               else\r
+                               {\r
+                                       /* Create a new DHCP NAK packet to reject the requested allocation */\r
+                                       AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, &uip_all_zeroes_addr, TransactionID);\r
+                               }\r
+                               \r
+                               /* Send the DHCP ACK or NAK packet */\r
+                               uip_poll_conn(BroadcastConnection);\r
+                               memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));\r
+                               uip_udp_send(AppDataSize);\r
                        \r
-                       /* Send the DHCP ACK or NAK packet */\r
-                       uip_poll_conn(BroadcastConnection);\r
-                       memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));\r
-                       uip_udp_send(AppDataSize);\r
-               \r
-                       break;\r
-               case DHCP_RELEASE:\r
-                       /* Mark the IP address as released in the allocation table */\r
-                       DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);\r
-                       break;\r
+                               break;\r
+                       case DHCP_RELEASE:\r
+                               /* Mark the IP address as released in the allocation table */\r
+                               DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);\r
+                               break;\r
+               }\r
        }\r
 }\r
 \r
@@ -133,14 +154,16 @@ void DHCPServerApp_Callback(void)
  *  \param[out] DHCPHeader             Location in the packet buffer where the BOOTP header should be written to\r
  *  \param[in]  DHCPMessageType        DHCP Message type, such as DHCP_DISCOVER\r
  *  \param[in]  ClientHardwareAddress  Client MAC address the created transaction should be directed to\r
+ *  \param[in]  PreferredClientIP      Preferred IP that should be given to the client if it is unallocated\r
  *  \param[in]  TransactionID          Transaction ID the created transaction should be associated with\r
  *\r
  *  \return Size in bytes of the created DHCP packet\r
  */\r
 static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,\r
                                              const uint8_t DHCPMessageType,\r
-                                             struct uip_eth_addr* ClientHardwareAddress,\r
-                                             uint32_t TransactionID)\r
+                                             const struct uip_eth_addr* const ClientHardwareAddress,\r
+                                                                                        const uip_ipaddr_t* const PreferredClientIP,\r
+                                             const uint32_t TransactionID)\r
 {\r
        /* Erase existing packet data so that we start will all 0x00 DHCP header data */\r
        memset(DHCPHeader, 0, sizeof(DHCP_Header_t));\r
@@ -153,8 +176,7 @@ static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
        DHCPHeader->ElapsedSeconds        = 0;\r
        DHCPHeader->Flags                 = 0;\r
        memcpy(&DHCPHeader->NextServerIP, &uip_hostaddr, sizeof(uip_ipaddr_t));\r
-       if (uip_ipaddr_cmp(&DHCPHeader->YourIP, &uip_all_zeroes_addr))\r
-         DHCPServerApp_GetUnleasedIP(&DHCPHeader->YourIP);\r
+       memcpy(&DHCPHeader->YourIP, PreferredClientIP, sizeof(uip_ipaddr_t));\r
        memcpy(&DHCPHeader->ClientHardwareAddress, ClientHardwareAddress, sizeof(struct uip_eth_addr));\r
        DHCPHeader->Cookie                = DHCP_MAGIC_COOKIE;\r
          \r
@@ -176,12 +198,13 @@ static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
  *\r
  *  \return Boolean true if the IP has already been leased to a client, false otherwise.\r
  */\r
-static bool DHCPServerApp_CheckIfIPLeased(uip_ipaddr_t* IPAddress)\r
+static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress)\r
 {\r
        uint8_t Byte = (IPAddress->u8[3] / 8);\r
        uint8_t Mask = (1 << (IPAddress->u8[3] % 8));\r
        \r
-       if (!(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))\r
+       /* Make sure that the requested IP address isn't already leased to the virtual server or another client */\r
+       if (IPAddress->u8[3] && !(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))\r
          return false;\r
        else\r
          return true;\r
@@ -191,14 +214,17 @@ static bool DHCPServerApp_CheckIfIPLeased(uip_ipaddr_t* IPAddress)
  *\r
  *  \param[out] NewIPAddress  Location where the generated IP Address should be stored\r
  */\r
-static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* NewIPAddress)\r
+static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress)\r
 {\r
        uip_ipaddr_copy(NewIPAddress, &uip_hostaddr);\r
        \r
+       /** Look through the current subnet, skipping the broadcast and zero IP addresses */\r
        for (uint8_t IP = 1; IP < 254; IP++)\r
        {\r
+               /* Update new IP address to lease with the current IP address to test */\r
                NewIPAddress->u8[3] = IP;\r
                \r
+               /* If we've found an unleased IP, abort with the updated IP stored for the called */\r
                if (!(DHCPServerApp_CheckIfIPLeased(NewIPAddress)))\r
                  return;\r
        }\r
@@ -211,11 +237,12 @@ static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* NewIPAddress)
  *\r
  *  \pre The IP address must be within the same /24 subnet as the virtual webserver.\r
  */\r
-static void DHCPServerApp_LeaseIP(uip_ipaddr_t* IPAddress)\r
+static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress)\r
 {\r
        uint8_t Byte = (IPAddress->u8[3] / 8);\r
        uint8_t Mask = (1 << (IPAddress->u8[3] % 8));\r
        \r
+       /* Mark the IP address as leased in the allocation table */\r
        LeasedIPs[Byte] |= Mask;\r
 }\r
 \r
@@ -226,11 +253,12 @@ static void DHCPServerApp_LeaseIP(uip_ipaddr_t* IPAddress)
  *\r
  *  \pre The IP address must be within the same /24 subnet as the virtual webserver.\r
  */\r
-static void DHCPServerApp_UnleaseIP(uip_ipaddr_t* IPAddress)\r
+static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress)\r
 {\r
        uint8_t Byte = (IPAddress->u8[3] / 8);\r
        uint8_t Mask = (1 << (IPAddress->u8[3] % 8));\r
        \r
+       /* Mark the IP address as unleased in the allocation table */\r
        LeasedIPs[Byte] &= ~Mask;\r
 }\r
 #endif\r