pure sdk for main
This commit is contained in:
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file dhcpd_eloop.c
|
||||
* @author HUGE-IC Application Team
|
||||
* @version V1.0.0
|
||||
* @date 2021-07-16
|
||||
* @brief a simple dhcp server
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2021 HUGE-IC</center></h2>
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#include "sys_config.h"
|
||||
#include "typesdef.h"
|
||||
#include "list.h"
|
||||
#include "osal/task.h"
|
||||
#include "osal/string.h"
|
||||
#include "osal/sleep.h"
|
||||
#include "lib/common/sysevt.h"
|
||||
#include "lib/net/utils.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "netif/ethernetif.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/prot/dhcp.h"
|
||||
#include "dhcpd_eloop.h"
|
||||
#include "event.h"
|
||||
|
||||
|
||||
#define dhcpd_dbg(fmt, ...) os_printf(fmt, ##__VA_ARGS__)
|
||||
#define dhcpd_err(fmt, ...) os_printf(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define DHCPD_RECVBUF_SIZE (1024)
|
||||
|
||||
struct dhcpd_ipaddr {
|
||||
struct list_head list;
|
||||
uint32 ip;
|
||||
uint64 lifetime;
|
||||
uint8 mac[6];
|
||||
};
|
||||
|
||||
struct dhcpd_optinfo {
|
||||
uint32 request_ip;
|
||||
uint8 msg_type;
|
||||
};
|
||||
|
||||
struct dhcpd_mgr {
|
||||
uint8 stop: 1;
|
||||
uint8 recvbuf[DHCPD_RECVBUF_SIZE];
|
||||
int32 sock;
|
||||
struct dhcpd_param param;
|
||||
struct dhcpd_optinfo info;
|
||||
struct list_head addr_list;
|
||||
uint32 nextip; // LITTLE_ENDIAN
|
||||
struct netif *netif;
|
||||
|
||||
void *dhcp_event;
|
||||
void *dhcp_timer_event;
|
||||
};
|
||||
|
||||
static struct dhcpd_mgr *dhcpd;
|
||||
|
||||
#if 0
|
||||
static int32 dhcpd_recv(uint32 tmo)
|
||||
{
|
||||
uint32 ret = 0;
|
||||
fd_set rset;
|
||||
socklen_t len = 0;
|
||||
struct timeval tv;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(dhcpd->sock, &rset);
|
||||
tv.tv_sec = tmo / 1000;
|
||||
tv.tv_usec = (tmo % 1000) * 1000;
|
||||
ret = select(dhcpd->sock + 1, &rset, NULL, NULL, &tv);
|
||||
if (ret > 0) {
|
||||
ret = recvfrom(dhcpd->sock, dhcpd->recvbuf, DHCPD_RECVBUF_SIZE, 0, (struct sockaddr *)&addr, &len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dhcpd_send(uint8 *dest, uint32 dstip, uint8 *data, uint32 len)
|
||||
{
|
||||
struct udpdata_info udp;
|
||||
uint8 bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
struct pbuf *buf = pbuf_alloc(PBUF_RAW, len + 14 + 20 + 12, PBUF_POOL);
|
||||
if (buf) {
|
||||
udp.dest = dest ? dest : bcast_addr;
|
||||
udp.src = dhcpd->netif->hwaddr;
|
||||
udp.dest_ip = ntohl(dstip);
|
||||
udp.src_ip = ntohl(dhcpd->netif->ip_addr.addr);
|
||||
udp.dest_port = 68;
|
||||
udp.src_port = 67;
|
||||
udp.data = data;
|
||||
udp.len = len;
|
||||
net_setup_udpdata(&udp, buf->payload);
|
||||
dhcpd->netif->linkoutput(dhcpd->netif, buf);
|
||||
pbuf_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void dhcpd_check_expired(void *ei, void *d)
|
||||
{
|
||||
uint64 jiff = os_jiffies();
|
||||
struct dhcpd_ipaddr *entry = NULL;
|
||||
struct dhcpd_ipaddr *nxt = NULL;
|
||||
struct dhcpd_mgr *dhcpd = (struct dhcpd_mgr *)d;
|
||||
struct list_head *head = &dhcpd->addr_list;
|
||||
|
||||
list_for_each_entry_safe(entry, nxt, head, list) {
|
||||
if (TIME_AFTER(jiff, entry->lifetime + os_msecs_to_jiffies(dhcpd->param.lease_time * 1000))) {
|
||||
list_del(&entry->list);
|
||||
dhcpd_dbg("ip (%s-"MACSTR") expired, del it\r\n", inet_ntoa(entry->ip), MAC2STR(entry->mac));
|
||||
os_free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dhcpd_dump_ippool(void)
|
||||
{
|
||||
struct dhcpd_ipaddr *entry = NULL;
|
||||
struct list_head *head = &dhcpd->addr_list;
|
||||
|
||||
dhcpd_dbg("IP Pool:\r\n");
|
||||
list_for_each_entry(entry, head, list) {
|
||||
dhcpd_dbg(" ip:%s - "MACSTR"\r\n", inet_ntoa(entry->ip), MAC2STR(entry->mac));
|
||||
}
|
||||
}
|
||||
|
||||
bool dhcpd_get_mac_by_ip(uint32 ip,uint8 *mac){
|
||||
struct dhcpd_ipaddr *entry = NULL;
|
||||
struct list_head *head = &dhcpd->addr_list;
|
||||
list_for_each_entry(entry, head, list) {
|
||||
if(ip == entry->ip){
|
||||
memcpy(mac,entry->mac,6);
|
||||
return RET_OK;
|
||||
}
|
||||
}
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
static uint32 dhcpd_next_ip(uint32 ip, uint32 mask)
|
||||
{
|
||||
uint32 subip = (ip&~mask)+1;
|
||||
uint32 newip = (ip&mask)+(subip&~mask);
|
||||
if(newip < ntohl(dhcpd->param.start_ip) || newip > ntohl(dhcpd->param.end_ip)){
|
||||
newip = ntohl(dhcpd->param.start_ip);
|
||||
}
|
||||
dhcpd_dbg("Next IP: "IPSTR"\r\n", IP2STR_H(newip));
|
||||
return newip;
|
||||
}
|
||||
|
||||
static struct dhcpd_ipaddr *dhcpd_find_ip(uint32 ip, uint8 *mac)
|
||||
{
|
||||
struct dhcpd_ipaddr *entry = NULL;
|
||||
struct list_head *head = &dhcpd->addr_list;
|
||||
|
||||
if (ip || mac) {
|
||||
list_for_each_entry(entry, head, list) {
|
||||
if ((ip && htonl(ip) == entry->ip) || (mac && os_memcmp(mac, entry->mac, 6) == 0)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32 dhcpd_check_ip(uint32 ip, uint8 *mac)
|
||||
{
|
||||
struct dhcpd_ipaddr *entry = dhcpd_find_ip(ip, 0);
|
||||
return (entry ? (os_memcmp(entry->mac, mac, 6) == 0) : 1);
|
||||
}
|
||||
|
||||
static uint32 dhcpd_netcmp(uint32 ip)
|
||||
{
|
||||
/* !0 if the network identifiers of both address match */
|
||||
return ((ip & ntohl(dhcpd->param.netmask)) == (ntohl(dhcpd->param.start_ip) & ntohl(dhcpd->param.netmask)));
|
||||
}
|
||||
|
||||
static uint32 dhcpd_free_ipaddr()
|
||||
{
|
||||
uint32 ip = dhcpd->nextip;
|
||||
|
||||
while(dhcpd_find_ip(dhcpd->nextip, 0)){
|
||||
dhcpd->nextip = dhcpd_next_ip(dhcpd->nextip, ntohl(dhcpd->param.netmask));
|
||||
if(dhcpd->nextip == ip){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return dhcpd->nextip;
|
||||
}
|
||||
|
||||
static uint32 dhcpd_get_ip(uint32 ip, uint8 *mac)
|
||||
{
|
||||
struct dhcpd_ipaddr *entry = dhcpd_find_ip(0, mac);
|
||||
if (entry == NULL) {
|
||||
if(ip == 0){
|
||||
if(!dhcpd_free_ipaddr()){
|
||||
SYSEVT_NEW_NETWORK_EVT(SYSEVT_DHCPD_IPPOOL_FULL, 0);
|
||||
return 0;
|
||||
}
|
||||
ip = dhcpd->nextip;
|
||||
}
|
||||
entry = os_zalloc(sizeof(struct dhcpd_ipaddr));
|
||||
if (entry) {
|
||||
list_add(&entry->list, &dhcpd->addr_list);
|
||||
entry->ip = htonl(ip);
|
||||
os_memcpy(entry->mac, mac, 6);
|
||||
entry->lifetime = os_jiffies();
|
||||
dhcpd->nextip = dhcpd_next_ip(dhcpd->nextip, ntohl(dhcpd->param.netmask));
|
||||
}
|
||||
}else{
|
||||
if(ip) entry->ip = htonl(ip);
|
||||
entry->lifetime = os_jiffies();
|
||||
}
|
||||
return (entry ? entry->ip: 0);
|
||||
}
|
||||
|
||||
static void dhcpd_send_nak(struct dhcp_msg *msg)
|
||||
{
|
||||
uint16 flags = get_unaligned_be16(&msg->flags);
|
||||
uint8 *opt = (uint8 *)msg + DHCP_OPTIONS_OFS;
|
||||
msg->op = 2;
|
||||
|
||||
*opt++ = DHCP_OPTION_MESSAGE_TYPE;
|
||||
*opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
|
||||
*opt++ = DHCP_NAK;
|
||||
|
||||
*opt++ = DHCP_OPTION_END;
|
||||
dhcpd_dbg("send DHCP_NAK to "MACSTR"\r\n", MAC2STR(msg->chaddr));
|
||||
dhcpd_send((flags&0x8000) ? NULL : msg->chaddr, 0xffffffff, (uint8 *)msg, (uint32)opt - (uint32)msg);
|
||||
}
|
||||
|
||||
static void dhcpd_reply(struct dhcp_msg *msg, uint8 reply)
|
||||
{
|
||||
uint8 *opt = (uint8 *)msg + DHCP_OPTIONS_OFS;
|
||||
uint32 ip = dhcpd_get_ip(dhcpd->info.request_ip, msg->chaddr);
|
||||
uint16 flags = get_unaligned_be16(&msg->flags);
|
||||
|
||||
/* dhcp server don't need setup client ip addr */
|
||||
put_unaligned_le32(0, &msg->ciaddr);
|
||||
if (ip == 0) {
|
||||
dhcpd_send_nak(msg);
|
||||
dhcpd_err("no free ip address\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// little order IP use IP2STR_H, and can not use inet_ntoa() at same statement
|
||||
dhcpd_err("Assign IP "IPSTR" for "MACSTR", flags=%x (next:"IPSTR")\r\n",
|
||||
IP2STR_N(ip), MAC2STR(msg->chaddr), flags, IP2STR_H(dhcpd->nextip));
|
||||
msg->op = 2;
|
||||
put_unaligned_le32(ip, &msg->yiaddr);
|
||||
|
||||
*opt++ = DHCP_OPTION_MESSAGE_TYPE;
|
||||
*opt++ = 1;
|
||||
*opt++ = reply;
|
||||
|
||||
*opt++ = DHCP_OPTION_SERVER_ID;
|
||||
*opt++ = 4;
|
||||
put_unaligned_le32(dhcpd->netif->ip_addr.addr, opt); opt += 4;
|
||||
|
||||
*opt++ = DHCP_OPTION_LEASE_TIME;
|
||||
*opt++ = 4;
|
||||
put_unaligned_be32(dhcpd->param.lease_time, opt); opt += 4;
|
||||
|
||||
*opt++ = DHCP_OPTION_SUBNET_MASK;
|
||||
*opt++ = 4;
|
||||
put_unaligned_le32(dhcpd->param.netmask, opt); opt += 4;
|
||||
|
||||
if (dhcpd->param.router) {
|
||||
*opt++ = DHCP_OPTION_ROUTER;
|
||||
*opt++ = 4;
|
||||
put_unaligned_le32(dhcpd->param.router, opt); opt += 4;
|
||||
}
|
||||
|
||||
if (dhcpd->param.dns1) {
|
||||
*opt++ = DHCP_OPTION_DNS_SERVER;
|
||||
*opt++ = 8;
|
||||
put_unaligned_le32(dhcpd->param.dns1, opt); opt += 4;
|
||||
put_unaligned_le32(dhcpd->param.dns2, opt); opt += 4;
|
||||
}
|
||||
|
||||
*opt++ = DHCP_OPTION_END;
|
||||
dhcpd_send((flags&0x8000) ? NULL : msg->chaddr, (flags&0x8000) ? 0xffffffff : ip, (uint8 *)msg, (uint32)opt - (uint32)msg);
|
||||
}
|
||||
|
||||
static void dhcpd_send_ack(struct dhcp_msg *msg)
|
||||
{
|
||||
dhcpd_dbg("send DHCP_ACK ...\r\n");
|
||||
return dhcpd_reply(msg, DHCP_ACK);
|
||||
}
|
||||
|
||||
static void dhcpd_send_offer(struct dhcp_msg *msg)
|
||||
{
|
||||
dhcpd_dbg("send DHCP_OFFER ...\r\n");
|
||||
return dhcpd_reply(msg, DHCP_OFFER);
|
||||
}
|
||||
|
||||
static void dhcpd_parse_opt(uint8 *dhcp_opt, int32 len, struct dhcpd_optinfo *info)
|
||||
{
|
||||
uint8 *opts = dhcp_opt;
|
||||
uint8 option;
|
||||
uint8 opt_len;
|
||||
|
||||
info->request_ip = 0;
|
||||
info->msg_type = 0;
|
||||
while (opts < dhcp_opt + len) {
|
||||
option = *opts++;
|
||||
opt_len = *opts++;
|
||||
switch (option) {
|
||||
case DHCP_OPTION_REQUESTED_IP:
|
||||
info->request_ip = get_unaligned_be32(opts);
|
||||
break;
|
||||
case DHCP_OPTION_MESSAGE_TYPE:
|
||||
info->msg_type = *opts;
|
||||
break;
|
||||
case DHCP_OPTION_END:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
opts += opt_len;
|
||||
}
|
||||
}
|
||||
|
||||
static void dhcpd_task_eloop(void *ei, void *d)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint8 *dhcp_opt;
|
||||
socklen_t len = 0;
|
||||
struct sockaddr_in addr;
|
||||
struct dhcp_msg *msg;
|
||||
struct dhcpd_mgr *dhcpd = (struct dhcpd_mgr *)d;
|
||||
ret = recvfrom(dhcpd->sock, dhcpd->recvbuf, DHCPD_RECVBUF_SIZE, 0, (struct sockaddr *)&addr, &len);
|
||||
if (ret >= (int32)DHCP_OPTIONS_OFS && !dhcpd->stop) {
|
||||
msg = (struct dhcp_msg *)dhcpd->recvbuf;
|
||||
if (msg->op == DHCP_BOOTREQUEST && msg->cookie == PP_HTONL(DHCP_MAGIC_COOKIE)) {
|
||||
os_memset(&dhcpd->info, 0, sizeof(dhcpd->info));
|
||||
dhcp_opt = dhcpd->recvbuf + DHCP_OPTIONS_OFS;
|
||||
dhcpd_parse_opt(dhcp_opt, ret - DHCP_OPTIONS_OFS, &dhcpd->info);
|
||||
if (dhcpd->info.msg_type == DHCP_DISCOVER) {
|
||||
if (!dhcpd_netcmp(dhcpd->info.request_ip) || !dhcpd_check_ip(dhcpd->info.request_ip, msg->chaddr)) {
|
||||
dhcpd->info.request_ip = 0;
|
||||
}
|
||||
dhcpd_send_offer(msg);
|
||||
} else if (dhcpd->info.msg_type == DHCP_REQUEST) {
|
||||
/* request_ip is empty then check client ip addr */
|
||||
if (dhcpd->info.request_ip == 0) {
|
||||
dhcpd->info.request_ip = ntohl(msg->ciaddr.addr);
|
||||
}
|
||||
if(dhcpd->info.request_ip && dhcpd_netcmp(dhcpd->info.request_ip)){
|
||||
if(!dhcpd_check_ip(dhcpd->info.request_ip, msg->chaddr)){
|
||||
dhcpd_send_nak(msg);
|
||||
}
|
||||
else{
|
||||
dhcpd_send_ack(msg);
|
||||
SYSEVT_NEW_NETWORK_EVT(SYSEVT_DHCPD_NEW_IP, dhcpd->info.request_ip);
|
||||
dhcpd_dump_ippool();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dhcpd_dbg("unsupport msg:%d\r\n", dhcpd->info.msg_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
//dhcpd_check_expired();
|
||||
|
||||
}
|
||||
|
||||
__init static int32 _dhcpd_start(char *ifname, struct dhcpd_param *param)
|
||||
{
|
||||
int32 ret = -1;
|
||||
int32 sock = -1;
|
||||
int32 optval = 1;
|
||||
struct sockaddr_in local_addr;
|
||||
struct ifreq nif;
|
||||
|
||||
dhcpd = os_zalloc(sizeof(struct dhcpd_mgr));
|
||||
if(dhcpd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&dhcpd->addr_list);
|
||||
dhcpd->netif = netif_find(ifname);
|
||||
if (dhcpd->netif == NULL) {
|
||||
dhcpd_err("netif:%s is not exist\r\n", ifname);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1) {
|
||||
dhcpd_err("create socket failed\r\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
fcntl(sock, F_SETFL, O_NONBLOCK);
|
||||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
|
||||
os_strncpy(nif.ifr_name, dhcpd->netif->name, 2);
|
||||
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &nif, sizeof(nif));
|
||||
os_memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_port = htons(67);
|
||||
local_addr.sin_addr.s_addr = dhcpd->netif->ip_addr.addr;
|
||||
ret = bind(sock, (struct sockaddr *)&local_addr, sizeof(struct sockaddr));
|
||||
if (ret == -1) {
|
||||
dhcpd_err("bind fail\r\n");
|
||||
closesocket(sock);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
dhcpd->sock = sock;
|
||||
os_memcpy(&dhcpd->param, param, sizeof(struct dhcpd_param));
|
||||
dhcpd->nextip = ntohl(dhcpd->param.start_ip);
|
||||
//OS_TASK_INIT("dhcpd", &dhcpd->task, dhcpd_task, NULL, OS_TASK_PRIORITY_NORMAL, 1024);
|
||||
dhcpd->dhcp_event = (void*) eloop_add_fd( dhcpd->sock, EVENT_READ, EVENT_F_ENABLED, dhcpd_task_eloop, dhcpd );
|
||||
dhcpd->dhcp_timer_event = (void*) eloop_add_timer(500, EVENT_F_ENABLED, dhcpd_check_expired, dhcpd);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int32 dhcpd_start_eloop(char *ifname, struct dhcpd_param *param)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
if (ifname == NULL || param == NULL) {
|
||||
dhcpd_err("invalid param!\r\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
if(dhcpd){
|
||||
dhcpd->stop = 1;
|
||||
if(dhcpd->dhcp_event)
|
||||
{
|
||||
eloop_remove_event(dhcpd->dhcp_event);
|
||||
}
|
||||
|
||||
if(dhcpd->dhcp_timer_event)
|
||||
{
|
||||
eloop_remove_event(dhcpd->dhcp_timer_event);
|
||||
}
|
||||
|
||||
if(dhcpd->sock)
|
||||
{
|
||||
closesocket(dhcpd->sock);
|
||||
}
|
||||
dhcpd_err("dhcpd already running ...,first stop last dhcp\r\n");
|
||||
//return RET_OK;
|
||||
os_free(dhcpd);
|
||||
dhcpd = NULL;
|
||||
}
|
||||
|
||||
ret = _dhcpd_start(ifname, param);
|
||||
ASSERT(!ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dhcpd_stop_eloop(char *ifname)
|
||||
{
|
||||
if(dhcpd){
|
||||
dhcpd->stop = 1;
|
||||
if(dhcpd->dhcp_event)
|
||||
{
|
||||
eloop_remove_event(dhcpd->dhcp_event);
|
||||
}
|
||||
|
||||
if(dhcpd->dhcp_timer_event)
|
||||
{
|
||||
eloop_remove_event(dhcpd->dhcp_timer_event);
|
||||
}
|
||||
|
||||
if(dhcpd->sock)
|
||||
{
|
||||
closesocket(dhcpd->sock);
|
||||
}
|
||||
dhcpd_err("stop last dhcp\r\n");
|
||||
//return RET_OK;
|
||||
os_free(dhcpd);
|
||||
dhcpd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user