Example #1
0
/** 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;
		}
	}
}
Example #2
0
/** 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 += DHCPCommon_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(&AppState->DHCPClient.Timeout);
			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(&AppState->DHCPClient.Timeout))
				  AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;

				break;
			}

			uint8_t OfferResponse_MessageType;
			if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
			    DHCPCommon_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));
				DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPClient.DHCPOffer_Data.Netmask);
				DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_ROUTER,      &AppState->DHCPClient.DHCPOffer_Data.GatewayIP);
				DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID,   &AppState->DHCPClient.DHCPOffer_Data.ServerIP);

				timer_reset(&AppState->DHCPClient.Timeout);
				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 += DHCPCommon_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 += DHCPCommon_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(&AppState->DHCPClient.Timeout);
			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(&AppState->DHCPClient.Timeout))
				  AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;

				break;
			}

			uint8_t RequestResponse_MessageType;
			if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
			    DHCPCommon_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;
	}
}