/** 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; } } }
/** 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; } }