/************************************************************************** * File Name : dhcp_server.c * Author : * Version : * Date : * Description : * * Copyright (c) 2014 Winner Microelectronics Co., Ltd. * All rights reserved. * ***************************************************************************/ #ifndef WM_W600 #include #else #ifndef assert #define assert(n) #endif #endif #include #include #include #include "tls_common.h" #include "wm_mem.h" #include "wm_debug.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/api.h" #include "lwip/tcpip.h" #include "lwip/dhcp.h" #include "lwip/prot/dhcp.h" #include "netif/ethernetif.h" #include "dhcp_server.h" #if TLS_CONFIG_AP #define ETHARP_FLAG_FIND_ONLY 2 #define ETHARP_FLAG_STATIC_ENTRY 4 extern u8 *wpa_supplicant_get_mac(void); /* 是否根据客户端dhcp报文中的broadcast标志来回应,不使用则统一使用广播回复 */ #define DHCPS_CHECK_BROADCAST_FLAG #ifdef DHCPS_CHECK_BROADCAST_FLAG #define IS_BROADCAST_SEND(x) (((x) >> 15) == 1 ? TRUE : FALSE) #endif static DHCP_SERVER DhcpServer; static DHCP_MSG DhcpMsg; #define DHCP_SET_OPTION_SUBNET_MASK(buffer, mask, len) \ { \ INT32U tmp; \ *buffer++ = DHCP_OPTION_ID_SUBNET_MASK; \ *buffer++ = 4; \ tmp = mask; \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ len += 6; \ } #define DHCP_SET_OPTION_GW(buffer, gw, len) \ { \ INT32U tmp; \ *buffer++ = DHCP_OPTION_ID_DEF_GW; \ *buffer++ = 4; \ tmp = gw; \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ len += 6; \ } #define DHCP_SET_OPTION_DNS(buffer, dns1, dns2, len) \ { \ INT32U tmp; \ *buffer++ = DHCP_OPTION_ID_DNS_SERVER; \ *buffer++ = 8; \ tmp = dns1; \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ tmp = dns2; \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ len += 10; \ } #define DHCP_SET_OPTION_SERVER_ID(buffer, ip, len) \ { \ INT32U tmp; \ *buffer++ = DHCP_OPTION_ID_SERVER_ID; \ *buffer++ = 4; \ tmp = ip; \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ len += 6; \ } #define DHCP_SET_OPTION_MSG_TYPE(buffer, type, len) \ { \ *buffer++ = DHCP_OPTION_ID_MSG_TYPE; \ *buffer++ = 1; \ *buffer++ = type; \ len += 3; \ } #define DHCP_SET_OPTION_LEASE_TIME(buffer, time, len) \ { \ INT32U tmp; \ *buffer++ = DHCP_OPTION_ID_LEASE_TIME; \ *buffer++ = 4; \ tmp = htonl(time); \ MEMCPY(buffer, &tmp, 4); \ buffer += 4; \ len += 6; \ } #define DHCP_SET_OPTION_END(buffer, len) \ { \ *buffer++ = DHCP_OPTION_ID_END; \ len ++; \ } #if 0 static void _PostMsgToSysQ(PDHCP_CLIENT pClient, INT16U nMsgId) { TSYSC_MSG * Msg; INT8U Err; INT8U Len; Len = 9; Msg = tls_mem_alloc(sizeof(TSYSC_MSG) + Len); if (Msg == NULL){return;} Msg->Id = nMsgId; Msg->Len = Len; Msg->Argc = 0; MEMCPY(&Msg->Argv[0], pClient->MacAddr, 6); MEMCPY(&Msg->Argv[0] + 6, (void *)&pClient->IpAddr, 4); Err = OSQPost(Que_Sys, (void *)Msg); assert(Err == OS_NO_ERR); UNUSED_ARG(Err); } #endif static bool _CheckMacIsValid(u8 *mac) { #define STA_MAC_BUF_LEN 64 u32 cnt; u32 sta_num = 0; u8 *sta_buf; bool ret = FALSE; struct tls_sta_info_t *sta; sta_buf = tls_mem_alloc(STA_MAC_BUF_LEN); if (!sta_buf) return FALSE;/* 系统资源不足,无需再让client接入 */ memset(sta_buf, 0, STA_MAC_BUF_LEN); tls_wifi_get_authed_sta_info(&sta_num, sta_buf, STA_MAC_BUF_LEN); sta = (struct tls_sta_info_t *)sta_buf; for (cnt = 0; cnt < sta_num; cnt++) { if (!compare_ether_addr(mac, sta->mac_addr)) { ret = TRUE;/* 本SOFTAP下的client才予以分配IP */ break; } sta++; } tls_mem_free(sta_buf); return ret; } static void _DhcpTickHandle(void * Arg) { INT8U i; PDHCP_CLIENT pClient; if(DhcpServer.Enable == 0) { return; } for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if(pClient->State == DHCP_CLIENT_STATE_REQUEST) { if(pClient->Timeout && (--pClient->Timeout == 0)) { /* Timeout for the client's request frame. */ memset(pClient->MacAddr, 0, 6); pClient->State = DHCP_CLIENT_STATE_IDLE; } } else if(pClient->State == DHCP_CLIENT_STATE_BIND) { #if 1 if(pClient->Lease && (--pClient->Lease == 0)) { /* The lease time over. */ pClient->State = DHCP_CLIENT_STATE_IDLE; // _PostMsgToSysQ(pClient, SYSC_MSG_IP_RELEASE); } else if(_CheckMacIsValid(pClient->MacAddr) == 0) { /* The client leave the wireless network. */ pClient->State = DHCP_CLIENT_STATE_IDLE; // _PostMsgToSysQ(pClient, SYSC_MSG_IP_RELEASE); } #endif } } if(DhcpServer.Enable) sys_timeout(DHCP_TICK_TIME, _DhcpTickHandle, NULL); } static INT8U _ParseDhcpOptions(PDHCP_MSG pMsg, INT8U * pMsgType, INT32U * pReqIpAddr, INT32U * pServerId) { INT8U * pDhcpOptions, * pEnd; INT32U Len; INT8U Ret; pDhcpOptions = pMsg->Options; pEnd = (INT8U *)(pMsg) + sizeof(DHCP_MSG); Len = 0; Ret = 0; while((*pDhcpOptions != DHCP_OPTION_ID_END) && (pDhcpOptions < pEnd)) { if (*pDhcpOptions == DHCP_OPTION_ID_PAD) { /* Skip the pad. */ pDhcpOptions += 1; } else { Len = (*(pDhcpOptions + 1)); if(*pDhcpOptions == DHCP_OPTION_ID_MSG_TYPE) { /* Get the message type. */ pDhcpOptions += 2; *pMsgType = *pDhcpOptions; Ret |= 0x01; } else if(*pDhcpOptions == DHCP_OPTION_ID_REQ_IP_ADDR) { /* Get the client's requested ip address. */ pDhcpOptions += 2; MEMCPY((INT8U*)pReqIpAddr, pDhcpOptions,4 ); Ret |= 0x02; } else if(*pDhcpOptions == DHCP_OPTION_ID_SERVER_ID) { /* Get the server's ip address. */ pDhcpOptions += 2; MEMCPY((INT8U*)pServerId, pDhcpOptions,4 ); Ret |= 0x04; } else { /* Dropped the other options. */ pDhcpOptions += 2; } pDhcpOptions += Len; } } return Ret; } static PDHCP_CLIENT _ClientTableLookup(INT8U * MacAddr, INT8U MsgType, INT32U ReqIpAddr, INT32U ServerId) { INT8U i; INT8U IpUnavailable; PDHCP_CLIENT pClient; PDHCP_CLIENT pFreeClient; PDHCP_CLIENT pReqClient; PDHCP_CLIENT pMyHistoryClient; PDHCP_CLIENT pHistoryClient; PDHCP_CLIENT pMyClient; PDHCP_CLIENT pReturnClient; pFreeClient = NULL; pReqClient = NULL; pHistoryClient= NULL; pMyHistoryClient = NULL; pMyClient = NULL; pReturnClient = NULL; IpUnavailable = 0; for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if(pClient->State == DHCP_CLIENT_STATE_IDLE) { if((pMyHistoryClient == NULL) && (memcmp(pClient->MacAddr, MacAddr, 6) == 0)) { /* Get my history entry. */ pMyHistoryClient = pClient; } if((pReqClient == NULL) && ip_addr_cmp(&pClient->IpAddr, (ip_addr_t *)&ReqIpAddr) ) { /* Get the idle entry that hold my requested ip address. */ pReqClient = pClient; } if((pFreeClient == NULL) && (memcmp(pClient->MacAddr, "\x00\x00\x00\x00\x00\x00", 6) == 0) ) { /* Get the first free entry. */ pFreeClient = pClient; } if((pHistoryClient == NULL) && (memcmp(pClient->MacAddr, "\x00\x00\x00\x00\x00\x00", 6) != 0)) { /* Get the first histoy entry that not belong to me. */ pHistoryClient = pClient; } } else { if(memcmp(pClient->MacAddr, MacAddr, 6) == 0) { /* Is negotiating ip address or has negotiated now. */ pMyClient = pClient; } else if(ip_addr_cmp(&pClient->IpAddr, (ip_addr_t *)&ReqIpAddr)) { /* The requested ip address is allocated. */ IpUnavailable = 1; } } } switch(MsgType) { case DHCP_MSG_DISCOVER: if(pMyClient) { /* Amazing!!The client restart the negotiation. */ pMyClient->State = DHCP_CLIENT_STATE_IDLE; if(pReqClient) { /* The client request another ip address and that address is not allocated now. */ if(pMyClient->State != DHCP_CLIENT_STATE_BIND) { memset(pMyClient->MacAddr, 0, 6); } else { // _PostMsgToSysQ(pMyClient, SYSC_MSG_IP_RELEASE); } pReturnClient = pReqClient; } else { /* The client request the same ip address. */ pReturnClient = pMyClient; } } else { /* A new negotiation! */ /* The IP address allocation priority(high to low): 1. the client's request ip address. 2. the client's history ip address. 3. a totally free ip address. 4. the other client's history ip address. */ if(pReqClient) { /* The client's request ip address. */ pReturnClient = pReqClient; } else if(pMyHistoryClient) { /* The client's history ip address. */ pReturnClient = pMyHistoryClient; } else if(pFreeClient) { /* A totally free ip address. */ pReturnClient = pFreeClient; } else if(pHistoryClient) { /* The other client's history ip address. */ pReturnClient = pHistoryClient; } else { /* The IP pool is full, so return null. */ pReturnClient = NULL; } } break; case DHCP_MSG_REQUEST: if(pMyClient) { if(IpUnavailable == 1) { /* The client request a new address that was allocated, so return null. */ pReturnClient = NULL; if(pMyClient->State != DHCP_CLIENT_STATE_BIND) { memset(pMyClient->MacAddr, 0, 6); } pMyClient->State = DHCP_CLIENT_STATE_IDLE; } else { if(pReqClient) { /* The client request a new address that is not allocated. */ if(pMyClient->State != DHCP_CLIENT_STATE_BIND) { memset(pMyClient->MacAddr, 0, 6); } else { // _PostMsgToSysQ(pMyClient, SYSC_MSG_IP_RELEASE); } pMyClient->State = DHCP_CLIENT_STATE_IDLE; if((ServerId == 0) || (ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr) == ServerId)) { /* The client request the new address and that is free, allocate it. */ pReturnClient = pReqClient; } else { /* The client refuses my offer and request another ip address. */ pReturnClient = NULL; } } else if((ServerId == 0) || (ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr) == ServerId)) { /* The client request this address that has been allocated to it(a little abnorm) or the client renew the lease time. */ pReturnClient = pMyClient; } else { /* The client refuses my offer. */ pReturnClient = NULL; } } } else { if(IpUnavailable == 1) { /* The requested ip address was allocated, so return null. */ pReturnClient = NULL; } else if((ServerId == 0) || (ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr) == ServerId)) { /* The client request my free address, so allocate it. */ pReturnClient = pReqClient; } else { /* The client request the address from another server, but send it to me, so return null. */ pReturnClient = NULL; } } break; case DHCP_MSG_RELEASE: /* The client release the ip address. */ if(pMyClient) { if(pMyClient->State != DHCP_CLIENT_STATE_BIND) { memset(pMyClient->MacAddr, 0, 6); } else { // _PostMsgToSysQ(pClient, SYSC_MSG_IP_RELEASE); } pMyClient->State = DHCP_CLIENT_STATE_IDLE; } pReturnClient = NULL; break; case DHCP_MSG_DECLINE: /* The client refuses my offer directly. */ if(pMyClient) { if(pMyClient->State != DHCP_CLIENT_STATE_BIND) { memset(pMyClient->MacAddr, 0, 6); } else { // _PostMsgToSysQ(pClient, SYSC_MSG_IP_RELEASE); } pMyClient->State = DHCP_CLIENT_STATE_IDLE; } pReturnClient = NULL; break; default: /* Dropped the other frames. */ pReturnClient = NULL; break; } if(pReturnClient) { /* Updata the client's MAC address. */ MEMCPY(pReturnClient->MacAddr, MacAddr, 6); } return pReturnClient; } static void _DHCPNakGenAndSend(INT8U * pClientMacAddr, INT32U Xid) { INT32U Len; INT8U * Body; PDHCP_MSG pDhcpMsg; struct pbuf * pDhcpBuf; pDhcpBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(DHCP_MSG), PBUF_RAM); if(pDhcpBuf == NULL) { return; } pDhcpMsg = &DhcpMsg; memset(pDhcpMsg, 0, sizeof(*pDhcpMsg)); /* Initialize the DHCP message header. */ pDhcpMsg->Op = DHCP_OP_REPLY; pDhcpMsg->HType = DHCP_HWTYPE_ETHERNET; pDhcpMsg->HLen = 6; pDhcpMsg->Xid = htonl(Xid); pDhcpMsg->Siaddr = ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr); MEMCPY(pDhcpMsg->Chaddr, pClientMacAddr, 6); pDhcpMsg->Magic = htonl(DHCP_MAGIC); Len = 240; Body = &pDhcpMsg->Options[0]; /* Set the message type. */ DHCP_SET_OPTION_MSG_TYPE(Body, DHCP_MSG_NAK, Len); DHCP_SET_OPTION_END(Body, Len); pbuf_take(pDhcpBuf, (const void *)pDhcpMsg, Len); pbuf_realloc(pDhcpBuf, Len); /* Send broadcast to the DHCP client. */ udp_sendto(DhcpServer.Socket, pDhcpBuf, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT); TLS_DBGPRT_INFO("sent dhcp nak, ClientMacAddr="MACSTR", ServerIp=%d.%d.%d.%d\n", MAC2STR(pClientMacAddr), ip4_addr1(&DhcpServer.ServerIpAddr), ip4_addr2(&DhcpServer.ServerIpAddr), ip4_addr3(&DhcpServer.ServerIpAddr), ip4_addr4(&DhcpServer.ServerIpAddr)); pbuf_free(pDhcpBuf); } static void _DHCPAckGenAndSend(PDHCP_CLIENT pClient, INT8U * pClientMacAddr, INT32U Xid, INT16U Flags) { INT32U Len; INT8U * Body; PDHCP_MSG pDhcpMsg; struct pbuf * pDhcpBuf; pDhcpBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(DHCP_MSG), PBUF_RAM); if(pDhcpBuf == NULL) { return; } pDhcpMsg = &DhcpMsg; memset(pDhcpMsg, 0, sizeof(*pDhcpMsg)); /* Initialize the DHCP message header. */ pDhcpMsg->Op = DHCP_OP_REPLY; pDhcpMsg->HType = DHCP_HWTYPE_ETHERNET; pDhcpMsg->HLen = 6; pDhcpMsg->Xid = htonl(Xid); pDhcpMsg->Yiaddr = ip_addr_get_ip4_u32(&pClient->IpAddr); pDhcpMsg->Siaddr = 0; MEMCPY(pDhcpMsg->Chaddr, pClientMacAddr, 6); pDhcpMsg->Magic = htonl(DHCP_MAGIC); Len = 240; Body = &pDhcpMsg->Options[0]; /* Set the message type. */ DHCP_SET_OPTION_MSG_TYPE(Body, DHCP_MSG_ACK, Len); /* Set the lease time. */ DHCP_SET_OPTION_LEASE_TIME(Body, DHCP_DEFAULT_LEASE_TIME, Len); /* Set the server's ip address */ DHCP_SET_OPTION_SERVER_ID(Body, ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr), Len); /* Set the subnet mask. */ DHCP_SET_OPTION_SUBNET_MASK(Body, ip_addr_get_ip4_u32(&DhcpServer.SubnetMask), Len); /* Set the default gatway's ip address. */ DHCP_SET_OPTION_GW(Body, ip_addr_get_ip4_u32(&DhcpServer.GateWay), Len); /* Set the dns server's ip address. */ DHCP_SET_OPTION_DNS(Body, ip_addr_get_ip4_u32(&DhcpServer.Dns1), ip_addr_get_ip4_u32(&DhcpServer.Dns2), Len); DHCP_SET_OPTION_END(Body, Len); pbuf_take(pDhcpBuf, (const void *)pDhcpMsg, Len); pbuf_realloc(pDhcpBuf, Len); #ifdef DHCPS_CHECK_BROADCAST_FLAG if (IS_BROADCAST_SEND(Flags)) { #endif /* Send broadcast to the DHCP client. */ udp_sendto(DhcpServer.Socket, pDhcpBuf, IP_ADDR_BROADCAST, DHCP_CLIENT_UDP_PORT); #ifdef DHCPS_CHECK_BROADCAST_FLAG } else { // etharp_update_arp_entry(tls_get_netif(), (ip_addr_t *)(&pClient->IpAddr), (struct eth_addr *)pClientMacAddr, ETHARP_FLAG_FIND_ONLY); etharp_update_arp_entry(tls_get_netif(), (ip_addr_t *)(&pClient->IpAddr), (struct eth_addr *)pClientMacAddr, ETHARP_FLAG_STATIC_ENTRY); udp_sendto(DhcpServer.Socket, pDhcpBuf, (ip_addr_t *)(&pClient->IpAddr), DHCP_CLIENT_UDP_PORT); } #endif TLS_DBGPRT_INFO("sent dhcp ack, ClientMacAddr="MACSTR", GivenIpAddr=%d.%d.%d.%d, ServerIp=%d.%d.%d.%d\n", MAC2STR(pClientMacAddr), ip4_addr1(&pClient->IpAddr), ip4_addr2( &pClient->IpAddr), ip4_addr3(&pClient->IpAddr), ip4_addr4( &pClient->IpAddr), ip4_addr1(&DhcpServer.ServerIpAddr), ip4_addr2(&DhcpServer.ServerIpAddr), ip4_addr3(&DhcpServer.ServerIpAddr), ip4_addr4(&DhcpServer.ServerIpAddr) ); pbuf_free(pDhcpBuf); } static void _DHCPOfferGenAndSend(PDHCP_CLIENT pClient, INT8U * pClientMacAddr, INT32U Xid, INT16U Flags) { INT32U Len; INT8U * Body; PDHCP_MSG pDhcpMsg; struct pbuf * pDhcpBuf; pDhcpBuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(DHCP_MSG), PBUF_RAM); if(pDhcpBuf == NULL) { return; } pDhcpMsg = &DhcpMsg; memset(pDhcpMsg, 0, sizeof(*pDhcpMsg)); /* Initialize the DHCP message header. */ pDhcpMsg->Op = DHCP_OP_REPLY; pDhcpMsg->HType = DHCP_HWTYPE_ETHERNET; pDhcpMsg->HLen = 6; pDhcpMsg->Xid = htonl(Xid); pDhcpMsg->Yiaddr = ip_addr_get_ip4_u32(&pClient->IpAddr); pDhcpMsg->Siaddr = 0; MEMCPY(pDhcpMsg->Chaddr, pClientMacAddr, 6); pDhcpMsg->Magic = htonl(DHCP_MAGIC); Len = 240; Body = &pDhcpMsg->Options[0]; /* Set the message type. */ DHCP_SET_OPTION_MSG_TYPE(Body, DHCP_MSG_OFFER, Len); /* Set the lease time. */ DHCP_SET_OPTION_LEASE_TIME(Body, DHCP_DEFAULT_LEASE_TIME, Len); /* Set the server's ip address */ DHCP_SET_OPTION_SERVER_ID(Body, ip_addr_get_ip4_u32(&DhcpServer.ServerIpAddr), Len); /* Set the subnet mask. */ DHCP_SET_OPTION_SUBNET_MASK(Body, ip_addr_get_ip4_u32(&DhcpServer.SubnetMask), Len); /* Set the default gatway's ip address. */ DHCP_SET_OPTION_GW(Body, ip_addr_get_ip4_u32(&DhcpServer.GateWay), Len); /* Set the dns server's ip address. */ DHCP_SET_OPTION_DNS(Body, ip_addr_get_ip4_u32(&DhcpServer.Dns1), ip_addr_get_ip4_u32(&DhcpServer.Dns2), Len); DHCP_SET_OPTION_END(Body, Len); pbuf_take(pDhcpBuf, (const void *)pDhcpMsg, Len); pbuf_realloc(pDhcpBuf, Len); #ifdef DHCPS_CHECK_BROADCAST_FLAG if (IS_BROADCAST_SEND(Flags)) { #endif /* Send broadcast to the DHCP client. */ udp_sendto(DhcpServer.Socket, pDhcpBuf, IP_ADDR_BROADCAST, DHCP_CLIENT_UDP_PORT); #ifdef DHCPS_CHECK_BROADCAST_FLAG } else { // etharp_update_arp_entry(tls_get_netif(), (ip_addr_t *)(&pClient->IpAddr), (struct eth_addr *)pClientMacAddr, ETHARP_FLAG_FIND_ONLY); etharp_update_arp_entry(tls_get_netif(), (ip_addr_t *)(&pClient->IpAddr), (struct eth_addr *)pClientMacAddr, ETHARP_FLAG_STATIC_ENTRY); udp_sendto(DhcpServer.Socket, pDhcpBuf, (ip_addr_t *)(&pClient->IpAddr), DHCP_CLIENT_UDP_PORT); } #endif TLS_DBGPRT_INFO("sent dhcp offer, ClientMacAddr="MACSTR", GivenIpAddr=%d.%d.%d.%d, ServerIp=%d.%d.%d.%d\n", MAC2STR(pClientMacAddr), ip4_addr1(&pClient->IpAddr), ip4_addr2(&pClient->IpAddr), ip4_addr3(&pClient->IpAddr), ip4_addr4(&pClient->IpAddr), ip4_addr1( &DhcpServer.ServerIpAddr), ip4_addr2( &DhcpServer.ServerIpAddr), ip4_addr3( &DhcpServer.ServerIpAddr), ip4_addr4( &DhcpServer.ServerIpAddr) ); pbuf_free(pDhcpBuf); } static void _CleanClientHistory(INT8U * pClientMacAddr) { INT8U i; PDHCP_CLIENT pClient; for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if((pClient->State == DHCP_CLIENT_STATE_IDLE) && (memcmp(pClient->MacAddr, pClientMacAddr, 6) == 0)) { /* Clean the history client's Mac address. */ memset(pClient->MacAddr, 0, 6); } } } static void _DhcpClientSMEHandle(PDHCP_CLIENT pClient, INT8U MsgType, INT32U Xid, INT8U * MacAddr, INT16U Flags) { switch(pClient->State) { case DHCP_CLIENT_STATE_IDLE: if(MsgType == DHCP_MSG_DISCOVER) { /* Receive the "DISCOVER" frame, switch the state to "SELECT". */ pClient->State = DHCP_CLIENT_STATE_SELECT; } else if(MsgType == DHCP_MSG_REQUEST) { /* If the requested ip is not allocated, allocate it. */ _DHCPAckGenAndSend(pClient, pClient->MacAddr, Xid, Flags); pClient->Lease = DHCP_DEFAULT_LEASE_TIME; pClient->State = DHCP_CLIENT_STATE_BIND; _CleanClientHistory(pClient->MacAddr); // _PostMsgToSysQ(pClient, SYSC_MSG_IP_ALLOCATED); break; } case DHCP_CLIENT_STATE_SELECT: /* Receive the "DISCOVER" frame, send "OFFER" to the client. */ _DHCPOfferGenAndSend(pClient, pClient->MacAddr, Xid, Flags); pClient->Timeout = DHCP_DEFFAULT_TIMEOUT; pClient->State = DHCP_CLIENT_STATE_REQUEST; break; case DHCP_CLIENT_STATE_REQUEST: // _PostMsgToSysQ(pClient, SYSC_MSG_IP_ALLOCATED); case DHCP_CLIENT_STATE_BIND: /* Send ACK to the client, if receive the "REQUEST" frame to select the offer or renew the DHCP lease. */ _DHCPAckGenAndSend(pClient, pClient->MacAddr, Xid, Flags); pClient->Lease = DHCP_DEFAULT_LEASE_TIME; pClient->State = DHCP_CLIENT_STATE_BIND; _CleanClientHistory(pClient->MacAddr); break; default: break; } } ip_addr_t *DHCPS_GetIpByMac(const INT8U *MacAddr) { INT8U i; PDHCP_CLIENT pClient; ip_addr_t *IpAddr = NULL; for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if (0 == compare_ether_addr(MacAddr, pClient->MacAddr)) { IpAddr = &pClient->IpAddr; break; } } return IpAddr; } INT8U *DHCPS_GetMacByIp(const ip_addr_t *ipaddr) { INT8U i; PDHCP_CLIENT pClient; INT8U *macaddr = NULL; for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if (pClient->IpAddr.addr == ipaddr->addr) { macaddr = pClient->MacAddr; break; } } return macaddr; } /* numdns 0/1 --> dns 1/2 */ void DHCPS_SetDns(INT8U numdns, INT32U dns) { if (0 == numdns) ip_addr_set_ip4_u32(&DhcpServer.Dns1, dns); if (1 == numdns) ip_addr_set_ip4_u32(&DhcpServer.Dns2, dns); return; } /*------------------------------------------------------------------------- Description: When an incoming DHCP message is to me, this function process it and trigger the state machine. Arguments: Arg: Pointer to the user supplied argument. Pcb: Pointer to the udp_pcb which received data. P: Pointer to the packet buffer that was received. Addr: The remote IP address from which the packet was received. Port: The remote port from which the packet was received . Return Value: None. Note: -------------------------------------------------------------------------*/ void DHCPS_RecvCb(void *Arg, struct udp_pcb *Pcb, struct pbuf *P, ip_addr_t *Addr, INT16U Port) { #if 1 INT16U Flags; INT32U Xid; INT8U MsgType; PDHCP_MSG pDhcpMsg; INT32U MsgLen; ip_addr_t ReqIpAddr; ip_addr_t ServerId; INT8U ClientMacAddr[6]; PDHCP_CLIENT pClient; INT8U* MacAddr; do { pDhcpMsg = &DhcpMsg; memset(pDhcpMsg, 0, sizeof(DHCP_MSG)); /* Copy the DHCP message. */ MsgLen = pbuf_copy_partial(P, (void *)pDhcpMsg, sizeof(DHCP_MSG), 0); /* Filter out the frame that is not request frame or has wrong magic number or has wrong hardware address type. */ if((MsgLen == 0) || (pDhcpMsg->Op != DHCP_OP_REQUEST) || (ntohl(pDhcpMsg->Magic) != DHCP_MAGIC) || (pDhcpMsg->HType != DHCP_HWTYPE_ETHERNET)) { break; } MacAddr = wpa_supplicant_get_mac(); if (0 == memcmp(MacAddr, pDhcpMsg->Chaddr, 6)) { TLS_DBGPRT_INFO("drop form ours dhcp packet\n"); break; } if (!_CheckMacIsValid(pDhcpMsg->Chaddr)) { TLS_DBGPRT_INFO("drop form router's dhcp packet\n"); break; } /* Parse the packet to get message type, ip address requested by client and server ID. */ MsgType = 0xff; memset(&ReqIpAddr, 0, sizeof(ip_addr_t)); memset(&ServerId, 0, sizeof(ip_addr_t)); if((_ParseDhcpOptions(pDhcpMsg, &MsgType, &ip4_addr_get_u32(&ReqIpAddr), &ip4_addr_get_u32(&ServerId)) & 0x01) == 0) { break; } if (DHCP_MSG_INFORM == MsgType) { TLS_DBGPRT_INFO("drop dhcp inform packet\n"); break; } /* Get the Xid and client's MAC address. */ Xid = ntohl(pDhcpMsg->Xid); Flags = ntohs(pDhcpMsg->Flags); MEMCPY(ClientMacAddr, pDhcpMsg->Chaddr, 6); TLS_DBGPRT_INFO("ClientMacAddr=%x, MsgType=%x, ReqIpAddr=%x, ServerId=%x\n", ClientMacAddr, MsgType, ReqIpAddr, ServerId); TLS_DBGPRT_INFO("ClientMacAddr="MACSTR", MsgType=%x, ReqIpAddr=%d.%d.%d.%d, ServerIp=%d.%d.%d.%d\n", MAC2STR(ClientMacAddr), MsgType, ip4_addr1(&ReqIpAddr), ip4_addr2(&ReqIpAddr), ip4_addr3(&ReqIpAddr), ip4_addr4(&ReqIpAddr), ip4_addr1(&ServerId), ip4_addr2(&ServerId), ip4_addr3(&ServerId), ip4_addr4(&ServerId)); /* Get the client entry that is free or negotiating. */ pClient = _ClientTableLookup(ClientMacAddr, MsgType, ip4_addr_get_u32(&ReqIpAddr), ip4_addr_get_u32(&ServerId)); if(pClient == NULL) { if((MsgType != DHCP_MSG_RELEASE) && (MsgType != DHCP_MSG_DECLINE)) { /* Ip is already allocated, so send nack. */ _DHCPNakGenAndSend(ClientMacAddr, Xid); } break; } /* Push to client state machine. */ _DhcpClientSMEHandle(pClient, MsgType, Xid, ClientMacAddr, Flags); }while(0); pbuf_free(P); #endif } /*------------------------------------------------------------------------- Description: This function is used to delete the dhcp client entry on the server. Arguments: MacAddr: Specify the MAC Address of the dhcp client entry to be delete. Return Value: The DHCP Server error code: DHCPS_ERR_SUCCESS - No error DHCPS_ERR_INACTIVE - The Server is inactive DHCPS_ERR_PARAM - The input parameter error DHCPS_ERR_NOT_FOUND - Not fount this client Note: -------------------------------------------------------------------------*/ INT8S DHCPS_ClientDelete(INT8U * MacAddr) { INT8U i; PDHCP_CLIENT pClient; /* Check the server is active now. */ if(DhcpServer.Enable == 0) { return DHCPS_ERR_INACTIVE; } if(MacAddr == NULL) { return DHCPS_ERR_PARAM; } for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; if((pClient->State != DHCP_CLIENT_STATE_IDLE) && (memcmp(pClient->MacAddr, MacAddr, 6) == 0)) { if(pClient->State != DHCP_CLIENT_STATE_BIND) { /* For negotiating client, return. */ return DHCPS_ERR_NOT_BIND; } else { /* For bind client, delete it directly. */ pClient->State = DHCP_CLIENT_STATE_IDLE; return DHCPS_ERR_SUCCESS; } } } return DHCPS_ERR_NOT_FOUND; } /*------------------------------------------------------------------------- Description: This function is used to start DHCP Server for a network interface. Arguments: Netif: Pointer to the Lwip network interface. Return Value: The DHCP Server error code: DHCPS_ERR_SUCCESS - No error DHCPS_ERR_MEM - Out of memory DHCPS_ERR_LINKDOWN - The NI is inactive Note: The dhcp server must be started after the network interface was actived. -------------------------------------------------------------------------*/ INT8S DHCPS_Start(struct netif *Netif) { INT32U Val, Mask, tmp, i; PDHCP_CLIENT pClient; /* Check the network interface is active now. */ if(netif_is_up(Netif) == 0) { return DHCPS_ERR_LINKDOWN; } memset(&DhcpServer, 0, sizeof(DhcpServer)); /* Calculate the start ip address of the server's ip pool. */ Val = ntohl(ip_addr_get_ip4_u32(&Netif->ip_addr)); Mask = ntohl(ip_addr_get_ip4_u32(&Netif->netmask)); tmp = (Val & (~Mask)); tmp = ((tmp + 1) % (~Mask)) ? ((tmp + 1) % (~Mask)) : 1; Val = htonl((Val & Mask) | tmp); /* Configure the DHCP Server. */ ip_addr_set(&DhcpServer.ServerIpAddr, &Netif->ip_addr); ip_addr_set(&DhcpServer.StartIpAddr, (ip_addr_t *)&Val); ip_addr_set(&DhcpServer.SubnetMask, &Netif->netmask); ip_addr_set(&DhcpServer.GateWay, &Netif->ip_addr); ip_addr_set(&DhcpServer.Dns1, &Netif->ip_addr); /* Set the default lease time - 2 hours. */ DhcpServer.LeaseTime = DHCP_DEFAULT_LEASE_TIME; /* Initialize the free DHCP clients. */ for(i = 0; i < DHCPS_HISTORY_CLIENT_NUM; i++) { pClient = &DhcpServer.Clients[i]; /* Set the initial client state is "IDLE". */ pClient->State = DHCP_CLIENT_STATE_IDLE; /* Set the ip address to the client. */ Val = ntohl(ip_addr_get_ip4_u32(&DhcpServer.StartIpAddr)); tmp = (Val & (~Mask)); tmp = ((tmp + i) % (~Mask)) ? ((tmp + i) % (~Mask)) : 1; Val = htonl((Val & Mask) | tmp); ip_addr_set(&pClient->IpAddr, (ip_addr_t *)&Val); /* Set the default lease time. */ pClient->Lease = DHCP_DEFAULT_LEASE_TIME; } /* Allocate a UDP PCB. */ DhcpServer.Socket = udp_new(); if(DhcpServer.Socket == NULL) { return DHCPS_ERR_MEM; } /* Set up local and remote port for the pcb. */ udp_bind(DhcpServer.Socket, IP_ADDR_ANY, DHCP_SERVER_UDP_PORT); /* bind multicast&broadcast netif */ udp_bind_multicast_netif(DhcpServer.Socket, &Netif->ip_addr); /* Set up the recv callback and argument. */ udp_recv(DhcpServer.Socket, (udp_recv_fn)DHCPS_RecvCb, Netif); /* Start the DHCP Server tick timer. */ sys_timeout(DHCP_TICK_TIME, _DhcpTickHandle, NULL); /* Enable the DHCP Server. */ DhcpServer.Enable = 1; return DHCPS_ERR_SUCCESS; } /*------------------------------------------------------------------------- Description: This function is used to disable dhcp server. Arguments: None. Return Value: None. Note: -------------------------------------------------------------------------*/ void DHCPS_Stop(void) { /* Disable the dhcp server's service. */ DhcpServer.Enable = 0; /* Stop the tick timer. */ sys_untimeout(_DhcpTickHandle, NULL); /* Release the socket. */ if(DhcpServer.Socket) { udp_remove(DhcpServer.Socket); } memset(&DhcpServer, 0, sizeof(DhcpServer)); } #endif