From 16ea5aa7a2e5f326f8ff129e740a19bb3fb7829f Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Wed, 3 Feb 2010 10:39:33 +0000 Subject: Add a TELNET server to the webserver project, which currently can list active TCP connections. --- Projects/Webserver/Lib/DHCPApp.c | 263 ------------------------------- Projects/Webserver/Lib/DHCPApp.h | 166 ------------------- Projects/Webserver/Lib/DHCPClientApp.c | 263 +++++++++++++++++++++++++++++++ Projects/Webserver/Lib/DHCPClientApp.h | 166 +++++++++++++++++++ Projects/Webserver/Lib/HTTPServerApp.c | 56 +++---- Projects/Webserver/Lib/HTTPServerApp.h | 2 +- Projects/Webserver/Lib/TELNETServerApp.c | 147 +++++++++++++++++ Projects/Webserver/Lib/TELNETServerApp.h | 68 ++++++++ Projects/Webserver/Lib/uIPManagement.c | 39 ++++- Projects/Webserver/Lib/uIPManagement.h | 5 +- Projects/Webserver/Lib/uip/clock.c | 5 +- Projects/Webserver/Lib/uip/clock.h | 1 + Projects/Webserver/Lib/uip/uipopt.h | 60 ++++--- Projects/Webserver/makefile | 9 +- 14 files changed, 763 insertions(+), 487 deletions(-) delete mode 100644 Projects/Webserver/Lib/DHCPApp.c delete mode 100644 Projects/Webserver/Lib/DHCPApp.h create mode 100644 Projects/Webserver/Lib/DHCPClientApp.c create mode 100644 Projects/Webserver/Lib/DHCPClientApp.h create mode 100644 Projects/Webserver/Lib/TELNETServerApp.c create mode 100644 Projects/Webserver/Lib/TELNETServerApp.h (limited to 'Projects/Webserver') diff --git a/Projects/Webserver/Lib/DHCPApp.c b/Projects/Webserver/Lib/DHCPApp.c deleted file mode 100644 index 2aad7a65b..000000000 --- a/Projects/Webserver/Lib/DHCPApp.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2010. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2010 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 disclaim 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 Client Application. When connected to the uIP stack, this will retrieve IP configuration settings from the - * DHCP server on the network. - */ - -#include "DHCPApp.h" - -#if defined(ENABLE_DHCP) || defined(__DOXYGEN__) -/** Timer for managing the timeout period for a DHCP server to respond */ -struct timer DHCPTimer; - -/** Initialization function for the DHCP client. */ -void DHCPApp_Init(void) -{ - uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate; - - /* Create a new UDP connection to the DHCP server port for the DHCP solicitation */ - uip_ipaddr_t DHCPServerIPAddress; - uip_ipaddr(&DHCPServerIPAddress, 255, 255, 255, 255); - AppState->Connection = uip_udp_new(&DHCPServerIPAddress, HTONS(DHCPC_SERVER_PORT)); - - /* If the connection was sucessfully created, bind it to the local DHCP client port */ - if(AppState->Connection != NULL) - { - uip_udp_bind(AppState->Connection, HTONS(DHCPC_CLIENT_PORT)); - AppState->CurrentState = DHCP_STATE_SendDiscover; - } - - /* Set timeout period to half a second for a DHCP server to respond */ - timer_set(&DHCPTimer, CLOCK_SECOND / 2); -} - -/** uIP stack application callback for the DHCP client. This function must be called each time the TCP/IP stack - * needs a UDP packet to be processed. - */ -void DHCPApp_Callback(void) -{ - uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate; - DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata; - uint16_t AppDataSize = 0; - - switch (AppState->CurrentState) - { - case DHCP_STATE_SendDiscover: - /* Clear all DHCP settings, reset client IP address */ - memset(&AppState->DHCPOffer_Data, 0x00, sizeof(AppState->DHCPOffer_Data)); - uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.AllocatedIP); - - /* Fill out the DHCP response header */ - AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState); - - /* Add the required DHCP options list to the packet */ - uint8_t RequiredOptionList[] = {DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_DNS_SERVER}; - AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList), - RequiredOptionList); - - /* Send the DHCP DISCOVER packet */ - uip_udp_send(AppDataSize); - - /* Reset the timeout timer, progress to next state */ - timer_reset(&DHCPTimer); - AppState->CurrentState = DHCP_STATE_WaitForOffer; - - break; - case DHCP_STATE_WaitForOffer: - if (!(uip_newdata())) - { - /* Check if the DHCP timeout period has expired while waiting for a response */ - if (timer_expired(&DHCPTimer)) - AppState->CurrentState = DHCP_STATE_SendDiscover; - - break; - } - - uint8_t OfferResponse_MessageType; - if ((AppData->TransactionID == DHCP_TRANSACTION_ID) && - DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) && - (OfferResponse_MessageType == DHCP_OFFER)) - { - /* Received a DHCP offer for an IP address, copy over values for later request */ - memcpy(&AppState->DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t)); - DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPOffer_Data.Netmask); - DHCPApp_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPOffer_Data.GatewayIP); - DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPOffer_Data.ServerIP); - - timer_reset(&DHCPTimer); - AppState->CurrentState = DHCP_STATE_SendRequest; - } - - break; - case DHCP_STATE_SendRequest: - /* Fill out the DHCP response header */ - AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState); - - /* Add the DHCP REQUESTED IP ADDRESS option to the packet */ - AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t), - &AppState->DHCPOffer_Data.AllocatedIP); - - /* Add the DHCP SERVER IP ADDRESS option to the packet */ - AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t), - &AppState->DHCPOffer_Data.ServerIP); - - /* Send the DHCP REQUEST packet */ - uip_udp_send(AppDataSize); - - /* Reset the timeout timer, progress to next state */ - timer_reset(&DHCPTimer); - AppState->CurrentState = DHCP_STATE_WaitForACK; - - break; - case DHCP_STATE_WaitForACK: - if (!(uip_newdata())) - { - /* Check if the DHCP timeout period has expired while waiting for a response */ - if (timer_expired(&DHCPTimer)) - AppState->CurrentState = DHCP_STATE_SendDiscover; - - break; - } - - uint8_t RequestResponse_MessageType; - if ((AppData->TransactionID == DHCP_TRANSACTION_ID) && - DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) && - (RequestResponse_MessageType == DHCP_ACK)) - { - /* Set the new network parameters from the DHCP server */ - uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.AllocatedIP); - uip_setnetmask((uip_ipaddr_t*)&AppState->DHCPOffer_Data.Netmask); - uip_setdraddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.GatewayIP); - - AppState->CurrentState = DHCP_STATE_AddressLeased; - } - - 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 server. - * - * \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] AppState Application state of the current UDP connection - * - * \return Size in bytes of the created DHCP packet - */ -uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState) -{ - /* Erase existing packet data so that we start will all 0x00 DHCP header data */ - memset(DHCPHeader, 0, sizeof(DHCP_Header_t)); - - /* Fill out the DHCP packet header */ - DHCPHeader->Operation = DHCP_OP_BOOTREQUEST; - DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET; - DHCPHeader->HardwareAddressLength = sizeof(MACAddress); - DHCPHeader->Hops = 0; - DHCPHeader->TransactionID = DHCP_TRANSACTION_ID; - DHCPHeader->ElapsedSeconds = 0; - DHCPHeader->Flags = HTONS(BOOTP_BROADCAST); - memcpy(&DHCPHeader->ClientIP, &uip_hostaddr, sizeof(uip_ipaddr_t)); - memcpy(&DHCPHeader->YourIP, &AppState->DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t)); - memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t)); - memcpy(&DHCPHeader->ClientHardwareAddress, &MACAddress, sizeof(struct uip_eth_addr)); - DHCPHeader->Cookie = DHCP_MAGIC_COOKIE; - - /* Add a DHCP 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); -} - -/** Sets the given DHCP option in the DHCP packet's option list. This automatically moves the - * end of options terminator past the new option in the options list. - * - * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list - * \param[in] Option DHCP option to add to the list - * \param[in] DataLen Size in bytes of the option data to add - * \param[in] OptionData Buffer where the option's data is to be sourced from - * - * \return Number of bytes added to the DHCP packet - */ -uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData) -{ - /* Skip through the DHCP options list until the terminator option is found */ - while (*DHCPOptionList != DHCP_OPTION_END) - DHCPOptionList += (DHCPOptionList[1] + 2); - - /* Overwrite the existing terminator with the new option, add a new terminator at the end of the list */ - DHCPOptionList[0] = Option; - DHCPOptionList[1] = DataLen; - memcpy(&DHCPOptionList[2], OptionData, DataLen); - DHCPOptionList[2 + DataLen] = DHCP_OPTION_END; - - /* Calculate the total number of bytes added to the outgoing packet */ - return (2 + DataLen); -} - -/** Retrieves the given option's data (if present) from the DHCP packet's options list. - * - * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list - * \param[in] Option DHCP option to retrieve to the list - * \param[out] Destination Buffer where the option's data is to be written to if found - * - * \return Boolean true if the option was found in the DHCP packet's options list, false otherwise - */ -bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination) -{ - /* Look through the incomming DHCP packet's options list for the requested option */ - while (*DHCPOptionList != DHCP_OPTION_END) - { - /* Check if the current DHCP option in the packet is the one requested */ - if (DHCPOptionList[0] == Option) - { - /* Copy request option's data to the destination buffer */ - memcpy(Destination, &DHCPOptionList[2], DHCPOptionList[1]); - - /* Indicate that the requested option data was sucessfully retrieved */ - return true; - } - - /* Skip to next DHCP option in the options list */ - DHCPOptionList += (DHCPOptionList[1] + 2); - } - - /* Requested option not found in the incomming packet's DHCP options list */ - return false; -} -#endif diff --git a/Projects/Webserver/Lib/DHCPApp.h b/Projects/Webserver/Lib/DHCPApp.h deleted file mode 100644 index 5d11d8236..000000000 --- a/Projects/Webserver/Lib/DHCPApp.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2010. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2010 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 disclaim 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 - * - * Header file for DHCPApp.c. - */ - -#ifndef _DHCP_APP_H_ -#define _DHCP_APP_H_ - - /* Includes: */ - #include - - #include - - #include "../Webserver.h" - - /* Macros: */ - /** UDP listen port for a BOOTP server */ - #define DHCPC_SERVER_PORT 67 - - /** UDP listen port for a BOOTP client */ - #define DHCPC_CLIENT_PORT 68 - - /** BOOTP message type for a BOOTP REQUEST message */ - #define DHCP_OP_BOOTREQUEST 0x01 - - /** BOOTP message type for a BOOTP REPLY message */ - #define DHCP_OP_BOOTREPLY 0x02 - - /** BOOTP flag for a BOOTP broadcast message */ - #define BOOTP_BROADCAST 0x8000 - - /** Magic DHCP cookie for a BOOTP message to identify it as a DHCP message */ - #define DHCP_MAGIC_COOKIE 0x63538263 - - /** Unique transaction ID used to identify DHCP responses to the client */ - #define DHCP_TRANSACTION_ID 0x13245466 - - /** DHCP message type for a DISCOVER message */ - #define DHCP_DISCOVER 1 - - /** DHCP message type for an OFFER message */ - #define DHCP_OFFER 2 - - /** DHCP message type for a REQUEST message */ - #define DHCP_REQUEST 3 - - /** DHCP message type for a DECLINE message */ - #define DHCP_DECLINE 4 - - /** DHCP message type for an ACK message */ - #define DHCP_ACK 5 - - /** DHCP message type for a NAK message */ - #define DHCP_NAK 6 - - /** DHCP message type for a RELEASE message */ - #define DHCP_RELEASE 7 - - /** DHCP medium type for standard Ethernet */ - #define DHCP_HTYPE_ETHERNET 1 - - /** DHCP message option for the network subnet mask */ - #define DHCP_OPTION_SUBNET_MASK 1 - - /** DHCP message option for the network gateway IP */ - #define DHCP_OPTION_ROUTER 3 - - /** DHCP message option for the network DNS server */ - #define DHCP_OPTION_DNS_SERVER 6 - - /** DHCP message option for the requested client IP address */ - #define DHCP_OPTION_REQ_IPADDR 50 - - /** DHCP message option for the IP address lease time */ - #define DHCP_OPTION_LEASE_TIME 51 - - /** DHCP message option for the DHCP message type */ - #define DHCP_OPTION_MSG_TYPE 53 - - /** DHCP message option for the DHCP server IP */ - #define DHCP_OPTION_SERVER_ID 54 - - /** DHCP message option for the list of required options from the server */ - #define DHCP_OPTION_REQ_LIST 55 - - /** DHCP message option for the options list terminator */ - #define DHCP_OPTION_END 255 - - /* Type Defines: */ - /** Type define for a DHCP packet inside an Ethernet frame. */ - typedef struct - { - uint8_t Operation; /**< DHCP operation, either DHCP_OP_BOOTREQUEST or DHCP_OP_BOOTREPLY */ - uint8_t HardwareType; /**< Hardware carrier type constant */ - uint8_t HardwareAddressLength; /**< Length in bytes of a hardware (MAC) address on the network */ - uint8_t Hops; /**< Number of hops required to reach the server, unused */ - - uint32_t TransactionID; /**< Unique ID of the DHCP packet, for positive matching between sent and received packets */ - - uint16_t ElapsedSeconds; /**< Elapsed seconds since the request was made */ - uint16_t Flags; /**< BOOTP packet flags */ - - uip_ipaddr_t ClientIP; /**< Client IP address, if already leased an IP */ - uip_ipaddr_t YourIP; /**< Client IP address */ - uip_ipaddr_t NextServerIP; /**< Legacy BOOTP protocol field, unused for DHCP */ - uip_ipaddr_t RelayAgentIP; /**< Legacy BOOTP protocol field, unused for DHCP */ - - uint8_t ClientHardwareAddress[16]; /**< Hardware (MAC) address of the client making a request to the DHCP server */ - uint8_t ServerHostnameString[64]; /**< Legacy BOOTP protocol field, unused for DHCP */ - uint8_t BootFileName[128]; /**< Legacy BOOTP protocol field, unused for DHCP */ - - uint32_t Cookie; /**< Magic BOOTP protocol cookie to indicate a valid packet */ - - uint8_t Options[]; /** DHCP message options */ - } DHCP_Header_t; - - /* Enums: */ - /** States for each DHCP connection to a DHCP client. */ - enum DHCP_States_t - { - DHCP_STATE_SendDiscover, /**< Send DISCOVER packet to retrieve DHCP lease offers */ - DHCP_STATE_WaitForOffer, /**< Waiting for OFFER packet giving available DHCP leases */ - DHCP_STATE_SendRequest, /**< Send REQUEST packet to request a DHCP lease */ - DHCP_STATE_WaitForACK, /**< Wait for ACK packet to complete the DHCP lease */ - DHCP_STATE_AddressLeased, /**< DHCP address has been leased from a DHCP server */ - }; - - /* Function Prototypes: */ - void DHCPApp_Init(void); - void DHCPApp_Callback(void); - - uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState); - uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData); - bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination); - -#endif diff --git a/Projects/Webserver/Lib/DHCPClientApp.c b/Projects/Webserver/Lib/DHCPClientApp.c new file mode 100644 index 000000000..79170fabe --- /dev/null +++ b/Projects/Webserver/Lib/DHCPClientApp.c @@ -0,0 +1,263 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 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 disclaim 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 Client Application. When connected to the uIP stack, this will retrieve IP configuration settings from the + * DHCP server on the network. + */ + +#include "DHCPClientApp.h" + +#if defined(ENABLE_DHCP) || defined(__DOXYGEN__) +/** Timer for managing the timeout period for a DHCP server to respond */ +struct timer DHCPTimer; + +/** Initialization function for the DHCP client. */ +void DHCPClientApp_Init(void) +{ + uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate; + + /* Create a new UDP connection to the DHCP server port for the DHCP solicitation */ + uip_ipaddr_t DHCPServerIPAddress; + uip_ipaddr(&DHCPServerIPAddress, 255, 255, 255, 255); + AppState->DHCPClient.Connection = uip_udp_new(&DHCPServerIPAddress, HTONS(DHCPC_SERVER_PORT)); + + /* If the connection was sucessfully created, bind it to the local DHCP client port */ + if(AppState->DHCPClient.Connection != NULL) + { + uip_udp_bind(AppState->DHCPClient.Connection, HTONS(DHCPC_CLIENT_PORT)); + AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover; + } + + /* Set timeout period to half a second for a DHCP server to respond */ + timer_set(&DHCPTimer, CLOCK_SECOND / 2); +} + +/** uIP stack application callback for the DHCP client. This function must be called each time the TCP/IP stack + * needs a UDP packet to be processed. + */ +void DHCPClientApp_Callback(void) +{ + uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate; + DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata; + uint16_t AppDataSize = 0; + + switch (AppState->DHCPClient.CurrentState) + { + case DHCP_STATE_SendDiscover: + /* Clear all DHCP settings, reset client IP address */ + memset(&AppState->DHCPClient.DHCPOffer_Data, 0x00, sizeof(AppState->DHCPClient.DHCPOffer_Data)); + uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP); + + /* Fill out the DHCP response header */ + AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState); + + /* Add the required DHCP options list to the packet */ + uint8_t RequiredOptionList[] = {DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_DNS_SERVER}; + AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList), + RequiredOptionList); + + /* Send the DHCP DISCOVER packet */ + uip_udp_send(AppDataSize); + + /* Reset the timeout timer, progress to next state */ + timer_reset(&DHCPTimer); + AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForOffer; + + break; + case DHCP_STATE_WaitForOffer: + if (!(uip_newdata())) + { + /* Check if the DHCP timeout period has expired while waiting for a response */ + if (timer_expired(&DHCPTimer)) + AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover; + + break; + } + + uint8_t OfferResponse_MessageType; + if ((AppData->TransactionID == DHCP_TRANSACTION_ID) && + DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) && + (OfferResponse_MessageType == DHCP_OFFER)) + { + /* Received a DHCP offer for an IP address, copy over values for later request */ + memcpy(&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t)); + DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPClient.DHCPOffer_Data.Netmask); + DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPClient.DHCPOffer_Data.GatewayIP); + DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPClient.DHCPOffer_Data.ServerIP); + + timer_reset(&DHCPTimer); + AppState->DHCPClient.CurrentState = DHCP_STATE_SendRequest; + } + + break; + case DHCP_STATE_SendRequest: + /* Fill out the DHCP response header */ + AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState); + + /* Add the DHCP REQUESTED IP ADDRESS option to the packet */ + AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t), + &AppState->DHCPClient.DHCPOffer_Data.AllocatedIP); + + /* Add the DHCP SERVER IP ADDRESS option to the packet */ + AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t), + &AppState->DHCPClient.DHCPOffer_Data.ServerIP); + + /* Send the DHCP REQUEST packet */ + uip_udp_send(AppDataSize); + + /* Reset the timeout timer, progress to next state */ + timer_reset(&DHCPTimer); + AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForACK; + + break; + case DHCP_STATE_WaitForACK: + if (!(uip_newdata())) + { + /* Check if the DHCP timeout period has expired while waiting for a response */ + if (timer_expired(&DHCPTimer)) + AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover; + + break; + } + + uint8_t RequestResponse_MessageType; + if ((AppData->TransactionID == DHCP_TRANSACTION_ID) && + DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) && + (RequestResponse_MessageType == DHCP_ACK)) + { + /* Set the new network parameters from the DHCP server */ + uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP); + uip_setnetmask((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.Netmask); + uip_setdraddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.GatewayIP); + + AppState->DHCPClient.CurrentState = DHCP_STATE_AddressLeased; + } + + 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 server. + * + * \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] AppState Application state of the current UDP connection + * + * \return Size in bytes of the created DHCP packet + */ +uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState) +{ + /* Erase existing packet data so that we start will all 0x00 DHCP header data */ + memset(DHCPHeader, 0, sizeof(DHCP_Header_t)); + + /* Fill out the DHCP packet header */ + DHCPHeader->Operation = DHCP_OP_BOOTREQUEST; + DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET; + DHCPHeader->HardwareAddressLength = sizeof(MACAddress); + DHCPHeader->Hops = 0; + DHCPHeader->TransactionID = DHCP_TRANSACTION_ID; + DHCPHeader->ElapsedSeconds = 0; + DHCPHeader->Flags = HTONS(BOOTP_BROADCAST); + memcpy(&DHCPHeader->ClientIP, &uip_hostaddr, sizeof(uip_ipaddr_t)); + memcpy(&DHCPHeader->YourIP, &AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t)); + memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPClient.DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t)); + memcpy(&DHCPHeader->ClientHardwareAddress, &MACAddress, sizeof(struct uip_eth_addr)); + DHCPHeader->Cookie = DHCP_MAGIC_COOKIE; + + /* Add a DHCP 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); +} + +/** Sets the given DHCP option in the DHCP packet's option list. This automatically moves the + * end of options terminator past the new option in the options list. + * + * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list + * \param[in] Option DHCP option to add to the list + * \param[in] DataLen Size in bytes of the option data to add + * \param[in] OptionData Buffer where the option's data is to be sourced from + * + * \return Number of bytes added to the DHCP packet + */ +uint8_t DHCPClientApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData) +{ + /* Skip through the DHCP options list until the terminator option is found */ + while (*DHCPOptionList != DHCP_OPTION_END) + DHCPOptionList += (DHCPOptionList[1] + 2); + + /* Overwrite the existing terminator with the new option, add a new terminator at the end of the list */ + DHCPOptionList[0] = Option; + DHCPOptionList[1] = DataLen; + memcpy(&DHCPOptionList[2], OptionData, DataLen); + DHCPOptionList[2 + DataLen] = DHCP_OPTION_END; + + /* Calculate the total number of bytes added to the outgoing packet */ + return (2 + DataLen); +} + +/** Retrieves the given option's data (if present) from the DHCP packet's options list. + * + * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list + * \param[in] Option DHCP option to retrieve to the list + * \param[out] Destination Buffer where the option's data is to be written to if found + * + * \return Boolean true if the option was found in the DHCP packet's options list, false otherwise + */ +bool DHCPClientApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination) +{ + /* Look through the incomming DHCP packet's options list for the requested option */ + while (*DHCPOptionList != DHCP_OPTION_END) + { + /* Check if the current DHCP option in the packet is the one requested */ + if (DHCPOptionList[0] == Option) + { + /* Copy request option's data to the destination buffer */ + memcpy(Destination, &DHCPOptionList[2], DHCPOptionList[1]); + + /* Indicate that the requested option data was sucessfully retrieved */ + return true; + } + + /* Skip to next DHCP option in the options list */ + DHCPOptionList += (DHCPOptionList[1] + 2); + } + + /* Requested option not found in the incomming packet's DHCP options list */ + return false; +} +#endif diff --git a/Projects/Webserver/Lib/DHCPClientApp.h b/Projects/Webserver/Lib/DHCPClientApp.h new file mode 100644 index 000000000..947151d0b --- /dev/null +++ b/Projects/Webserver/Lib/DHCPClientApp.h @@ -0,0 +1,166 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 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 disclaim 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 + * + * Header file for DHCPClientApp.c. + */ + +#ifndef _DHCPCLIENT_APP_H_ +#define _DHCPCLIENT_APP_H_ + + /* Includes: */ + #include + + #include + + #include "../Webserver.h" + + /* Macros: */ + /** UDP listen port for a BOOTP server */ + #define DHCPC_SERVER_PORT 67 + + /** UDP listen port for a BOOTP client */ + #define DHCPC_CLIENT_PORT 68 + + /** BOOTP message type for a BOOTP REQUEST message */ + #define DHCP_OP_BOOTREQUEST 0x01 + + /** BOOTP message type for a BOOTP REPLY message */ + #define DHCP_OP_BOOTREPLY 0x02 + + /** BOOTP flag for a BOOTP broadcast message */ + #define BOOTP_BROADCAST 0x8000 + + /** Magic DHCP cookie for a BOOTP message to identify it as a DHCP message */ + #define DHCP_MAGIC_COOKIE 0x63538263 + + /** Unique transaction ID used to identify DHCP responses to the client */ + #define DHCP_TRANSACTION_ID 0x13245466 + + /** DHCP message type for a DISCOVER message */ + #define DHCP_DISCOVER 1 + + /** DHCP message type for an OFFER message */ + #define DHCP_OFFER 2 + + /** DHCP message type for a REQUEST message */ + #define DHCP_REQUEST 3 + + /** DHCP message type for a DECLINE message */ + #define DHCP_DECLINE 4 + + /** DHCP message type for an ACK message */ + #define DHCP_ACK 5 + + /** DHCP message type for a NAK message */ + #define DHCP_NAK 6 + + /** DHCP message type for a RELEASE message */ + #define DHCP_RELEASE 7 + + /** DHCP medium type for standard Ethernet */ + #define DHCP_HTYPE_ETHERNET 1 + + /** DHCP message option for the network subnet mask */ + #define DHCP_OPTION_SUBNET_MASK 1 + + /** DHCP message option for the network gateway IP */ + #define DHCP_OPTION_ROUTER 3 + + /** DHCP message option for the network DNS server */ + #define DHCP_OPTION_DNS_SERVER 6 + + /** DHCP message option for the requested client IP address */ + #define DHCP_OPTION_REQ_IPADDR 50 + + /** DHCP message option for the IP address lease time */ + #define DHCP_OPTION_LEASE_TIME 51 + + /** DHCP message option for the DHCP message type */ + #define DHCP_OPTION_MSG_TYPE 53 + + /** DHCP message option for the DHCP server IP */ + #define DHCP_OPTION_SERVER_ID 54 + + /** DHCP message option for the list of required options from the server */ + #define DHCP_OPTION_REQ_LIST 55 + + /** DHCP message option for the options list terminator */ + #define DHCP_OPTION_END 255 + + /* Type Defines: */ + /** Type define for a DHCP packet inside an Ethernet frame. */ + typedef struct + { + uint8_t Operation; /**< DHCP operation, either DHCP_OP_BOOTREQUEST or DHCP_OP_BOOTREPLY */ + uint8_t HardwareType; /**< Hardware carrier type constant */ + uint8_t HardwareAddressLength; /**< Length in bytes of a hardware (MAC) address on the network */ + uint8_t Hops; /**< Number of hops required to reach the server, unused */ + + uint32_t TransactionID; /**< Unique ID of the DHCP packet, for positive matching between sent and received packets */ + + uint16_t ElapsedSeconds; /**< Elapsed seconds since the request was made */ + uint16_t Flags; /**< BOOTP packet flags */ + + uip_ipaddr_t ClientIP; /**< Client IP address, if already leased an IP */ + uip_ipaddr_t YourIP; /**< Client IP address */ + uip_ipaddr_t NextServerIP; /**< Legacy BOOTP protocol field, unused for DHCP */ + uip_ipaddr_t RelayAgentIP; /**< Legacy BOOTP protocol field, unused for DHCP */ + + uint8_t ClientHardwareAddress[16]; /**< Hardware (MAC) address of the client making a request to the DHCP server */ + uint8_t ServerHostnameString[64]; /**< Legacy BOOTP protocol field, unused for DHCP */ + uint8_t BootFileName[128]; /**< Legacy BOOTP protocol field, unused for DHCP */ + + uint32_t Cookie; /**< Magic BOOTP protocol cookie to indicate a valid packet */ + + uint8_t Options[]; /** DHCP message options */ + } DHCP_Header_t; + + /* Enums: */ + /** States for each DHCP connection to a DHCP client. */ + enum DHCP_States_t + { + DHCP_STATE_SendDiscover, /**< Send DISCOVER packet to retrieve DHCP lease offers */ + DHCP_STATE_WaitForOffer, /**< Waiting for OFFER packet giving available DHCP leases */ + DHCP_STATE_SendRequest, /**< Send REQUEST packet to request a DHCP lease */ + DHCP_STATE_WaitForACK, /**< Wait for ACK packet to complete the DHCP lease */ + DHCP_STATE_AddressLeased, /**< DHCP address has been leased from a DHCP server */ + }; + + /* Function Prototypes: */ + void DHCPClientApp_Init(void); + void DHCPClientApp_Callback(void); + + uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState); + uint8_t DHCPClientApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData); + bool DHCPClientApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination); + +#endif diff --git a/Projects/Webserver/Lib/HTTPServerApp.c b/Projects/Webserver/Lib/HTTPServerApp.c index 18366888d..9a70dade1 100644 --- a/Projects/Webserver/Lib/HTTPServerApp.c +++ b/Projects/Webserver/Lib/HTTPServerApp.c @@ -98,36 +98,36 @@ void HTTPServerApp_Callback(void) if (uip_aborted() || uip_timedout() || uip_closed()) { /* Connection is being terminated for some reason - close file handle */ - f_close(&AppState->FileHandle); - AppState->FileOpen = false; + f_close(&AppState->HTTPServer.FileHandle); + AppState->HTTPServer.FileOpen = false; /* Lock to the closed state so that no further processing will occur on the connection */ - AppState->CurrentState = WEBSERVER_STATE_Closed; - AppState->NextState = WEBSERVER_STATE_Closed; + AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closed; + AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed; } if (uip_connected()) { /* New connection - initialize connection state values */ - AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile; - AppState->NextState = WEBSERVER_STATE_OpenRequestedFile; - AppState->FileOpen = false; - AppState->ACKedFilePos = 0; - AppState->SentChunkSize = 0; + AppState->HTTPServer.CurrentState = WEBSERVER_STATE_OpenRequestedFile; + AppState->HTTPServer.NextState = WEBSERVER_STATE_OpenRequestedFile; + AppState->HTTPServer.FileOpen = false; + AppState->HTTPServer.ACKedFilePos = 0; + AppState->HTTPServer.SentChunkSize = 0; } if (uip_acked()) { /* Add the amount of ACKed file data to the total sent file bytes counter */ - AppState->ACKedFilePos += AppState->SentChunkSize; + AppState->HTTPServer.ACKedFilePos += AppState->HTTPServer.SentChunkSize; /* Progress to the next state once the current state's data has been ACKed */ - AppState->CurrentState = AppState->NextState; + AppState->HTTPServer.CurrentState = AppState->HTTPServer.NextState; } if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll()) { - switch (AppState->CurrentState) + switch (AppState->HTTPServer.CurrentState) { case WEBSERVER_STATE_OpenRequestedFile: HTTPServerApp_OpenRequestedFile(); @@ -144,7 +144,7 @@ void HTTPServerApp_Callback(void) case WEBSERVER_STATE_Closing: uip_close(); - AppState->NextState = WEBSERVER_STATE_Closed; + AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed; break; } } @@ -175,19 +175,19 @@ static void HTTPServerApp_OpenRequestedFile(void) /* If the requested filename has more that just the leading '/' path in it, copy it over */ if (strlen(RequestedFileName) > 1) - strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1)); + strncpy(AppState->HTTPServer.FileName, &RequestedFileName[1], (sizeof(AppState->HTTPServer.FileName) - 1)); else - strcpy(AppState->FileName, "index.htm"); + strcpy(AppState->HTTPServer.FileName, "index.htm"); /* Ensure filename is null-terminated */ - AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00; + AppState->HTTPServer.FileName[(sizeof(AppState->HTTPServer.FileName) - 1)] = 0x00; /* Try to open the file from the Dataflash disk */ - AppState->FileOpen = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK); + AppState->HTTPServer.FileOpen = (f_open(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK); /* Lock to the SendResponseHeader state until connection terminated */ - AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader; - AppState->NextState = WEBSERVER_STATE_SendResponseHeader; + AppState->HTTPServer.CurrentState = WEBSERVER_STATE_SendResponseHeader; + AppState->HTTPServer.NextState = WEBSERVER_STATE_SendResponseHeader; } /** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of @@ -202,15 +202,15 @@ static void HTTPServerApp_SendResponseHeader(void) uint16_t HeaderLength; /* Determine which HTTP header should be sent to the client */ - if (AppState->FileOpen) + if (AppState->HTTPServer.FileOpen) { HeaderToSend = HTTP200Header; - AppState->NextState = WEBSERVER_STATE_SendMIMETypeHeader; + AppState->HTTPServer.NextState = WEBSERVER_STATE_SendMIMETypeHeader; } else { HeaderToSend = HTTP404Header; - AppState->NextState = WEBSERVER_STATE_Closing; + AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing; } /* Copy over the HTTP response header and send it to the receiving client */ @@ -227,7 +227,7 @@ static void HTTPServerApp_SendMIMETypeHeader(void) uip_tcp_appstate_t* const AppState = &uip_conn->appstate; char* const AppData = (char*)uip_appdata; - char* Extension = strpbrk(AppState->FileName, "."); + char* Extension = strpbrk(AppState->HTTPServer.FileName, "."); uint16_t MIMEHeaderLength = 0; /* Check to see if a file extension was found for the requested filename */ @@ -261,7 +261,7 @@ static void HTTPServerApp_SendMIMETypeHeader(void) uip_send(AppData, MIMEHeaderLength); /* When the MIME header is ACKed, progress to the data send stage */ - AppState->NextState = WEBSERVER_STATE_SendData; + AppState->HTTPServer.NextState = WEBSERVER_STATE_SendData; } /** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks @@ -276,14 +276,14 @@ static void HTTPServerApp_SendData(void) uint16_t MaxSegmentSize = uip_mss(); /* Return file pointer to the last ACKed position */ - f_lseek(&AppState->FileHandle, AppState->ACKedFilePos); + f_lseek(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.ACKedFilePos); /* Read the next chunk of data from the open file */ - f_read(&AppState->FileHandle, AppData, MaxSegmentSize, &AppState->SentChunkSize); + f_read(&AppState->HTTPServer.FileHandle, AppData, MaxSegmentSize, &AppState->HTTPServer.SentChunkSize); /* Send the next file chunk to the receiving client */ - uip_send(AppData, AppState->SentChunkSize); + uip_send(AppData, AppState->HTTPServer.SentChunkSize); /* Check if we are at the last chunk of the file, if so next ACK should close the connection */ - AppState->NextState = (MaxSegmentSize != AppState->SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData; + AppState->HTTPServer.NextState = (MaxSegmentSize != AppState->HTTPServer.SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData; } diff --git a/Projects/Webserver/Lib/HTTPServerApp.h b/Projects/Webserver/Lib/HTTPServerApp.h index 43ad5b18c..13399b0f9 100644 --- a/Projects/Webserver/Lib/HTTPServerApp.h +++ b/Projects/Webserver/Lib/HTTPServerApp.h @@ -47,7 +47,7 @@ /** States for each HTTP connection to the webserver. */ enum Webserver_States_t { - WEBSERVER_STATE_OpenRequestedFile, /** Currently opening requested file */ + WEBSERVER_STATE_OpenRequestedFile, /**< Currently opening requested file */ WEBSERVER_STATE_SendResponseHeader, /**< Currently sending HTTP response headers to the client */ WEBSERVER_STATE_SendMIMETypeHeader, /**< Currently sending HTTP MIME type header to the client */ WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */ diff --git a/Projects/Webserver/Lib/TELNETServerApp.c b/Projects/Webserver/Lib/TELNETServerApp.c new file mode 100644 index 000000000..cabf52756 --- /dev/null +++ b/Projects/Webserver/Lib/TELNETServerApp.c @@ -0,0 +1,147 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 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 disclaim 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 + * + * TELNET Webserver Application. When connected to the uIP stack, + * this will serve out connection information to the client. + */ + +#define INCLUDE_FROM_TELNETSERVERAPP_C +#include "TELNETServerApp.h" + +/** Welcome message to send to a TELNET client when a connection is first made. */ +char PROGMEM WelcomeHeader[] = "********************************************\r\n" + "* LUFA uIP Webserver (TELNET) *\r\n" + "********************************************\r\n"; + +/** Main TELNET menu, giving the user the list of available commands they may issue */ +char PROGMEM TELNETMenu[] = "\r\n" + " Available Commands:\r\n" + " c) List Active TCP Connections\r\n" + "\r\nCommand>"; + +/** Initialization function for the simple HTTP webserver. */ +void TELNETServerApp_Init(void) +{ + /* Listen on port 23 for TELNET connections from hosts */ + uip_listen(HTONS(TELNET_SERVER_PORT)); +} + +/** uIP stack application callback for the TELNET server. This function must be called each time the + * TCP/IP stack needs a TCP packet to be processed. + */ +void TELNETServerApp_Callback(void) +{ + uip_tcp_appstate_t* const AppState = &uip_conn->appstate; + char* const AppData = (char*)uip_appdata; + + if (uip_connected()) + { + AppState->TELNETServer.CurrentState = TELNET_STATE_SendHeader; + } + + if (uip_acked()) + { + AppState->TELNETServer.CurrentState = AppState->TELNETServer.NextState; + } + + if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll()) + { + switch (AppState->TELNETServer.CurrentState) + { + case TELNET_STATE_SendHeader: + /* Copy over and send the TELNET welcome message upon first connection */ + strncpy_P(AppData, WelcomeHeader, strlen_P(WelcomeHeader)); + uip_send(AppData, strlen_P(WelcomeHeader)); + + AppState->TELNETServer.NextState = TELNET_STATE_SendMenu; + break; + case TELNET_STATE_SendMenu: + /* Copy over and send the TELNET menu to the client */ + strncpy_P(AppData, TELNETMenu, strlen_P(TELNETMenu)); + uip_send(AppData, strlen_P(TELNETMenu)); + + AppState->TELNETServer.NextState = TELNET_STATE_GetCommand; + break; + case TELNET_STATE_GetCommand: + if (!(uip_datalen())) + break; + + /* Save the issued command for later processing */ + AppState->TELNETServer.IssuedCommand = AppData[0]; + + AppState->TELNETServer.CurrentState = TELNET_STATE_SendResponse; + break; + case TELNET_STATE_SendResponse: + /* Determine which command was issued, perform command processing */ + switch (AppState->TELNETServer.IssuedCommand) + { + case 'c': + TELNETServerApp_DisplayTCPConnections(); + break; + } + + AppState->TELNETServer.NextState = TELNET_STATE_SendMenu; + break; + } + } +} + +/** Sends a list of active TCP connections to the TELNET client. */ +static void TELNETServerApp_DisplayTCPConnections(void) +{ + char* const AppData = (char*)uip_appdata; + + strcpy(AppData, "\r\n* Current TCP Connections: *\r\n"); + + uint16_t ResponseLen = strlen(AppData); + uint8_t ActiveConnCount = 0; + + /* Loop through the complete uIP TCP connections list, looking for active connections */ + for (uint8_t i = 0; i < UIP_CONNS; i++) + { + struct uip_conn* CurrConnection = &uip_conns[i]; + + /* If the connection is not closed, it is active and must be added to the out buffer */ + if (CurrConnection->tcpstateflags != UIP_CLOSED) + { + /* Add the current connection's details to the out buffer */ + ResponseLen += sprintf(&AppData[ResponseLen], "%u) %02d.%02d.%02d.%02d (Local %u, Remote %u)\r\n", + ++ActiveConnCount, CurrConnection->ripaddr.u8[0], + CurrConnection->ripaddr.u8[1], + CurrConnection->ripaddr.u8[2], + CurrConnection->ripaddr.u8[3], + HTONS(CurrConnection->lport), HTONS(CurrConnection->rport)); + } + } + + uip_send(AppData, ResponseLen); +} \ No newline at end of file diff --git a/Projects/Webserver/Lib/TELNETServerApp.h b/Projects/Webserver/Lib/TELNETServerApp.h new file mode 100644 index 000000000..7b1eb46ee --- /dev/null +++ b/Projects/Webserver/Lib/TELNETServerApp.h @@ -0,0 +1,68 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.fourwalledcubicle.com +*/ + +/* + Copyright 2010 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 disclaim 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 + * + * Header file for TELNETServerApp.c. + */ + +#ifndef _TELNETSERVER_APP_H_ +#define _TELNETSERVER_APP_H_ + + /* Includes: */ + #include + #include + #include + + #include + + /* Macros: */ + /** TCP listen port for incomming TELNET traffic */ + #define TELNET_SERVER_PORT 23 + + /* Enums: */ + /** States for each TELNET connection to the server. */ + enum TELNET_States_t + { + TELNET_STATE_SendHeader, /**< Currently sending welcome header to the client */ + TELNET_STATE_SendMenu, /**< Currently sending the command list menu to the client */ + TELNET_STATE_GetCommand, /**< Currently waiting for a command from the client */ + TELNET_STATE_SendResponse, /**< Processing the issued command and sending a response */ + }; + + /* Function Prototypes: */ + void TELNETServerApp_Init(void); + void TELNETServerApp_Callback(void); + + #if defined(INCLUDE_FROM_TELNETSERVERAPP_C) + static void TELNETServerApp_DisplayTCPConnections(void); + #endif + +#endif diff --git a/Projects/Webserver/Lib/uIPManagement.c b/Projects/Webserver/Lib/uIPManagement.c index e207d9ce1..a2cadd674 100644 --- a/Projects/Webserver/Lib/uIPManagement.c +++ b/Projects/Webserver/Lib/uIPManagement.c @@ -58,10 +58,11 @@ void uIPManagement_Init(void) /* uIP Stack Initialization */ uip_init(); uip_arp_init(); + uip_setethaddr(MACAddress); /* DHCP/Server IP Settings Initialization */ #if defined(ENABLE_DHCP) - DHCPApp_Init(); + DHCPClientApp_Init(); #else uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress; uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]); @@ -71,11 +72,12 @@ void uIPManagement_Init(void) uip_setnetmask(&Netmask); uip_setdraddr(&GatewayIPAddress); #endif - - uip_setethaddr(MACAddress); /* HTTP Webserver Initialization */ HTTPServerApp_Init(); + + /* TELNET Server Initialization */ + TELNETServerApp_Init(); } /** uIP Management function. This function manages the uIP stack when called while an RNDIS device has been @@ -90,6 +92,37 @@ void uIPManagement_ManageNetwork(void) } } +/** uIP TCP/IP network stack callback function for the processing of a given TCP connection. This routine dispatches + * to the appropriate TCP protocol application based on the connection's listen port number. + */ +void uIPManagement_TCPCallback(void) +{ + /* Call the correct TCP application based on the port number the connection is listening on */ + switch (uip_conn->lport) + { + case HTONS(HTTP_SERVER_PORT): + HTTPServerApp_Callback(); + break; + case HTONS(TELNET_SERVER_PORT): + TELNETServerApp_Callback(); + break; + } +} + +/** uIP TCP/IP network stack callback function for the processing of a given UDP connection. This routine dispatches + * to the appropriate UDP protocol application based on the connection's listen port number. + */ +void uIPManagement_UDPCallback(void) +{ + /* Call the correct UDP application based on the port number the connection is listening on */ + switch (uip_udp_conn->lport) + { + case HTONS(DHCPC_CLIENT_PORT): + DHCPClientApp_Callback(); + break; + } +} + /** Processes incomming packets to the server from the connected RNDIS device, creating responses as needed. */ static void uIPManagement_ProcessIncommingPacket(void) { diff --git a/Projects/Webserver/Lib/uIPManagement.h b/Projects/Webserver/Lib/uIPManagement.h index 57a1393fe..1e7ffd0be 100644 --- a/Projects/Webserver/Lib/uIPManagement.h +++ b/Projects/Webserver/Lib/uIPManagement.h @@ -43,8 +43,9 @@ #include #include - #include "Lib/DHCPApp.h" + #include "Lib/DHCPClientApp.h" #include "Lib/HTTPServerApp.h" + #include "Lib/TELNETServerApp.h" /* Macros: */ /** IP address that the webserver should use once connected to a RNDIS device (when DHCP is disabled). */ @@ -64,6 +65,8 @@ /* Function Prototypes: */ void uIPManagement_Init(void); void uIPManagement_ManageNetwork(void); + void uIPManagement_TCPCallback(void); + void uIPManagement_UDPCallback(void); #if defined(INCLUDE_FROM_UIPMANAGEMENT_C) static void uIPManagement_ProcessIncommingPacket(void); diff --git a/Projects/Webserver/Lib/uip/clock.c b/Projects/Webserver/Lib/uip/clock.c index e8a676b1a..299a747bc 100644 --- a/Projects/Webserver/Lib/uip/clock.c +++ b/Projects/Webserver/Lib/uip/clock.c @@ -29,9 +29,10 @@ clock_time_t clock_time() { clock_time_t time; - cli(); + ATOMIC_BLOCK(ATOMIC_FORCEON) + { time = clock_datetime; - sei(); + } return time; } diff --git a/Projects/Webserver/Lib/uip/clock.h b/Projects/Webserver/Lib/uip/clock.h index 0852cde15..3e42e4a59 100644 --- a/Projects/Webserver/Lib/uip/clock.h +++ b/Projects/Webserver/Lib/uip/clock.h @@ -2,6 +2,7 @@ #define __CLOCK_ARCH_H__ #include +#include typedef uint16_t clock_time_t; #define CLOCK_SECOND 100 diff --git a/Projects/Webserver/Lib/uip/uipopt.h b/Projects/Webserver/Lib/uip/uipopt.h index 23bce28a3..c8b3ad59e 100644 --- a/Projects/Webserver/Lib/uip/uipopt.h +++ b/Projects/Webserver/Lib/uip/uipopt.h @@ -346,14 +346,18 @@ * * \hideinitializer */ +#if !defined(UIP_URGDATA) #define UIP_URGDATA 0 +#endif /** * The initial retransmission timeout counted in timer pulses. * * This should not be changed. */ +#if !defined(UIP_RTO) #define UIP_RTO 3 +#endif /** * The maximum number of times a segment should be retransmitted @@ -361,7 +365,9 @@ * * This should not be changed. */ +#if !defined(UIP_MAXRTX) #define UIP_MAXRTX 8 +#endif /** * The maximum number of times a SYN segment should be retransmitted @@ -370,7 +376,9 @@ * * This should not need to be changed. */ +#if !defined(UIP_MAXSYNRTX) #define UIP_MAXSYNRTX 5 +#endif /** * The TCP maximum segment size. @@ -654,7 +662,7 @@ typedef uint32_t uip_stats_t; typedef struct httpd_state uip_tcp_appstate_t \endcode */ -#define UIP_UDP_APPCALL DHCPApp_Callback +#define UIP_UDP_APPCALL uIPManagement_UDPCallback void UIP_UDP_APPCALL(void); /** @@ -664,7 +672,7 @@ void UIP_UDP_APPCALL(void); * response to TCP/IP events. * */ -#define UIP_APPCALL HTTPServerApp_Callback +#define UIP_APPCALL uIPManagement_TCPCallback void UIP_APPCALL(void); /** @@ -674,16 +682,27 @@ void UIP_APPCALL(void); * uip_conn structure. This usually is typedef:ed to a struct holding * application state information. */ -typedef struct +typedef union { - uint8_t CurrentState; - uint8_t NextState; + struct + { + uint8_t CurrentState; + uint8_t NextState; + + char FileName[30]; + FIL FileHandle; + bool FileOpen; + uint32_t ACKedFilePos; + uint16_t SentChunkSize; + } HTTPServer; - char FileName[30]; - FIL FileHandle; - bool FileOpen; - uint32_t ACKedFilePos; - uint16_t SentChunkSize; + struct + { + uint8_t CurrentState; + uint8_t NextState; + + uint8_t IssuedCommand; + } TELNETServer; } uip_tcp_appstate_t; /** @@ -693,18 +712,21 @@ typedef struct * uip_conn structure. This usually is typedef:ed to a struct holding * application state information. */ -typedef struct +typedef union { - uint8_t CurrentState; - struct uip_udp_conn* Connection; - struct { - uint8_t AllocatedIP[4]; - uint8_t Netmask[4]; - uint8_t GatewayIP[4]; - uint8_t ServerIP[4]; - } DHCPOffer_Data; + uint8_t CurrentState; + struct uip_udp_conn* Connection; + + struct + { + uint8_t AllocatedIP[4]; + uint8_t Netmask[4]; + uint8_t GatewayIP[4]; + uint8_t ServerIP[4]; + } DHCPOffer_Data; + } DHCPClient; } uip_udp_appstate_t; /** @} */ diff --git a/Projects/Webserver/makefile b/Projects/Webserver/makefile index 37aecc76f..949283383 100644 --- a/Projects/Webserver/makefile +++ b/Projects/Webserver/makefile @@ -128,10 +128,11 @@ SRC = $(TARGET).c \ USBDeviceMode.c \ USBHostMode.c \ Lib/SCSI.c \ + Lib/DataflashManager.c \ Lib/uIPManagement.c \ - Lib/DHCPApp.c \ + Lib/DHCPClientApp.c \ Lib/HTTPServerApp.c \ - Lib/DataflashManager.c \ + Lib/TELNETServerApp.c \ Lib/uip/uip.c \ Lib/uip/uip_arp.c \ Lib/uip/timer.c \ @@ -200,10 +201,10 @@ CDEFS = -DF_CPU=$(F_CPU)UL -DF_CLOCK=$(F_CLOCK)UL -DBOARD=BOARD_$(BOARD) $(LUFA CDEFS += -DENABLE_DHCP=1 CDEFS += -DUIP_CONF_UDP_CONNS=1 -DUIP_CONF_TCP=1 -DUIP_CONF_MAX_CONNECTIONS=5 -CDEFS += -DUIP_CONF_MAX_LISTENPORTS=1 -DUIP_CONF_BUFFER_SIZE=1514 +CDEFS += -DUIP_CONF_MAX_LISTENPORTS=5 -DUIP_CONF_BUFFER_SIZE=1514 CDEFS += -DUIP_CONF_LL_802154=0 -DUIP_CONF_LL_80211=0 -DUIP_CONF_ROUTER=0 -DUIP_CONF_ICMP6=0 -DUIP_CONF_LL_802154=0 CDEFS += -DUIP_ARCH_ADD32=0 -DUIP_ARCH_CHKSUM=0 -DUIP_CONF_ICMP_DEST_UNREACH=1 -DUIP_NEIGHBOR_CONF_ADDRTYPE=0 -CDEFS += -DUIP_CONF_UDP=ENABLE_DHCP +CDEFS += -DUIP_URGDATA=0 -DUIP_CONF_UDP=ENABLE_DHCP # Place -D or -U options here for ASM sources -- cgit v1.2.3