UDHCP+Option 开发

本文介绍如何在UDHCP开发包中实现DHCP协议的自定义Option功能,包括客户端和服务器端的开发步骤。通过定义特定结构体并在构造数据包时加入自定义Option,实现了数据的有效传输。

不知道是哪个聪明人发明的,使用DHCP协议来做数据的传输…….,该协议使用的可是broadcast的方式去search需要的东西,所以DHCP协议出现了LEASE这种东西,就是防止客户端经常去使用该协议.       回到正文…
网络上关于DHCP协议上自定义option的开发资料很少,我们使用的是UDHCP的开发包,如果要支持自定义的option那就需要在客户端和服务器端分别做开发.
Client:
       Clientpacket.c
              static void init_packet(struct dhcpMessage *packet, char type)
              {
                            //这里我们需要定义一个结构体,为了增加option字段
                            //特别str可以写成””,因为该字段是作为option的显示字段
                            //但如果不是系统保留的option号,那么这里只会显示private
                            struct usermodule
                            {
                                   char um,length;
                                   char str[64];
                            }_usermod={DHCP_USER_DEFINE161,64,""};
              _usermod={DHCP_USER_DEFINE161,64,""};
              //增加两个option
              struct usermodule _usermod1={DHCP_USER_DEFINE162,64,""};
              struct usermodule _usermod2={DHCP_USER_DEFINE163,64,""};
              //在构造包体时添加字段
              add_option_string(packet->options, (unsigned char *) &_usermod);
              add_option_string(packet->options, (unsigned char *) &_usermod1);
              add_option_string(packet->options, (unsigned char *) &_usermod2);
}
Dhcpd.h
#define DHCP_USER_DEFINE161 0xA1   //这里一定要16位的
#define DHCP_USER_DEFINE162 0xA2
#define DHCP_USER_DEFINE163 0xA3
Server端:
                     Dhcpd.h
struct server_config_t {
                                   char *opt_161;          
                                   char *opt_162;                      
                                   char *opt_163;                      
}
        Files.c
static struct config_keyword keywords[] = {
                     {"161",read_str,&(server_config.opt_161),  "My Network 161"},
                     {"162",read_str,&(server_config.opt_162),  "My Network 162"},
              {"163",read_str,&(server_config.opt_163),  "My Network 163"}
}
//这两个部分主要时为了Udhcpd在启动时会读取udhcpd.conf的文件,我们可以提前在该文件中定义好所有的option,所以这就需要程序的支持,
在做通讯时,DHCPD会将自定义的option放在offer包中,client只要解析就可以了.

后面我将给你一个IPC的dhcps模块,给我注释,大概1000行代码, /* dhcps.h */ #ifndef _DHCPS_H #define _DHCPS_H #include "dhcp.h" #define MAX_FILE_NAME_LEN 256 #define MAX_BOOTP_SRV_NAME_LEN 16 #define DHCPS_DOMAIN_NAME_LENGTH 32 #define DHCP_4G_ROUTER_STR "4g router" #define DHCP_4G_ROUTER_LEN 9 /***************************************************************************************** **********************DHCPS SERVER CLASS************************************************** *****************************************************************************************/ #define DHCPS_LEASE_LIST_SIZE 128 typedef struct _DHCPS_LEASE { U8 host_name[32]; U8 mac[6]; U32 state; U32 ip; U32 expires; }DHCPS_LEASE; typedef struct _DHCP_OPTION_STATIC { UINT8 lease[6]; UINT8 subnet[6]; UINT8 router[6]; UINT8 dns[10]; char domain[34]; UINT8 router4g[DHCP_4G_ROUTER_LEN+2]; }DHCP_OPTION_STATIC; /* Struct to store public server config.*/ typedef struct _DHCPS_PARAMS { S32 sock; /* Berkeley Packet Filter Device in vxworks OS or skt in linux OS */ S32 inet_iendx; S32 timer_index; char dev_name[32]; S32 dev; UINT8 mac[6]; /* Our mac address */ U32 decline_time; /* how long an address is reserved if a client returns a * decline message */ U32 conflict_time; /* how long an arp conflict offender is leased for */ U32 offer_time; /* how long an offered address is reserved */ U32 min_lease; /* minimum lease a client can request*/ U32 server; /* Our IP, in network order */ U32 netmask; /* Our netmask */ U32 gateway; /*added by yangying for*/ U32 dns_server[2]; char host_name[DHCPS_DOMAIN_NAME_LENGTH]; DHCP_OPTION_STATIC options; /* List of DHCP options loaded from the config file */ U32 start; /* Start address of leases, network order */ U32 end; /* End of leases, network order */ U32 lease_time; /* lease time in seconds (host order) */ U32 siaddr; /* next server bootp option */ char sname[MAX_BOOTP_SRV_NAME_LEN]; /* bootp server name */ char boot_file[MAX_FILE_NAME_LEN]; /* bootp boot file option */ DHCPS_LEASE lease[DHCPS_LEASE_LIST_SIZE]; U16 is_lte; }DHCPS_PARAMS; #define DHCPS_DEBUG(fmt, ...) NSD_DEBUG("[DHCPS]" fmt, ##__VA_ARGS__) #define DHCPS_INFO(fmt, ...) NSD_LOG(LOG_INFO, "[Network][DHCP]" fmt, ##__VA_ARGS__) #define DHCPS_WARN(fmt, ...) NSD_WARN("[DHCPS]" fmt, ##__VA_ARGS__) #endif /* dhcps.c * * udhcp Server * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au> * Chris Trew <ctrew@moreton.com.au> * * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <netinet/if_ether.h> #include <linux/filter.h> #include <linux/if_packet.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "options.h" #include "packet.h" #include "dhcp.h" #include "dhcps.h" #include "libds.h" /* DHCPS模块中各个参数项单位都改为秒 */ #define LEASE_TIME_MAX (48*60*60) /* 租期最长2天 */ #define LEASE_TIME_MIN (1*60) /* 租期最短一分钟 */ #define LEASE_OFFER_TIME (2*60*60) #define DECLINE_TIME (60*60) #define CONFLICT_TIME (60*60) #define DHCP_CHANGE_RECEIVE_PORT 52261 #define DHCP_CHANGE_SEND_PORT 52262 #define DEFAULT_DHCPS_IP "192.168.191.1" #define DEFAULT_DHCPS_MASK "255.255.255.0" #define DEF_DHCPS_IP_BEGIN "192.168.191.120" #define DEF_DHCPS_IP_END "192.168.191.199" #define DHCPS_HOST_NAME_LEN 32 #define DHCPS_OPTION_AUTO "auto" #define DHCPS_OPTION_ENABLE "enable" #define DHCPS_OPTION_POOLSTART "pool_start" #define DHCPS_OPTION_POOLEND "pool_end" #define DHCPS_OPTION_LEASETIME "lease_time" #define DHCPS_OPTION_GATEWAY "gateway" #define DHCPS_OPTION_PRIDNS "pri_dns" #define DHCPS_OPTION_SNDDNS "snd_dns" #define DHCPS_OPTION_IP "ip" #define DHCPS_OPTION_MAC "mac" #define DHCPS_OPTION_EXPIRES "expires" #define DHCPS_OPTION_HOSTNAME "hostname" DHCPS_PARAMS dhcps_params; LOCAL struct dhcp_packet recv_dhcp_packet; LOCAL struct dhcp_packet packet; #define DHCPS_MALLOC(size) malloc(size) #define DHCPS_FREE(addr) free((UINT8*)(addr)) #define ISNOTSAMESUBNET(ip1, ip2, mask) (0 != (((ip1) ^ (ip2)) & (mask))) /* 是否4G IPC - 4G上网模式 */ LOCAL U16 get_lte_enabled(void) { LTE_CAPABILITY lte_cap = {0}; LTE_CONFIG_INFO_DATA lte_config = {0}; if (0 == ds_read(LTE_CAPABILITY_PATH, (U8 *)&lte_cap, sizeof(lte_cap))) { //未定义lte_capability,判断为非4G IPC,未开启4G上网模式 return 0; } if (0 == ds_read(LTE_INFO_DATA_PATH, (U8 *)&lte_config, sizeof(lte_config))) { //4G IPC默认4G上网模式,获取失败时按照4G上网处理 return 1; } return !(lte_cap.internet_wired_support && lte_config.internet_wired_enable); } /* clear every lease out that chaddr OR yiaddr matches and is nonzero */ LOCAL void clear_lease(U8 *mac, U32 ip, DHCPS_LEASE *leases) { S32 i, j, k; for (j = 0; j < CHADDR_LEN && !mac[j]; j++); for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++) { if ((j != CHADDR_LEN && !memcmp(leases[i].mac, mac, 6)) || (ip && leases[i].ip == ip)) { memset(&(leases[i]), 0, sizeof(leases[i])); for (k = i;(k + 1) < DHCPS_LEASE_LIST_SIZE; k++) { memcpy(&(leases[k]), &(leases[k + 1]), sizeof(leases[k])); memset(&(leases[k + 1]), 0, sizeof(leases[k + 1])); } i--; } } } /* Find the oldest expired lease, NULL if there are no expired leases */ LOCAL S32 oldest_expired_lease(DHCPS_LEASE *leases) { U32 i; for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++) { if (leases[i].expires == 0) { return i; } } return -1; } /* add a lease into the table, clearing out any old ones */ LOCAL S32 add_lease(U32 state, char *host_name, U8 *mac, U32 ip, U32 time_lease, DHCPS_LEASE *dhcps_lease) { S32 lease_index = -1 ; IP_ADDR ipAddr = {0}; /* clean out any old ones */ clear_lease(mac, ip, dhcps_lease); lease_index = oldest_expired_lease(dhcps_lease); if (lease_index != -1) { dhcps_lease[lease_index].state = state; DHCPS_DEBUG("state = %d", dhcps_lease[lease_index].state); memcpy(dhcps_lease[lease_index].host_name, host_name, 32); /* add by Li Shaozhang, 07Jun07 */ DHCPS_DEBUG("hostname = %s", dhcps_lease[lease_index].host_name); memcpy(dhcps_lease[lease_index].mac, mac, 6); DHCPS_DEBUG("mac = %02x-%02x-%02x-%02x-%02x-%02x", dhcps_lease[lease_index].mac[0],\ dhcps_lease[lease_index].mac[1], dhcps_lease[lease_index].mac[2],\ dhcps_lease[lease_index].mac[3], dhcps_lease[lease_index].mac[4],\ dhcps_lease[lease_index].mac[5]); dhcps_lease[lease_index].ip = ip; ipAddr.ipAddr = ip; DHCPS_DEBUG("ip = %d.%d.%d.%d", ipAddr.ipAddrByteFormat[0], ipAddr.ipAddrByteFormat[1], ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]); dhcps_lease[lease_index].expires = time_lease; DHCPS_DEBUG("lease = %d", dhcps_lease[lease_index].expires); } return lease_index; } /* true if a lease has expired */ LOCAL S32 lease_expired(S32 lease_index, DHCPS_LEASE *dhcps_lease) { return (dhcps_lease[lease_index].expires == 0); } /* * Find the first lease that matches chaddr, NULL if no match. * Modified by xcl, if the lease ip is not in the same subnet, deleted it and return null. */ LOCAL S32 find_lease_by_mac(U8 *mac, DHCPS_LEASE *dhcps_lease) { U32 i; for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++) { if (!memcmp(dhcps_lease[i].mac, mac, 6)) { /* If not in the very subnet, delete this lease. Modified by xcl.*/ if (0 == ((dhcps_lease[i].ip ^ dhcps_params.server) & dhcps_params.netmask)) { return i; } memset(&(dhcps_lease[i]), 0, sizeof(dhcps_lease[i])); } } return -1; } /* Find the first lease that matches yiaddr, NULL is no match */ LOCAL S32 find_lease_by_ip(U32 ip, DHCPS_LEASE *dhcps_lease) { U32 i; for (i = 0; i < DHCPS_LEASE_LIST_SIZE; i++) { if (dhcps_lease[i].ip == ip) { return i; } } return -1; } /* check is an IP is taken, if it is, add it to the lease table */ LOCAL S32 check_ip(U32 addr, DHCPS_LEASE *dhcps_lease) { char strIp[18] = {0}; /* Added for bug: dut会将lan IP(若在地址池范围内)分配出去,若收到此IP的Client无 * 免费arp检查功能,将导致IP冲突. 2011-12-27, xcl.*/ if (addr == dhcps_params.server) { DHCPS_WARN("The IP distributed equals to server ip, ignore!!!"); return 1; } if (0 == arpping(addr, recv_dhcp_packet.chaddr, dhcps_params.server, dhcps_params.mac, dhcps_params.dev_name, 500)) { DHCPS_WARN("%s belongs to someone, reserving it for %ld seconds.", strIp, dhcps_params.conflict_time); return 1; } return 0; } /* Check if an ip is in dhcp server pool or not. */ LOCAL S32 ip_in_srv_pool(U32 ip) { IP_ADDR ipAddr = {0}; ipAddr.ipAddr = ip; ip = ntohl(ip); if ((ip >= ntohl(dhcps_params.start)) && (ip <= ntohl(dhcps_params.end)) && (ip != ntohl(dhcps_params.server))) { return 1; } DHCPS_WARN("IP(%d.%d.%d.%d) not in dhcp pool or equal to server ip, ignore!!!", ipAddr.ipAddrByteFormat[0], ipAddr.ipAddrByteFormat[1], ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]); return 0; } /* find an assignable address, it check_expired is true, we check all the expired leases as well. * Maybe this should try expired leases by age... */ LOCAL U32 find_address(S32 check_expired, DHCPS_LEASE *dhcps_lease) { U32 addrStart, addrEnd; /* 主机序,用于遍历地址池 */ U32 ret; /* 网络序,存放查找到的地址 */ S32 lease_index = -1; U32 mask = 0; mask = ntohl(dhcps_params.netmask); addrStart = ntohl(dhcps_params.start); addrEnd = ntohl(dhcps_params.end); for (; addrStart <= addrEnd; addrStart++)/* Modified by xcl, 2011-06-01.*/ { ret = htonl(addrStart); /* ie, 192.168.55.0 */ if (!(ret & (~mask))) { continue; } /* ie, 192.168.55.255 */ if ((ret & (~mask)) == (~mask)) { continue; } /* ip已被dhcps分配出去 */ if (-1 != (lease_index = find_lease_by_ip(ret, dhcps_lease))) { if (check_expired && lease_expired(lease_index, dhcps_lease)) { return ret; } continue; } /* 有静态接入主机正在使用该IP也要跳过 */ if (TRUE == check_ip(ret, dhcps_lease)) { continue; } return ret; } return 0; } /* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ LOCAL S32 send_packet(struct dhcp_packet *payload, S32 force_broadcast) { U8 *chaddr = NULL; U32 ciaddr = 0; if (force_broadcast) { DHCPS_DEBUG("Broadcasting packet to client (NAK)."); ciaddr = INADDR_BROADCAST; chaddr = MAC_BCAST_ADDR; } else if (ntohs(payload->flags) & BROADCAST_FLAG) { DHCPS_DEBUG("Broadcasting packet to client (requested)."); ciaddr = INADDR_BROADCAST; chaddr = MAC_BCAST_ADDR; } else if ((0 == payload->yiaddr) && (payload->ciaddr)) { DHCPS_DEBUG("Unicasting packet to client ciaddr."); ciaddr = payload->ciaddr; chaddr = payload->chaddr; } else { ciaddr = payload->yiaddr; chaddr = payload->chaddr; } return make_and_send_dhcp_frame(payload, dhcps_params.server, SERVER_PORT, ciaddr, CLIENT_PORT, chaddr, dhcps_params.dev); } LOCAL void init_packet(struct dhcp_packet *packet, struct dhcp_packet *old_packet, char type) { init_header(packet, type); packet->xid = old_packet->xid; memcpy(packet->chaddr, old_packet->chaddr, CHADDR_LEN); packet->flags = old_packet->flags; packet->giaddr = old_packet->giaddr; packet->ciaddr = old_packet->ciaddr; add_simple_option(packet->options, DHCP_SERVER_ID, dhcps_params.server); } /* add in the bootp options */ LOCAL void add_bootp_options(struct dhcp_packet *packet) { packet->siaddr = dhcps_params.siaddr; if (dhcps_params.sname) { strncpy((char *)packet->sname, dhcps_params.sname, sizeof(packet->sname) - 1); } if (dhcps_params.boot_file) { strncpy((char *)packet->file, dhcps_params.boot_file, sizeof(packet->file) - 1); } } LOCAL S32 get_host_name_len(char* name, S32 len) { S32 index = 0; S32 language_flag = 0; if (len < 32) { return len; } for (index=0; index < 31; index++) { /* GB2312编码每个汉字及符号以两个字节来表示,高位字节使用了0xA1-0xF7,低位字节使用了0xA1-0xFE。*/ /* 为保障存储汉字不出现乱码,出现奇数个大于0xA1的字节时,去掉最后一个。这种方法只能解决采用 */ /* GB2312编码的乱码问题 */ if (*(UINT8*)(name + index) >= 0xA1) { language_flag ^= 1; } } if (language_flag == 0) { return 31; } return 30; } /* send a DHCP OFFER to a DHCP DISCOVER */ LOCAL S32 send_offer(struct dhcp_packet *old_packet, DHCPS_LEASE *dhcps_lease) { S32 lease_index = -1; U32 req_align, lease_time_align = dhcps_params.lease_time; U8 *req, *lease_time; char blank_hostname[] = /*"Unknown"*/""; S32 copy_host_name_len; IP_ADDR ip_addr = {0}; char host_name[DHCPS_HOST_NAME_LEN]; char *host_name_start, *host_name_len; U32 lease_ip; DHCPS_DEBUG("before init_packet."); init_packet(&packet, old_packet, DHCPOFFER); /* the client has a requested ip */ if ((req = get_option(old_packet, DHCP_REQUESTED_IP)) && memcpy(&req_align, req, 4) && ip_in_srv_pool(req_align) && (((-1 == (lease_index = find_lease_by_ip(req_align, dhcps_lease))) || lease_expired(lease_index, dhcps_lease)))) { lease_ip = req_align; if (TRUE == check_ip(lease_ip, dhcps_lease)) { goto choose_dynamic_lease_ip; } packet.yiaddr = lease_ip; goto send_offer; } choose_dynamic_lease_ip: lease_index = find_lease_by_mac(old_packet->chaddr, dhcps_lease); if (-1 != lease_index) { /* lease的时间到期或者ip已经不在地址池中。 */ if ((FALSE == ip_in_srv_pool(dhcps_lease[lease_index].ip)) || lease_expired(lease_index, dhcps_lease)) { memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index])); lease_index = -1; goto choose_pool_ip; } lease_time_align = dhcps_lease[lease_index].expires; packet.yiaddr = dhcps_lease[lease_index].ip; goto send_offer; } choose_pool_ip: packet.yiaddr = find_address(0, dhcps_lease); if (0 == packet.yiaddr) { packet.yiaddr = find_address(1, dhcps_lease); } if(0 == packet.yiaddr) { DHCPS_WARN("No ip addresses to give, OFFER abandoned."); return -1; } send_offer: if (0xFFFFFFFF != lease_time_align) /* 非静态条目。 */ { if (!(host_name_start = (char *)get_option(old_packet, DHCP_HOST_NAME))) { DHCPS_WARN("Lease host name not found."); /* host_name_start = blank_hostname;*/ memset(host_name, 0, DHCPS_HOST_NAME_LEN); memcpy(host_name, blank_hostname, strlen(blank_hostname)); } else { host_name_len = host_name_start - OPT_LEN; memset(host_name, 0, DHCPS_HOST_NAME_LEN); /* fix host name length bug by tiger 20091208 */ copy_host_name_len = get_host_name_len(host_name_start, *host_name_len); memcpy(host_name, host_name_start, copy_host_name_len); } if (-1 == add_lease(DHCPOFFER, host_name, packet.chaddr, packet.yiaddr, dhcps_params.offer_time, dhcps_lease)) { DHCPS_WARN("Lease pool is full, OFFER abandoned."); return -1; } if ((lease_time = get_option(old_packet, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); DHCPS_DEBUG("lease time = %d ", lease_time); lease_time_align = ntohl(lease_time_align); if (lease_time_align > (dhcps_params.lease_time*60)) { lease_time_align = (dhcps_params.lease_time*60); } } /* Make sure we aren't just using the lease time from the previous offer */ if (lease_time_align < dhcps_params.min_lease) { lease_time_align = dhcps_params.lease_time; } } DHCPS_DEBUG("OFFER lease time = %d; configed dhcp lease = %d\n", lease_time_align, dhcps_params.lease_time); add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); add_option_string(packet.options, dhcps_params.options.dns); add_option_string(packet.options, dhcps_params.options.subnet); add_option_string(packet.options, dhcps_params.options.router); if(dhcps_params.is_lte) { DHCPS_DEBUG("OFFER: lte enabled\n"); add_option_string(packet.options, dhcps_params.options.router4g); } /*addVendorSpecInfo(oldpacket, packet.options);*/ add_bootp_options(&packet); ip_addr.ipAddr = packet.yiaddr; DHCPS_INFO("Send OFFER with ip %d.%d.%d.%d.", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); return send_packet(&packet, 0); } LOCAL S32 send_NAK(struct dhcp_packet *old_packet) { init_packet(&packet, old_packet, DHCPNAK); return send_packet(&packet, 1); } LOCAL S32 send_ACK(struct dhcp_packet *old_packet, U32 ip, DHCPS_LEASE *dhcps_lease) { U8 *lease_time; U32 lease_time_align = dhcps_params.lease_time; char blank_hostname[] = /*"Unknown"*/""; IP_ADDR ipAddr = {0}; U8 host_name[DHCPS_HOST_NAME_LEN]; U8 *host_name_start = NULL; U8 *host_name_len = NULL; S32 copy_host_name_len = 0; init_packet(&packet, old_packet, DHCPACK); packet.yiaddr = ip; if ((lease_time = get_option(old_packet, DHCP_LEASE_TIME))) { memcpy(&lease_time_align, lease_time, 4); lease_time_align = ntohl(lease_time_align); if ((lease_time_align < dhcps_params.min_lease) || (lease_time_align > dhcps_params.lease_time)) { lease_time_align = dhcps_params.lease_time; } } DHCPS_DEBUG("ACK lease time = %d\n", lease_time_align); add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); add_option_string(packet.options, dhcps_params.options.dns); add_option_string(packet.options, dhcps_params.options.subnet); add_option_string(packet.options, dhcps_params.options.router); if(dhcps_params.is_lte) { DHCPS_DEBUG("ACK: lte enabled\n"); add_option_string(packet.options, dhcps_params.options.router4g); } /*addVendorSpecInfo(oldpacket, packet.options);*/ add_bootp_options(&packet); ipAddr.ipAddr = packet.yiaddr; DHCPS_DEBUG("Send ACK to %d.%d.%d.%d.", ipAddr.ipAddrByteFormat[0], ipAddr.ipAddrByteFormat[1], ipAddr.ipAddrByteFormat[2], ipAddr.ipAddrByteFormat[3]); /* TODO:只在请求OFFER时输出信息 */ if (send_packet(&packet, 0) < 0) { return -1; } if (!(host_name_start = get_option(old_packet, DHCP_HOST_NAME))) { DHCPS_DEBUG("Lease host name not found."); /* TODO:只在请求OFFER时输出信息 */ memset(host_name, 0, DHCPS_HOST_NAME_LEN); memcpy(host_name, blank_hostname, strlen(blank_hostname)); } else { /* fix host name length bug by tiger 20091208 */ host_name_len = host_name_start - OPT_LEN; copy_host_name_len = get_host_name_len((char *)host_name_start, (int)*host_name_len); if(copy_host_name_len > DHCPS_HOST_NAME_LEN) { return -1; } memset(host_name, 0, DHCPS_HOST_NAME_LEN); memcpy(host_name, host_name_start, copy_host_name_len); } add_lease(DHCPACK, (char *)host_name, packet.chaddr, packet.yiaddr, lease_time_align, dhcps_lease); return OK; } LOCAL S32 send_inform(struct dhcp_packet *old_packet) { init_packet(&packet, old_packet, DHCPACK); add_option_string(packet.options, dhcps_params.options.dns); add_option_string(packet.options, dhcps_params.options.subnet); add_option_string(packet.options, dhcps_params.options.router); if(dhcps_params.is_lte) { DHCPS_DEBUG("INFORM: lte enabled\n"); add_option_string(packet.options, dhcps_params.options.router4g); } add_bootp_options(&packet); return send_packet(&packet, 0); } LOCAL S32 check_and_ack(struct dhcp_packet* packet, UINT32 ip, DHCPS_LEASE *dhcps_lease) { IP_ADDR ip_addr1 = {0}; ip_addr1.ipAddr = ip; /* if some one reserve it */ if (ip != packet->ciaddr && check_ip(ip, dhcps_lease)) { DHCPS_INFO("REQUEST ip %d.%d.%d.%d already reserved by someone", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3]); return send_NAK(packet); } if (!ip_in_srv_pool(ip)) { DHCPS_INFO("REQUEST ip %d.%d.%d.%d is not in the address pool", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3]); return send_NAK(packet); } return send_ACK(packet, ip, dhcps_lease); } LOCAL void destroy_sock(S32 sock) { if (-1 != sock) { close(sock); } } LOCAL S32 create_sock() { struct sockaddr_in sock_addr; S32 option = 1; S32 sock = -1; /* 因为MAX_GROUP_NUM为1,而且这里也只有1份DHCP服务器配置,这里就暂不考虑为多网段提供DHCP服务了。 */ if (ERROR == (sock = socket(AF_INET, SOCK_DGRAM, 0))) { DHCPS_WARN("server socket call failed: %m"); goto error_exit; } if (ERROR == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option))) { DHCPS_WARN("server socket set reuseaddr option failed: %m"); goto error_exit; } if (ERROR == setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &option, sizeof(option))) { DHCPS_WARN("server socket set broadcast option failed: %m"); goto error_exit; } memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons(SERVER_PORT); sock_addr.sin_addr.s_addr = INADDR_ANY; /* 这里只是针对单个网段提供服务,可以这样做,但如果考虑多网段,多接口,则必须绑定接口的实际地址。 */ if (ERROR == bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr))) { DHCPS_WARN("server socket set broadcast option failed: %m"); goto error_exit; } return sock; error_exit: destroy_sock(sock); return -1; } LOCAL void dhcps_check_timer() { U32 index = 0; U32 move_index = 0; DHCPS_LEASE *dhcps_lease = NULL; dhcps_lease = dhcps_params.lease; for (index = 0; index < DHCPS_LEASE_LIST_SIZE; index++) { if (dhcps_lease[index].ip == 0 || dhcps_lease[index].expires == 0xFFFFFFFF) { continue; } if (dhcps_lease[index].expires > 0) { dhcps_lease[index].expires -= 1; continue; } for (move_index = index; (move_index + 1) < DHCPS_LEASE_LIST_SIZE; move_index++) { memcpy(&(dhcps_lease[move_index]), &(dhcps_lease[move_index + 1]), sizeof(dhcps_lease[move_index])); memset(&(dhcps_lease[move_index + 1]), 0, sizeof(dhcps_lease[move_index + 1])); } index--; } } LOCAL void dhcps_handle(S32 sock) { U8 *server_id, *requested; U32 server_id_align, requested_align; S32 bytes = 0; U8 *state = NULL; S32 lease_index = -1; DHCPS_LEASE *dhcps_lease = NULL; U32 move_index = 0; IP_ADDR ip_addr1 = {0}; IP_ADDR ip_addr2 = {0}; dhcps_lease = dhcps_params.lease; if ((bytes = get_packet(&recv_dhcp_packet, dhcps_params.sock)) < 0) { DHCPS_WARN("Error on read, %m, reopening socket."); return; } if ((state = get_option(&recv_dhcp_packet, DHCP_MESSAGE_TYPE)) == NULL) { DHCPS_WARN("Couldn't get option from packet, ignoring."); return; } lease_index = find_lease_by_mac(recv_dhcp_packet.chaddr, dhcps_lease); if (-1 != lease_index) { /* 如果租约过期需要老化,或者租约与地址段不匹配,需要强制老化。 */ if ((lease_expired(lease_index, dhcps_lease)) || !ip_in_srv_pool(dhcps_lease[lease_index].ip)) { memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index])); lease_index = -1; } } switch (state[0]) { case DHCPDISCOVER: DHCPS_DEBUG("Recv DISCOVER from %02X:%02X:%02X:%02X:%02X:%02X.", recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2], recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); /* 防止被攻击时持续刷log */ if (send_offer(&recv_dhcp_packet, dhcps_lease) < 0) { DHCPS_WARN("Send OFFER failed."); } break; case DHCPREQUEST: DHCPS_DEBUG("Recv REQUEST from %02X:%02X:%02X:%02X:%02X:%02X.", recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2], recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); requested = get_option(&recv_dhcp_packet, DHCP_REQUESTED_IP); server_id = get_option(&recv_dhcp_packet, DHCP_SERVER_ID); if (NULL != requested) { memcpy(&requested_align, requested, 4); } if (NULL != server_id) { memcpy(&server_id_align, server_id, 4); } if (-1 != lease_index) { /* SELECTING State */ if ((NULL != server_id) && (server_id_align == dhcps_params.server) && (NULL != requested) && (requested_align == dhcps_lease[lease_index].ip)) { send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease); } /* INIT-REBOOT State */ else if ((NULL == server_id) && (NULL != requested) && (dhcps_lease[lease_index].ip == requested_align)) { send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease); } /* RENEWING or REBINDING State */ else if ((NULL == server_id) && (NULL == requested) && (dhcps_lease[lease_index].ip == recv_dhcp_packet.ciaddr)) { send_ACK(&recv_dhcp_packet, dhcps_lease[lease_index].ip, dhcps_lease); } else { /* todo: 显示有效的requested_align */ ip_addr1.ipAddr = recv_dhcp_packet.ciaddr; ip_addr2.ipAddr = dhcps_lease[lease_index].ip; DHCPS_INFO("Send NAK to %d.%d.%d.%d, lease ip %d.%d.%d.%d.", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2] ,ip_addr1.ipAddrByteFormat[3], ip_addr2.ipAddrByteFormat[0], ip_addr2.ipAddrByteFormat[1],ip_addr2.ipAddrByteFormat[2], ip_addr2.ipAddrByteFormat[3]); send_NAK(&recv_dhcp_packet); } } else if (NULL != requested) { /* INIT-REBOOT State */ if (-1 != (lease_index = find_lease_by_ip(requested_align, dhcps_lease))) { /* Requested IP already reserved by other one */ if (lease_expired(lease_index, dhcps_lease)) { /* probably best if we drop this lease */ memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index])); lease_index = -1; check_and_ack(&recv_dhcp_packet, requested_align, dhcps_lease); /* make some contention for this address */ } else /* still reserved by someone */ { ip_addr1.ipAddr = requested_align; DHCPS_INFO("REQUEST ip %d.%d.%d.%d already reserved by %02X:%02X:%02X:%02X:%02X:%02X", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2], ip_addr1.ipAddrByteFormat[3], dhcps_lease[lease_index].mac[0], dhcps_lease[lease_index].mac[1], dhcps_lease[lease_index].mac[2], dhcps_lease[lease_index].mac[3], dhcps_lease[lease_index].mac[4], dhcps_lease[lease_index].mac[5]); send_NAK(&recv_dhcp_packet); } } else { check_and_ack(&recv_dhcp_packet, requested_align, dhcps_lease); } } else { ip_addr1.ipAddr = recv_dhcp_packet.ciaddr; DHCPS_INFO("Send NAK to %d.%d.%d.%d.", ip_addr1.ipAddrByteFormat[0], ip_addr1.ipAddrByteFormat[1], ip_addr1.ipAddrByteFormat[2], ip_addr1.ipAddrByteFormat[3]); send_NAK(&recv_dhcp_packet); } /* otherwise on reply. */ break; case DHCPDECLINE: DHCPS_INFO("Recv DECLINE from %02X:%02X:%02X:%02X:%02X:%02X.", recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2], recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); if (lease_index != -1) { memset(dhcps_lease[lease_index].mac, 0, 6); dhcps_lease[lease_index].expires = dhcps_params.decline_time; dhcps_lease[lease_index].state = 0; } break; case DHCPRELEASE: DHCPS_INFO("Recv RELEASE from %02X:%02X:%02X:%02X:%02X:%02X.", recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2], recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); if (lease_index != -1) { /* Delete the lease, lsz 080221 */ memset(&(dhcps_lease[lease_index]), 0, sizeof(dhcps_lease[lease_index])); for (move_index = lease_index; (move_index + 1) < DHCPS_LEASE_LIST_SIZE; move_index++) { memcpy(&(dhcps_lease[move_index]), &(dhcps_lease[move_index + 1]), sizeof(dhcps_lease[move_index])); memset(&(dhcps_lease[move_index + 1]), 0, sizeof(dhcps_lease[move_index + 1])); } } break; case DHCPINFORM: DHCPS_DEBUG("Recv INFORM from %02X:%02X:%02X:%02X:%02X:%02X.", recv_dhcp_packet.chaddr[0], recv_dhcp_packet.chaddr[1], recv_dhcp_packet.chaddr[2], recv_dhcp_packet.chaddr[3], recv_dhcp_packet.chaddr[4], recv_dhcp_packet.chaddr[5]); send_inform(&recv_dhcp_packet); break; default: DHCPS_WARN("Unsupported DHCP message (%02x) -- ignoring.", state[0]); } return; } LOCAL S32 dhcps_start_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { DHCPS_MSG *dhcps_msg = (DHCPS_MSG *)mbuf; U32 temp_ip = 0; IP_ADDR ipaddr; if ((NULL == dhcps_msg) || (mlen != sizeof(DHCPS_MSG))) { return ERROR; } strcpy(dhcps_params.dev_name, dhcps_msg->dev_name); if (0 > read_interface_info(dhcps_params.dev_name, &dhcps_params.dev, dhcps_params.mac)) { DHCPS_DEBUG("Read interface info error"); return ERROR; } if (ntohl(dhcps_msg->pool_start) > ntohl(dhcps_msg->pool_end)) { temp_ip = dhcps_msg->pool_start; dhcps_msg->pool_start = dhcps_msg->pool_end; dhcps_msg->pool_end = temp_ip; } if ((dhcps_msg->pool_start != dhcps_params.start) || (dhcps_msg->pool_end != dhcps_params.end)) { dhcps_params.start= dhcps_msg->pool_start; dhcps_params.end = dhcps_msg->pool_end; memset(dhcps_params.lease, 0, sizeof(DHCPS_LEASE)*DHCPS_LEASE_LIST_SIZE); } dhcps_params.gateway = dhcps_msg->gateway; dhcps_params.lease_time = dhcps_msg->lease_time; dhcps_params.dns_server[0] = dhcps_msg->pri_dns; dhcps_params.dns_server[1] = dhcps_msg->snd_dns; dhcps_params.server = dhcps_msg->gateway; dhcps_params.netmask = dhcps_msg->netmask; /* 是否4G路由 */ dhcps_params.is_lte = get_lte_enabled(); memset(&dhcps_params.options, 0, sizeof(DHCP_OPTION_STATIC)); dhcps_params.options.lease[0] = DHCP_LEASE_TIME; dhcps_params.options.lease[1] = 4; memcpy(&(dhcps_params.options.lease[2]), &(dhcps_params.lease_time), 4); temp_ip = dhcps_params.netmask; dhcps_params.options.subnet[0] = DHCP_SUBNET; dhcps_params.options.subnet[1] = 4; memcpy(&(dhcps_params.options.subnet[2]), (char *)&temp_ip, 4); dhcps_params.options.router[0] = DHCP_ROUTER; dhcps_params.options.router[1] = 4; memcpy(&(dhcps_params.options.router[2]), (char *)&dhcps_params.gateway, 4); dhcps_params.options.dns[0] = DHCP_DNS_SERVER; dhcps_params.options.dns[1] = 4; memcpy(&(dhcps_params.options.dns[2]), (char *)&dhcps_params.dns_server[0], 4); dhcps_params.options.router4g[0] = DHCP_4G_ROUTER; dhcps_params.options.router4g[1] = DHCP_4G_ROUTER_LEN; memcpy(&(dhcps_params.options.router4g[2]), DHCP_4G_ROUTER_STR, DHCP_4G_ROUTER_LEN); if (-1 == dhcps_params.sock) { dhcps_params.sock = create_sock(); if (-1 == dhcps_params.sock) { DHCPS_DEBUG("create socket error"); return ERROR; } } if (-1 == dhcps_params.inet_iendx) { dhcps_params.inet_iendx = inet_add_socket(dhcps_params.sock, (void*)dhcps_handle, NULL, NULL); if (ERROR == dhcps_params.inet_iendx) { destroy_sock(dhcps_params.sock); dhcps_params.sock = -1; DHCPS_DEBUG("Listen socket error"); return ERROR; } } if (-1 == dhcps_params.timer_index) { dhcps_params.timer_index = inet_add_timer((void*)dhcps_check_timer, 0, 1, EXECUTE_FOREVER); if (ERROR == dhcps_params.timer_index) { inet_del_socket(dhcps_params.inet_iendx); dhcps_params.inet_iendx = -1; destroy_sock(dhcps_params.sock); dhcps_params.sock = -1; DHCPS_DEBUG("Add timer error"); return ERROR; } } DHCPS_INFO("Start DHCP server"); ipaddr.ipAddr = dhcps_params.server; DHCPS_DEBUG("Server = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); ipaddr.ipAddr = dhcps_params.netmask; DHCPS_DEBUG("Netmask = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); ipaddr.ipAddr = dhcps_params.dns_server[0]; DHCPS_DEBUG("DNS1 = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); ipaddr.ipAddr = dhcps_params.dns_server[1]; DHCPS_DEBUG("DNS2 = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); ipaddr.ipAddr = dhcps_params.start; DHCPS_DEBUG("Pool Start = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); ipaddr.ipAddr = dhcps_params.end; DHCPS_DEBUG("Pool End = %d.%d.%d.%d", ipaddr.ipAddrByteFormat[0], ipaddr.ipAddrByteFormat[1], ipaddr.ipAddrByteFormat[2], ipaddr.ipAddrByteFormat[3]); DHCPS_DEBUG("Lease Time = %d", dhcps_params.lease_time); return OK; } LOCAL S32 dhcps_stop_cb(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { if (-1 != dhcps_params.inet_iendx) { inet_del_socket(dhcps_params.inet_iendx); dhcps_params.inet_iendx = -1; } if (-1 != dhcps_params.sock) { destroy_sock(dhcps_params.sock); dhcps_params.sock = -1; } if (-1 != dhcps_params.timer_index) { inet_del_timer(dhcps_params.timer_index); dhcps_params.timer_index = -1; } return OK; } LOCAL int dhcps_init() { memset(&recv_dhcp_packet, 0, sizeof(recv_dhcp_packet)); memset(&dhcps_params, 0, sizeof(DHCPS_PARAMS)); dhcps_params.inet_iendx = -1; dhcps_params.timer_index = -1; dhcps_params.sock = -1; dhcps_params.decline_time = DECLINE_TIME; dhcps_params.conflict_time = CONFLICT_TIME; dhcps_params.offer_time = LEASE_OFFER_TIME; dhcps_params.min_lease = LEASE_TIME_MIN; msg_attach_handler(DHCPS_START_MSG, dhcps_start_cb); msg_attach_handler(DHCPS_STOP_MSG, dhcps_stop_cb); return OK; } LOCAL S32 dhcps_reload(DS_MSG *msg) { /* 4G上网模式变化 */ if (ds_path_id_exist(msg->id, msg->num, LTE_INFO_DATA_PATH)) { dhcps_params.is_lte = get_lte_enabled(); } return OK; } LOCAL void dhcps_main() { DS_DAT_MON_DESC dhcps_monitor[] = { DS_DAT_MON(LTE_INFO_DATA_PATH, DATA_ATTRI_NOTIFY), }; DS_MOD_DESC dhcps_module = DS_STRUCT_MOD("dhcps", dhcps_init, NULL, dhcps_reload, NULL, NULL, NULL, dhcps_monitor); MODULE *module_node = ds_register_module("dhcps", &dhcps_module); NSD_ASSERT(NULL != module_node); } NSD_INIT(dhcps_main);
最新发布
11-21
#include <netinet/if_ether.h> #include <linux/filter.h> #include <linux/if_packet.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <net/if.h> #include "options.h" #include "packet.h" #include "dhcp.h" #include "dhcpc.h" #include "nsd_common.h" #include "libdms.h" #include "libds.h" #define DHCPC_SOCKET_RECV_BUF_SIZE (32 * 1024) #define DHCPC_SOCKET_SEND_BUF_SIZE (32 * 1024) LOCAL S32 discovery_timeout[DISCOVERY_RETRY_TIMES] = {2, 2, 4, 2, 12, 2, 2, 4, 2, 20, 2, 2, 4, 2, 20, 2, 2, 4, 2, 2}; /* DISCOVERY超时时间。 */ LOCAL DHCPC_PARAMS dhcpc_params = {0}; LOCAL struct dhcp_packet packet = {0}; #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT #define DHCP_4G_ROUTER_STR "4g router" #define DHCPC_4G_IPC_DEV_NAME "usb0" #define DHCPC_WIRED_INTERNET_MODE 0 #define DHCPC_4G_INTERNET_MODE 1 LTE_CONFIG_INFO_DATA g_lte_config_data = {0}; S32 g_sock_idx = -1; S32 get_lte_config_data_flag = 0; /* 是否已经读取了lte_config_info_data的配置,0:未读取 ,1:已读取 */ #endif LOCAL S32 dhcpc_ip_reset() { DHCPC_MSG msg; memset(&msg, 0, sizeof(DHCPC_MSG)); msg.status = LINK_IP_RESET; msg.code = LINK_CODE_NORMAL; NSD_SEND(NSD_DHCPC_STATUS, (U8*)&msg, sizeof(DHCPC_MSG)); return OK; } LOCAL S32 dhcpc_flush_net(U32 status, U32 code) { DHCPC_MSG msg; PHY_STATUS phy_status = {0}; memset(&msg, 0, sizeof(DHCPC_MSG)); /* Stopped by caller, no need to send message. */ if (-1 == dhcpc_params.call_bk_id) { return OK; } msg.call_bk_id = dhcpc_params.call_bk_id; msg.ctrl = 0; //memcpy(msg.dev_name, dhcpc_params[iface].dev_name, DEV_NAME_LEN); msg.status = status; msg.code = code; msg.ip = dhcpc_params.yiaddr; msg.mask = dhcpc_params.mask; msg.gateway = dhcpc_params.gateway; msg.mtu = dhcpc_params.mtu; /*msg.proto = PROTO_DHCP;*/ if (FALSE == dhcpc_params.manual_dns) { msg.dns[0] = dhcpc_params.dns[0]; msg.dns[1] = dhcpc_params.dns[1]; } memcpy(msg.mac, dhcpc_params.server_mac, MAC_ADDR_SIZE); ds_read(PHY_STATUS_PATH, &phy_status, sizeof(PHY_STATUS)); if (phy_status.diag_wlan == 1) { DHCPC_DEBUG("DHCP success,clean tag"); phy_status.diag_wlan = 0; ds_write(PHY_STATUS_PATH, (U8 *)&phy_status, sizeof(PHY_STATUS)); } NSD_SEND(NSD_DHCPC_STATUS, (U8*)&msg, sizeof(DHCPC_MSG)); return OK; } LOCAL void dhcpc_timeout_flush_net() { PHY_STATUS phy_status = {0}; EXCEPTION_STATUS_MSG msg = {0}; ds_read(PHY_STATUS_PATH, &phy_status, sizeof(PHY_STATUS)); if (phy_status.diag_wlan == 1) { DHCPC_DEBUG("record wrong code"); msg.type = WLAN_GATEWAY_UNREACHABLE; msg.status = 1; msg_send(EXCEPTION_STATUS_MID, (U8 *)&msg, sizeof(msg)); phy_status.diag_wlan = 0; ds_write(PHY_STATUS_PATH, (U8 *)&phy_status, sizeof(PHY_STATUS)); } if (dhcpc_params.dhcp_timeout == 1) { dhcpc_flush_net(LINK_UP, LINK_CODE_DHCP_TIMEOUT); dhcpc_params.dhcp_timeout = 0; } return; } /* Multi-wans support: add parameter S32 i for all function. By xcl, 2011-05-04.*/ /* initialize a packet with the proper defaults */ LOCAL void init_packet(char type) { struct vendor { char vendor, length; char str[sizeof("MSFT 5.0")]; } vendor_id = { DHCP_VENDOR, sizeof("MSFT 5.0") - 1, "MSFT 5.0"}; /* Changed by lsz 080424, cheat server:"I am Windows XP" */ /* vendor_id = { DHCP_VENDOR, sizeof("udhcp "VERSION) - 1, "udhcp "VERSION};*/ init_header(&packet, type); /* message type */ memcpy(packet.chaddr, dhcpc_params.mac, 6); /* moved by tiger 20090304, from send_discover, flags should be setting for all packet in that mode */ /* Modified by Li Shaozhang, 070707 */ /* Multi-wans support.*/ if (dhcpc_params.flags/*get_runtime_dhcp_flags()*/) /* server reply mode choose */ packet.flags &= htons(0x7FFF); /* set first bit to 0, just AND 0111 1111 1111 1111 */ else /* server reply in broadcast mode */ packet.flags |= htons(0x8000); /* set first bit to 1, just OR 1000 0000 0000 0000 */ /* Edited by xcl, 13Feb12. * According to rfc2131, release packet must include options 53、54 and may 61, must not others. * decline packet is most the same but must include options 50. */ if (DHCPRELEASE != type && DHCPDECLINE != type) { /* 080501, add maximum size option --- lsz */ /* Explicitly saying that we want RFC-compliant packets helps * some buggy DHCP servers to NOT send bigger packets */ add_simple_option(packet.options, DHCP_MAX_SIZE, htons(DHCP_MAX_MSG_SIZE)); } if (dhcpc_params.client[OPT_DATA]) add_option_string(packet.options, (uint8_t *)dhcpc_params.client);/* client id */ /* Edited by xcl, 13Feb12. * According to rfc2131, release and decline packet must not include option 12. */ if (DHCPRELEASE != type && DHCPDECLINE != type && dhcpc_params.name[OPT_DATA]) add_option_string(packet.options, (uint8_t *)dhcpc_params.name);/* hostname */ /* Edited by xcl, 13Feb12. * According to rfc2131, release and decline packet must not include option 60. */ if (DHCPRELEASE != type && DHCPDECLINE != type) add_option_string(packet.options, (uint8_t *) &vendor_id); /* vendor id */ } /* Add a parameter request list for stubborn DHCP servers. Pull the data * from the struct in options.c. Don't do bounds checking here because it * goes towards the head of the packet. */ LOCAL void add_requests() { S32 end = end_option(packet.options); S32 i, len = 0; packet.options[end + OPT_CODE] = DHCP_PARAM_REQ; for (i = 0; dhcp_options[i].code; i++) if (dhcp_options[i].flags & OPTION_REQ) packet.options[end + OPT_DATA + len++] = dhcp_options[i].code; packet.options[end + OPT_LEN] = len; packet.options[end + OPT_DATA + len] = DHCP_END; } /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ LOCAL S32 send_discover() { init_packet(DHCPDISCOVER); packet.xid = dhcpc_params.xid; /* 080424, del by lsz, cauz some server may ignore our request with an requested ip */ #if 0 if (requested) add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); #endif add_requests(&packet); return make_and_send_dhcp_frame(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, dhcpc_params.dev); } /* Broadcasts a DHCP request message */ LOCAL S32 send_selecting(U32 server, U32 requested) { init_packet(DHCPREQUEST); packet.xid = dhcpc_params.xid; add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); add_simple_option(packet.options, DHCP_SERVER_ID, server); add_requests(&packet); return make_and_send_dhcp_frame(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, dhcpc_params.dev); } /* Unicasts or broadcasts a DHCP renew message */ LOCAL S32 send_renew(U32 server, U32 ciaddr) { init_packet(DHCPREQUEST); packet.xid = dhcpc_params.xid; packet.ciaddr = ciaddr; add_requests(&packet); /* 指定了server的,就单播发送 */ if (server) { return send_dhcp_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); } return make_and_send_dhcp_frame(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, dhcpc_params.dev); } #if 0 /* Unicasts a DHCP release message */ LOCAL S32 send_release(U32 server, U32 ciaddr) { init_packet(DHCPRELEASE); packet.xid = random(); /* 使用新ID */ packet.ciaddr = ciaddr; /* Del by xcl, 13Feb12. According to rfc2131, release packet must not include option 50 */ /*add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr);*/ add_simple_option(packet.options, DHCP_SERVER_ID, server); return send_dhcp_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); } #endif /* send broadcast when GARP checking failed added by tiger 20090825 */ LOCAL S32 send_decline(U32 server, U32 requested) { init_packet(DHCPDECLINE); packet.xid = dhcpc_params.xid; add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); add_simple_option(packet.options, DHCP_SERVER_ID, server); return make_and_send_dhcp_frame(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, dhcpc_params.dev); } LOCAL void dhcpc_params_update() { DHCPC dhcpc_data; memset(&dhcpc_data, 0, sizeof(DHCPC)); if (0 > read_interface_info(dhcpc_params.dev_name, &dhcpc_params.dev, dhcpc_params.mac)) { DHCPC_ERROR("read dev_name:%s failed", dhcpc_params.dev_name); return; } dhcpc_params.code = LINK_CODE_NORMAL; if (NULL != dhcpc_params.path) { ds_read(dhcpc_params.path, (U8*)&dhcpc_data, sizeof(DHCPC)); dhcpc_params.mtu = dhcpc_data.mtu; dhcpc_params.flags = !dhcpc_data.enable_broadcast; dhcpc_params.manual_dns = (dhcpc_data.dns_mode == DNS_MODE_MANUAL); /*TODO: 目前只考虑为非手动获取dns的情况 */ #if 0 dhcpc_params[iface].dns[0] = dhcpc_params[iface].manual_dns ? dhcpc_data.dns[0] : 0; dhcpc_params[iface].dns[1] = dhcpc_params[iface].manual_dns ? dhcpc_data.dns[1] : 0; #endif dhcpc_params.name[OPT_CODE] = DHCP_HOST_NAME; dhcpc_params.name[OPT_LEN] = strlen(dhcpc_data.hostname); strncpy(&(dhcpc_params.name[OPT_DATA]), dhcpc_data.hostname, MAX_HOST_NAME_LEN); dhcpc_params.name[dhcpc_params.name[OPT_LEN] + 2] = '\0'; } dhcpc_params.client[OPT_CODE] = DHCP_CLIENT_ID; dhcpc_params.client[OPT_LEN] = 7; dhcpc_params.client[OPT_DATA] = 1; memcpy(&(dhcpc_params.client[OPT_DATA + 1]), dhcpc_params.mac, MAC_ADDR_SIZE); dhcpc_params.client[dhcpc_params.client[OPT_LEN] + 2] = '\0'; } /* start dial */ LOCAL S32 link_up_inner() { U64 cur_time = NSD_TIMESTAMP(); LINK_STATUS link_status = {0}; #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT LTE_CONFIG_INFO_DATA lte_config = {0}; if(0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("Read lte config data failed"); return ERROR; } if(lte_config.internet_wired_enable == 0) { LTE_DHCP_IP dhcp_ip = {0}; if (0 == ds_read(LTE_DHCP_IP_PATH, &dhcp_ip, sizeof(LTE_DHCP_IP))) { DHCPC_ERROR("Read lte dhcp ip failed"); return ERROR; } /* 4G_IPC: 用当前生效的ip去尝试续约 */ if (dhcp_ip.ipaddr != 0) { dhcpc_params.yiaddr = dhcp_ip.ipaddr; if(dhcpc_params.server != 0) { dhcpc_params.state = RECONNECT_RENEWING; DHCPC_DEBUG("Use ip %x server %x to renewing.", dhcpc_params.yiaddr, dhcpc_params.server); } else { dhcpc_params.state = RECONNECT_REBINDING; DHCPC_DEBUG("Use ip %x to rebinding.", dhcpc_params.yiaddr); } } else { DHCPC_DEBUG("No old ip, try discovery."); dhcpc_params.state = DISCOVERY; } }else { if (0 == ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS))) { return ERROR; } /* 用当前生效的ip去尝试续约 */ if (link_status.ipaddr != 0) { dhcpc_params.yiaddr = link_status.ipaddr; if (dhcpc_params.server != 0) { dhcpc_params.state = RECONNECT_RENEWING; DHCPC_DEBUG("Use ip %x server %x to renewing.", dhcpc_params.yiaddr, dhcpc_params.server); } else { dhcpc_params.state = RECONNECT_REBINDING; DHCPC_DEBUG("Use ip %x to rebinding.", dhcpc_params.yiaddr); } } else { DHCPC_DEBUG("No old ip, try discovery."); dhcpc_params.state = DISCOVERY; } } #else if (0 == ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS))) { return ERROR; } /* 用当前生效的ip去尝试续约 */ if (link_status.ipaddr != 0) { dhcpc_params.yiaddr = link_status.ipaddr; if (dhcpc_params.server != 0) { dhcpc_params.state = RECONNECT_RENEWING; DHCPC_DEBUG("Use ip %x server %x to renewing.", dhcpc_params.yiaddr, dhcpc_params.server); } else { dhcpc_params.state = RECONNECT_REBINDING; DHCPC_DEBUG("Use ip %x to rebinding.", dhcpc_params.yiaddr); } } else { DHCPC_DEBUG("No old ip, try discovery."); dhcpc_params.state = DISCOVERY; } #endif if (DISCOVERY == dhcpc_params.state || RECONNECT_RENEWING == dhcpc_params.state) { DHCPC_DEBUG("dhcpc_ip_reset"); dhcpc_ip_reset(); } switch (dhcpc_params.state) { case DISCOVERY: dhcpc_params_update(); dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.timeout = 0; /* 最迟1s以后,DHCPC进程自动发送DISCOVERY包。 */ break; case RECONNECT_REBINDING: dhcpc_params.timeout = 0; dhcpc_params.t2 = 60; dhcpc_params.start = cur_time - dhcpc_params.t2; dhcpc_params.lease = 120; break; case RECONNECT_RENEWING: dhcpc_params.timeout = 0; dhcpc_params.start = cur_time; dhcpc_params.lease = 120; dhcpc_params.t2 = 60; dhcpc_params.t1 = 0; break; } dhcpc_params.dhcp_timeout = 1; /* 重连才触发dhcp timeout*/ #if 0 /* 如果当前正处在释放IP状态。 */ if ((RELEASED == dhcpc_params.state) || (IFDOWN == dhcpc_params.state)) { dhcpc_params.re_dial = TRUE; /* IP地址释放完毕之后会自动重拨。 */ return 0; } /* 如果已经拨上号了,断线重连。 */ if ((BOUND == dhcpc_params.state) || (RENEWING == dhcpc_params.state) || (REBINDING == dhcpc_params.state)) { /* 断开DHCPC-LAN的连接时,不要释放租约,对外表现与SLP平台保持一致,详解见linkDownInner。 */ if (dhcpc_params.send_release) { DHCPC_DEBUG("Send RELEASE to server %.8x", ntohl(dhcpc_params.server)); send_release(dhcpc_params.server, dhcpc_params.yiaddr); /* unicast */ } dhcpc_params.timeout = 0; /* 确保release包发出之后再释放接口IP */ dhcpc_params.state = IFDOWN; dhcpc_params.re_dial = TRUE; /* IP地址释放完毕之后会自动重拨。 */ #endif return OK; } /* stop dial */ LOCAL S32 link_down_inner(U32 code) { /* 智能ip策略,不需要发送release包,直接停止状态机即可 */ if (INIT != dhcpc_params.state) { /* 保留已经获取的ip */ /*dhcpc_params.yiaddr = 0;*/ dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.timeout = 0xFFFFFFFF; dhcpc_params.state = INIT; memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); } dhcpc_flush_net(LINK_DOWN, code); #if 0 /* 如果已经拨上号了,需要发送release包。 */ if ((BOUND == dhcpc_params.state) || (RENEWING == dhcpc_params.state) || (REBINDING == dhcpc_params.state)) { /* 修复Bug 185658 & 185215,由于桥接到rootAP使用的MAC与DHCPC-LAN使用的LAN MAC不同,因此重桥会出 * 现以下问题: * 如果发送DHCP RELEASE释放了原来的租约,那么重桥重新获取IP时,rootAP的DHCPS可能会发ARP Request * 来探测原来分配的IP是否被使用,因为此时LAN口已配置了该IP,因此会给rootAP ARP Reply,告知该IP对 * 应的是LAN MAC。 * 但在rootAP端来看,ARP reply的MAC与DHCPC DISCOVER里携带MAC不同,因此DHCPS会误判成IP已被另一个设 * 备使用,从而又分配了另一个可用的IP,导致重桥后的LAN IP改变。 * SLP平台机型在重桥时因为没有发DHCP RELEASE释放租约,因此在租约有效期间重桥能够保持LAN IP不变。 * 当租约被老化清理掉,重桥同样会导致LAN IP改变。 * 要完全修复此bug需要无线驱动与DHCPC-LAN互相配合着修改,现在先部分修复,断开DHCPC-LAN的连接时, * 不要发DHCP RELEASE释放租约,令SDMP平台的对外表现与SLP平台一致。 */ if (dhcpc_params.send_release) { /* 实际上release包不一定能马上发出了,因为有可能发DHCP release时,ARP * 已经老化,于是还要先等ARP查询结果,所以1s后再释放接口IP比较稳妥。 */ DHCPC_DEBUG("Send RELEASE to server %.8x", ntohl(dhcpc_params.server)); send_release(dhcpc_params.server, dhcpc_params.yiaddr); /* unicast */ } dhcpc_params.timeout = 0; /* 确保release包发出之后再释放接口IP */ dhcpc_params.state = IFDOWN; return 0; } /* 如果正在断开,保持当前的状态机即可。 */ if ((RELEASED == dhcpc_params.state) || (IFDOWN == dhcpc_params.state)) { return 0; } /* 如果正在拨号,停止状态机即可。 */ if (INIT != dhcpc_params.state) { dhcpc_params.yiaddr = 0; dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.timeout = 0xFFFFFFFF; dhcpc_params.state = INIT; memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); dhcpc_flush_net(LINK_DOWN, LINK_CODE_MANUAL); } #endif return 0; } LOCAL void dhcpc_check_timer() { U64 cur_time = NSD_TIMESTAMP(); IP_ADDR ip_addr = {0}; /* DHCPC_DEBUG("DHCP state is %d", dhcpc_params.state); */ if (cur_time < dhcpc_params.timeout) /* 暂不考虑溢出问题。 */ { return; } switch (dhcpc_params.state) { case INIT: /* just do nothing */ break; /* 和发REQUEST包行为统一,第一个包要在收包前一个状态发,避免还未发DISCOVER包,就开始收包。 */ case DISCOVERY: DHCPC_DEBUG("Send DISCOVER with unicast flag %d", dhcpc_params.flags); dhcpc_params.xid = random(); /* 每次重新拨号,每次续约时才更换xid,若没有得到响应,可以不更换xid。 */ send_discover(); dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(discovery_timeout[0]); dhcpc_params.packet++; dhcpc_params.state = SELECTING; break; case SELECTING: if (dhcpc_params.packet >= DISCOVERY_RETRY_TIMES) { /* DHCPC fail, start in 2s again. */ DHCPC_DEBUG("Dhcpc failed, retry count = %d", dhcpc_params.packet); dhcpc_params.timeout = cur_time + 2; dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.state = DISCOVERY; break; } /* change runtime dhcp flags when exceed DISCOVER_INVERT_TIMES added by tiger 20090819 apply 11G and XP's option */ /* 修复Bug 40838:切换单/广播时需同步加/卸载filter(20130924) */ /* 在PNE2.2平台里,每5个包为一组,每组里第三个包开始切换 */ if ((dhcpc_params.support_un_cast) && (DISCOVERY_INVERT_TIMES == (dhcpc_params.packet % DISCOVERY_GROUP_TIMES))) { dhcpc_params.flags = !dhcpc_params.flags; } DHCPC_DEBUG("Send DISCOVER with unicast flag %d", dhcpc_params.flags); dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(discovery_timeout[dhcpc_params.packet]); send_discover(); dhcpc_params.packet++; if (DISCOVERY_RETRY_TIMEOUT == dhcpc_params.packet) { dhcpc_timeout_flush_net(); } break; case REQUESTING: if (dhcpc_params.packet > REQUESTING_RETRY_TIMES) /* 当尝试超过一定次数,重新发DISCOVERY。*/ { DHCPC_DEBUG("Recv no ACK, restart"); dhcpc_params.timeout = 0; dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.state = DISCOVERY; break; } ip_addr.ipAddr = dhcpc_params.server; DHCPC_DEBUG("Send REQUEST to server %d.%d.%d.%d", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); send_selecting(dhcpc_params.server, dhcpc_params.yiaddr); /* broadcast */ dhcpc_params.timeout = /*time(0) + ((cur_client->packet_num == 2) ? 10 : 2)*/cur_time + NSD_SECTOUSEC(REQUESTING_TIMEOUT); dhcpc_params.packet++; break; case BOUND: case RENEWING: /* Either set a new T1, or enter REBINDING state */ if ((dhcpc_params.t2 - dhcpc_params.t1) <= (dhcpc_params.lease / 14400 + 1)) { /* timed out, enter rebinding state */ dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(dhcpc_params.t2 - dhcpc_params.t1); dhcpc_params.state = REBINDING; /* 智能ip:renewing失败,视为以前的server失效了,重新在REBINDING状态收到包时会更新server */ dhcpc_params.server = 0; DHCPC_DEBUG("Entering rebinding state"); break; } /* send a request packet */ DHCPC_DEBUG("Send REQUEST to server %.8x", dhcpc_params.server); send_renew(dhcpc_params.server, dhcpc_params.yiaddr); /* unicast */ dhcpc_params.t1 = (dhcpc_params.t2 - dhcpc_params.t1) / 2 + dhcpc_params.t1; dhcpc_params.timeout = NSD_SECTOUSEC(dhcpc_params.t1) + dhcpc_params.start; dhcpc_params.state = RENEWING; break; case REBINDING: /* Either set a new T2, or enter INIT state */ if ((dhcpc_params.lease - dhcpc_params.t2) <= (dhcpc_params.lease / 14400 + 1)) { //dhcpc_flush_net(LINK_DOWN, LINK_CODE_NOECHO); DHCPC_DEBUG("Lease lost, entering DISCOVERY state"); /* timed out, enter init state */ dhcpc_params.timeout = cur_time; dhcpc_params.packet = 0; dhcpc_params.state = DISCOVERY; dhcpc_timeout_flush_net(); /* 智能ip:rebinding失败,视为之前的ip失效了 */ dhcpc_params.yiaddr = 0; break; } ip_addr.ipAddr = dhcpc_params.yiaddr; DHCPC_DEBUG("broadcast REQUEST with request ip %d.%d.%d.%d", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); send_renew(0, dhcpc_params.yiaddr); /* broadcast */ dhcpc_params.t2 = (dhcpc_params.lease - dhcpc_params.t2) / 2 + dhcpc_params.t2; dhcpc_params.timeout = NSD_SECTOUSEC(dhcpc_params.t2) + dhcpc_params.start; dhcpc_params.packet++; break; case RECONNECT_RENEWING: /* 每秒发一次包,等待 RECONNECT_RENEWING_TIMES 秒 */ if (dhcpc_params.packet > RECONNECT_RENEWING_TIMES) { /* timed out, enter rebinding state */ dhcpc_params.timeout = cur_time; dhcpc_params.state = RECONNECT_REBINDING; dhcpc_params.packet = 0; /* 智能ip:renewing失败,视为以前的server失效了,重新在REBINDING状态收到包时会更新server */ dhcpc_params.server = 0; DHCPC_DEBUG("[RECONNECT]Entering reconect_rebinding state"); break; } /* send a request packet */ DHCPC_DEBUG("[RECONNECT]Send REQUEST to server %.8x", dhcpc_params.server); send_renew(dhcpc_params.server, dhcpc_params.yiaddr); /* unicast */ dhcpc_params.packet++; dhcpc_params.timeout = 0; break; case RECONNECT_REBINDING: /* 每秒发一次包,等待 RECONNECT_REBINDING_TIMES 秒 */ if (dhcpc_params.packet > RECONNECT_REBINDING_TIMES) { /* timed out, enter init state */ dhcpc_params.timeout = cur_time; dhcpc_params.packet = 0; dhcpc_params.state = DISCOVERY; /* 智能ip:rebinding失败,视为之前的ip失效了 */ dhcpc_params.yiaddr = 0; DHCPC_DEBUG("[RECONNECT]Reconnect fail, Entering discovery state"); break; } /* send a request packet */ ip_addr.ipAddr = dhcpc_params.yiaddr; DHCPC_DEBUG("broadcast REQUEST with request ip %d.%d.%d.%d", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); send_renew(0, dhcpc_params.yiaddr); /* broadcast */ dhcpc_params.timeout = cur_time; dhcpc_params.packet++; break; #if 0 case RELEASED: /* 实际上release包不一定能马上发出了,因为有可能发DHCP release时,ARP * 已经老化,于是还要先等ARP查询结果,所以1s后再释放接口IP比较稳妥。 */ ip_addr.ipAddr = dhcpc_params.server; DHCPC_DEBUG("Send RELEASE to server %d.%d.%d.%d", ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); send_release(dhcpc_params.server, dhcpc_params.yiaddr); /* unicast */ dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(1); /* 确保release包发出之后再释放接口IP */ dhcpc_params.state = IFDOWN; break; case IFDOWN: dhcpc_flush_net(LINK_DOWN, LINK_CODE_MANUAL); /* 注释掉,保存上次获取的ip */ //dhcpc_params.yiaddr = 0; dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.timeout = 0xFFFFFFFF; dhcpc_params.state = INIT; if (-1 != dhcpc_params.call_bk_id_new) { dhcpc_params.call_bk_id = dhcpc_params.call_bk_id_new; dhcpc_params.call_bk_id_new = -1; } memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); if (TRUE == dhcpc_params.re_dial) { dhcpc_params.re_dial = FALSE; dhcpc_params_update(); dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.timeout = 0; /* 最迟1s以后,DHCPC进程自动发送DISCOVERY包。 */ dhcpc_params.state = DISCOVERY; } break; #endif } } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT LOCAL void write_mobile_access(U8 val) { DEVICE_BASIC_INFO info = {0}; if (0 == ds_read(DEVICE_BASIC_INFO_PATH, &info, sizeof(info))) { DHCPC_ERROR("ds read device basic_info failed"); return; } else { info.mobile_access = val; ds_write(DEVICE_BASIC_INFO_PATH, &info, sizeof(info)); } } #endif LOCAL void dhcpc_handle(S32 sock) { S32 bytes = 0; U8 *message = NULL, *option = NULL; U64 cur_time = NSD_TIMESTAMP(); IP_ADDR ip_addr = {0}, mask = {0}, gateway = {0}, server = {0}; U32 dns[2] = {0}; #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT LTE_CONFIG_INFO_DATA lte_config = {0}; if(0 == ds_read(LTE_INFO_DATA_PATH, (U8*)&lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("Read lte config error"); return; } #endif /* 收到DHCP服务器的响应报文。 */ bytes = get_packet(&packet, sock); if (bytes < 0) { DHCPC_WARNING("Error on read, %m, reopening socket"); return; } /* Ignore packets that aren't for us */ if (memcmp(packet.chaddr, dhcpc_params.mac, sizeof(dhcpc_params.mac))) { DHCPC_DEBUG("Packet does not have our chaddr -- ignoring"); return; } if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { DHCPC_WARNING("Couldnt get option from packet -- ignoring"); return; } if (packet.xid != dhcpc_params.xid) { DHCPC_WARNING("ignoring XID %lx (our xid is %lx)", packet.xid, dhcpc_params.xid); return; } switch (dhcpc_params.state) { case INIT: case DISCOVERY: /* just drop all message. */ break; case SELECTING: if ((DHCPOFFER != *message) || /* 在此处只能接收OFFER包,其它包丢弃 */ (NULL == (option = get_option(&packet, DHCP_SERVER_ID)))) /* 必须带有SERVER_ID。 */ { break; } memcpy(&dhcpc_params.server, option, 4); dhcpc_params.mask = inet_addr("255.255.255.255"); switch (ip_network_id(packet.yiaddr)) { case 'A': dhcpc_params.mask = inet_addr("255.0.0.0"); break; case 'B': dhcpc_params.mask = inet_addr("255.255.0.0"); break; case 'C': dhcpc_params.mask = inet_addr("255.255.255.0"); break; } if (NULL != (option = get_option(&packet, DHCP_SUBNET))) { memcpy(&dhcpc_params.mask, option, 4); } /*dhcpc_params[iface].xid = packet.xid;*/ /* 忽略? */ dhcpc_params.yiaddr = packet.yiaddr; ip_addr.ipAddr = dhcpc_params.yiaddr; server.ipAddr = dhcpc_params.server; DHCPC_DEBUG("Recv OFFER from server %d.%d.%d.%d with ip %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3], ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); /* 在此处验证获得的IP的合法性。这里DHCP不回MTU */ if ((OK != check_valid_param(dhcpc_params.mtu, dhcpc_params.yiaddr, dhcpc_params.mask, 0))) { DHCPC_DEBUG("check_valid_param failed."); break; /* 继续等待其它的服务器响应 */ } /* 合法性验证通过后,发送Request报文,跳转到REQUESTING状态。 */ ip_addr.ipAddr = dhcpc_params.yiaddr; server.ipAddr = dhcpc_params.server; DHCPC_DEBUG("Send REQUEST to server %d.%d.%d.%d with request ip %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3], ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); send_selecting(dhcpc_params.server, dhcpc_params.yiaddr); /* broadcast */ dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(REQUESTING_TIMEOUT); dhcpc_params.state = REQUESTING; dhcpc_params.packet = 0; dhcpc_params.retry = 0; break; case RENEWING: case REBINDING: case REQUESTING: case RECONNECT_RENEWING: case RECONNECT_REBINDING: /* 是否要验证server id?这里暂且验证下,个人认为这样安全。 */ if (NULL == (option = get_option(&packet, DHCP_SERVER_ID))) { break; /* unknown dhcp server? */ } /* REBINDING阶段更新server */ if (dhcpc_params.state == REBINDING || dhcpc_params.state == RECONNECT_REBINDING) { memcpy(&dhcpc_params.server, option, 4); } /* REBINDING阶段可能会切换server,此时不可检查 */ #if 0 if (dhcpc_params[iface].server != *(U32 *)option) { break; /* invalid dhcp server? */ } #endif if (DHCPACK == *message) { dhcpc_params.lease = 60*60; /* 默认1小时。 */ if (NULL != (option = get_option(&packet, DHCP_LEASE_TIME))) { memcpy(&dhcpc_params.lease, option, 4); dhcpc_params.lease = ntohl(dhcpc_params.lease); } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT if(lte_config.internet_wired_enable == 0) { IF_CONF if_conf = {0}; if (0 == ds_read(IF_CONF_PATH, &if_conf, sizeof(IF_CONF))) { DHCPC_ERROR("Read wan config error"); return; } /* 无论是否为bridge ifname都存放我们需要的值 */ if (0 == if_conf.ifname[0]) { DHCPC_ERROR("Get ifname failed."); return; } char dev_name[32] = {0}; U8 dev_mac[6] = {0}; snprintf(dev_name, sizeof(dev_name), "%s", if_conf.ifname); if (0 > read_interface_info(dev_name, NULL, dev_mac)) { DHCPC_ERROR("read usb0 device info error"); return; } /* 发送GARP验证IP是否被占用。 */ if (((packet.yiaddr != dhcpc_params.yiaddr) || (REQUESTING == dhcpc_params.state)) && ((0 == arpping(packet.yiaddr, NULL, (uint32_t)0, dhcpc_params.mac, dhcpc_params.dev_name, 300)) || (0 == arpping(packet.yiaddr, NULL, (uint32_t)0, dev_mac, dev_name, 300)))) { server.ipAddr = dhcpc_params.server; DHCPC_WARNING("Offered address is in use, send DECLINE to server %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3]); send_decline(dhcpc_params.server, packet.yiaddr); dhcpc_params.yiaddr = 0; dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(10); /* 推迟一段时间再重新申请。 */ dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.state = DISCOVERY; dhcpc_timeout_flush_net(); memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); break; } }else #endif { /* 发送GARP验证IP是否被占用。 */ if (((packet.yiaddr != dhcpc_params.yiaddr) || (REQUESTING == dhcpc_params.state)) && (0 == arpping(packet.yiaddr, NULL, (uint32_t)0, dhcpc_params.mac, dhcpc_params.dev_name, 300))) { server.ipAddr = dhcpc_params.server; DHCPC_WARNING("Offered address is in use, send DECLINE to server %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3]); send_decline(dhcpc_params.server, packet.yiaddr); dhcpc_params.yiaddr = 0; dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(10); /* 推迟一段时间再重新申请。 */ dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.state = DISCOVERY; dhcpc_timeout_flush_net(); memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); break; } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT /* 在有线上网模式下,dhcp server分配的IP不能为4G网关192.168.43.1 */ if(((packet.yiaddr != dhcpc_params.yiaddr) || (REQUESTING == dhcpc_params.state)) && packet.yiaddr == 0x012ba8c0) { server.ipAddr = dhcpc_params.server; DHCPC_WARNING("Offered address is in Gateway for 4G, send DECLINE to server %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3]); send_decline(dhcpc_params.server, packet.yiaddr); dhcpc_params.yiaddr = 0; dhcpc_params.timeout = cur_time + NSD_SECTOUSEC(10); /* 推迟一段时间再重新申请。 */ dhcpc_params.packet = 0; dhcpc_params.retry = 0; dhcpc_params.state = DISCOVERY; dhcpc_timeout_flush_net(); memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); break; } #endif } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT if (NULL != (option = get_option(&packet, DHCP_4G_ROUTER))) { if(0 == memcmp(option, DHCP_4G_ROUTER_STR, strlen(DHCP_4G_ROUTER_STR))) { DHCPC_INFO("get option DHCP_4G_ROUTER"); write_mobile_access(1); } else { write_mobile_access(0); } } else { write_mobile_access(0); } #endif /* 分配的IP没有被占用,则使用该IP,并且进入bound状态。 */ dhcpc_params.t1 = dhcpc_params.lease/2; dhcpc_params.t2 = ((dhcpc_params.lease * 0x7) >> 3);/* little fixed point for n * .875 */ dhcpc_params.start = cur_time; dhcpc_params.timeout = NSD_SECTOUSEC(dhcpc_params.t1) + cur_time; ip_addr.ipAddr = dhcpc_params.yiaddr; /* 保留原IP的值 */ dhcpc_params.yiaddr = packet.yiaddr; /* 获取网关。 */ gateway.ipAddr = dhcpc_params.gateway; dhcpc_params.gateway = 0; if (NULL != (option = get_option(&packet, DHCP_ROUTER))) { if(0 != *option) { memcpy(&dhcpc_params.gateway, option, 4); } else if(0 != dhcpc_params.server) { dhcpc_params.gateway = dhcpc_params.server; DHCPC_ERROR("Received ACK but gateway option is zero, making the dhcpc_params.gateway [%.8x] equal to the dhcpc_params.server [%.8x]", dhcpc_params.gateway, dhcpc_params.server); } else { #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT if(lte_config.internet_wired_enable == 0) { dhcpc_params.gateway = 0x012ba8c0; /* 4G上网模式下,无法从dhcp服务器获取网关信息的情况下将网关设置为192.168.43.1 */ DHCPC_ERROR("Received ACK but gateway and source IP are zero, making the dhcpc_params.gateway [%.8x] equal to 192.168.43.1", dhcpc_params.gateway); }else #endif { dhcpc_params.gateway = 0x0100a8c0; /* 无法从dhcp服务器获取网关信息的情况下将网关设置为192.168.0.1 */ DHCPC_ERROR("Received ACK but gateway and source IP are zero, making the dhcpc_params.gateway [%.8x] equal to 192.168.0.1", dhcpc_params.gateway); } } } else { if(0 != dhcpc_params.server) { dhcpc_params.gateway = dhcpc_params.server; DHCPC_ERROR("Received ACK but gateway option is empty, making the dhcpc_params.gateway [%.8x] equal to the dhcpc_params.server [%.8x]", dhcpc_params.gateway, dhcpc_params.server); } else { dhcpc_params.gateway = 0x0100a8c0; DHCPC_ERROR("Received ACK but the gateway and source IP are illegal, making the dhcpc_params.gateway [%.8x] equal to 192.168.0.1", dhcpc_params.gateway); } } /* 获取掩码。 */ mask.ipAddr = dhcpc_params.mask; dhcpc_params.mask = inet_addr("255.255.255.255"); switch (ip_network_id(packet.yiaddr)) { case 'A': dhcpc_params.mask = inet_addr("255.0.0.0"); break; case 'B': dhcpc_params.mask = inet_addr("255.255.0.0"); break; case 'C': dhcpc_params.mask = inet_addr("255.255.255.0"); break; } if (NULL != (option = get_option(&packet, DHCP_SUBNET))) { memcpy(&dhcpc_params.mask, option, 4); } /* 获取DNS. */ if (FALSE == dhcpc_params.manual_dns) { dns[0] = dhcpc_params.dns[0]; dns[1] = dhcpc_params.dns[1]; dhcpc_params.dns[0] = 0; dhcpc_params.dns[1] = 0; if (NULL != (option = get_option(&packet, DHCP_DNS_SERVER))) { S32 dnsNum = 0; S32 i = 0; dnsNum = (*(option - 1))/4; dnsNum = dnsNum > 2 ? 2 : dnsNum; for (i = 0; i < dnsNum; i++) { memcpy(dhcpc_params.dns + i, option + 4 * i, 4); } } } /* REQUESTING状态或者ip、gateway、mask有更新则刷新接口。 */ /* RECONNECT_RENEWING 和 RECONNECT_REBINDING状态可能是静态转为动态,因此也要进行设置 */ if ((REQUESTING == dhcpc_params.state) || dhcpc_params.state == RECONNECT_RENEWING || dhcpc_params.state == RECONNECT_REBINDING || (ip_addr.ipAddr != dhcpc_params.yiaddr) || (gateway.ipAddr != dhcpc_params.gateway) || (mask.ipAddr != dhcpc_params.mask)) { /* 根据获得的IP配置本地接口。 */ ip_addr.ipAddr = dhcpc_params.yiaddr; mask.ipAddr = dhcpc_params.mask; gateway.ipAddr = dhcpc_params.gateway; DHCPC_INFO("%s set ip %d.%d.%d.%d mask %d.%d.%d.%d gateway %d.%d.%d.%d lease time %ld", dhcpc_params.dev_name, ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3], mask.ipAddrByteFormat[0], mask.ipAddrByteFormat[1], mask.ipAddrByteFormat[2], mask.ipAddrByteFormat[3], gateway.ipAddrByteFormat[0], gateway.ipAddrByteFormat[1], gateway.ipAddrByteFormat[2], gateway.ipAddrByteFormat[3], dhcpc_params.lease); dhcpc_flush_net(LINK_UP, LINK_CODE_NORMAL); } else if ((TRUE != dhcpc_params.manual_dns) && ((dns[0] != dhcpc_params.dns[0]) || (dns[1] != dhcpc_params.dns[1]))) { dhcpc_flush_net(LINK_UP, LINK_CODE_NORMAL); } DHCPC_DEBUG("Recv ACK from server %.8x with ip %.8x lease time %ld", dhcpc_params.server, dhcpc_params.yiaddr, dhcpc_params.lease); dhcpc_params.retry = 0; /* clear the retry counter */ dhcpc_params.packet = 0; dhcpc_params.state = BOUND; break; } if (DHCPNAK != *message) { break; } /* 这里需要考虑两种情况: */ /* 在未配置本地IP的情况(即REQUESTING状态),只需更新状态到INIT_SELECTING状态即可。 */ /* 其它状态则需要释放已配置的IP。 */ if (REQUESTING != dhcpc_params.state) { DHCPC_DEBUG("state [%d] receive NACK", dhcpc_params.state); dhcpc_flush_net(LINK_DOWN, LINK_CODE_DENY); } ip_addr.ipAddr = dhcpc_params.yiaddr; server.ipAddr = dhcpc_params.server; DHCPC_INFO("Recv NAK from server %d.%d.%d.%d with ip %d.%d.%d.%d", server.ipAddrByteFormat[0], server.ipAddrByteFormat[1], server.ipAddrByteFormat[2], server.ipAddrByteFormat[3], ip_addr.ipAddrByteFormat[0], ip_addr.ipAddrByteFormat[1], ip_addr.ipAddrByteFormat[2], ip_addr.ipAddrByteFormat[3]); if (dhcpc_params.state != RECONNECT_RENEWING && dhcpc_params.state != RECONNECT_REBINDING) { dhcpc_timeout_flush_net(); } else { /* 收到NAK后重新开始DISCOVERY前刷新参数 */ dhcpc_params_update(); } dhcpc_params.timeout = 0; dhcpc_params.yiaddr = 0; dhcpc_params.packet = 0; dhcpc_params.state = DISCOVERY; memset(dhcpc_params.server_mac, 0, MAC_ADDR_SIZE); break; } } LOCAL S32 dhcpc_ctrl_callback(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { DHCPC_MSG *msg = (DHCPC_MSG *)mbuf; if (NULL == msg || sizeof(DHCPC_MSG) != mlen) { DHCPC_WARNING("call back parameter error."); return ERROR; } if (DHCPC_CTRL_START == msg->ctrl) { DHCPC_DEBUG("Now start dhcpc progress."); link_up_inner(); dhcpc_params.call_bk_id = msg->call_bk_id; return OK; } if (DHCPC_CTRL_STOP == msg->ctrl) { DHCPC_DEBUG("Now stop dhcpc progress."); link_down_inner(msg->code); return OK; } DHCPC_WARNING("Unknown command."); return ERROR; } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT LOCAL S32 dhcpc_socket_reload() { S32 fd = -1; struct sockaddr_in addr; S32 option = 1; S32 buf_size = 0; if (0 > (fd = socket(AF_INET, SOCK_DGRAM, 0))) { DHCPC_ERROR("client socket call failed"); goto dhcpc_error_exit; } if (0 > setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option))) { DHCPC_ERROR("client socket set reuseaddr option failed"); goto dhcpc_error_exit; } if (0 > setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &option, sizeof(option))) { DHCPC_ERROR("client socket set broadcast option failed"); goto dhcpc_error_exit; } /* 设置缓存大小 */ buf_size = DHCPC_SOCKET_RECV_BUF_SIZE; if (ERROR == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size))) { DHCPC_ERROR("Set sock rcv buf error."); } buf_size = DHCPC_SOCKET_SEND_BUF_SIZE; if (ERROR == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size))) { DHCPC_ERROR("Set sock rcv buf error."); } /* 绑定网卡 */ struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); IF_CONF if_conf = {0}; LTE_CONFIG_INFO_DATA lte_config; memset(&lte_config, 0, sizeof(LTE_CONFIG_INFO_DATA)); if(0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("Read lte config data ERROR"); return ERROR; } if(lte_config.internet_wired_enable == 0) { strncpy(ifr.ifr_name, DHCPC_4G_IPC_DEV_NAME, strlen(DHCPC_4G_IPC_DEV_NAME) + 1); DHCPC_ERROR("ifr.ifr_name:%s", ifr.ifr_name); }else { if (0 == ds_read(IF_CONF_PATH, &if_conf, sizeof(IF_CONF))) { DHCPC_ERROR("Read wan config error"); goto dhcpc_error_exit; } /* 无论是否为bridge ifname都存放我们需要的值 */ if (0 == if_conf.ifname[0]) { DHCPC_ERROR("Get ifname failed."); goto dhcpc_error_exit; } strncpy(ifr.ifr_name, if_conf.ifname, strlen(if_conf.ifname)); } if(ERROR == setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char*)&ifr, sizeof(ifr))) { DHCPC_ERROR("can't bind to interface :%s", ifr.ifr_name); } DHCPC_ERROR("ifr.ifr_name:%s", ifr.ifr_name); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(CLIENT_PORT); addr.sin_addr.s_addr = INADDR_ANY; if (0 > bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { DHCPC_ERROR("server socket set broadcast option failed"); goto dhcpc_error_exit; } return fd; dhcpc_error_exit: if (-1 != fd) { close(fd); fd = -1; } return fd; } LOCAL int dhcpc_param_reload(int flag) { IF_CONF if_conf = {0}; DHCPC dhcpc_data; dhcpc_params.yiaddr = 0xFFFFFFFF; dhcpc_params.call_bk_id_new = -1; //dhcpc_params.call_bk_id = -1; dhcpc_params.path = DHCPC_PATH; if(flag == DHCPC_4G_INTERNET_MODE) { /* 4G_ICP使用usb0 */ snprintf(dhcpc_params.dev_name, sizeof(dhcpc_params.dev_name), "%s", DHCPC_4G_IPC_DEV_NAME); if(0 > read_interface_info(dhcpc_params.dev_name, &dhcpc_params.dev, dhcpc_params.mac)) { DHCPC_ERROR("read usb0 device info error"); return ERROR; } } else { if (0 == ds_read(IF_CONF_PATH, &if_conf, sizeof(IF_CONF))) { DHCPC_ERROR("Read wan config error"); return ERROR; } /* 无论是否为bridge ifname都存放我们需要的值 */ if (0 == if_conf.ifname[0]) { DHCPC_ERROR("Get ifname failed."); return ERROR; } /* IPC使用br-wan */ snprintf(dhcpc_params.dev_name, sizeof(dhcpc_params.dev_name), "%s", if_conf.ifname); if (0 > read_interface_info(dhcpc_params.dev_name, &dhcpc_params.dev, dhcpc_params.mac)) { DHCPC_ERROR("read usb0 device info error"); return ERROR; } } /* 智能ip,IPC断开dhcp时不释放租约 */ dhcpc_params.send_release = FALSE; dhcpc_params.support_un_cast = TRUE; dhcpc_params.mtu = 1500; dhcpc_params.flags = FALSE; /* 默认广播。 */ if (NULL != dhcpc_params.path) { memset(&dhcpc_data, 0, sizeof(DHCPC)); ds_read(dhcpc_params.path, (U8*)&dhcpc_data, sizeof(DHCPC)); dhcpc_params.name[OPT_CODE] = DHCP_HOST_NAME; dhcpc_params.name[OPT_LEN] = strlen(dhcpc_data.hostname); strncpy(&(dhcpc_params.name[OPT_DATA]), dhcpc_data.hostname, MAX_HOST_NAME_LEN); dhcpc_params.name[dhcpc_params.name[OPT_LEN] + 2] = '\0'; } dhcpc_params.client[OPT_CODE] = DHCP_CLIENT_ID; dhcpc_params.client[OPT_LEN] = 7; dhcpc_params.client[OPT_DATA] = 1; memcpy(&(dhcpc_params.client[OPT_DATA + 1]), dhcpc_params.mac, MAC_ADDR_SIZE); dhcpc_params.client[dhcpc_params.client[OPT_LEN] + 2] = '\0'; dhcpc_params.client[OPT_CODE] = DHCP_CLIENT_ID; dhcpc_params.client[OPT_LEN] = 7; dhcpc_params.client[OPT_DATA] = 1; memcpy(&(dhcpc_params.client[OPT_DATA + 1]), dhcpc_params.mac, MAC_ADDR_SIZE); dhcpc_params.client[dhcpc_params.client[OPT_LEN] + 2] = '\0'; dhcpc_params.re_dial = FALSE; dhcpc_params.code = LINK_CODE_NORMAL; if(dhcpc_params.sock) { inet_del_socket(g_sock_idx); close(dhcpc_params.sock); dhcpc_params.sock = -1; } dhcpc_params.sock = dhcpc_socket_reload(); g_sock_idx = inet_add_socket(dhcpc_params.sock, (void*)dhcpc_handle, NULL, NULL); if(0 > g_sock_idx) { DHCPC_ERROR("add dhcp client socket to inetd failed"); close(dhcpc_params.sock); dhcpc_params.sock = -1; return ERROR; } if(0 > inet_add_timer((void*)dhcpc_check_timer, 0, 1, EXECUTE_FOREVER)) { DHCPC_ERROR("add dhcp timer to inetd failed"); inet_del_socket(g_sock_idx); close(dhcpc_params.sock); dhcpc_params.sock = -1; return ERROR; } return OK; } LOCAL S32 lte_dhcpc_ctrl_callback(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { DHCPC_MSG *msg = (DHCPC_MSG *)mbuf; U8 dev_mac[6] = {0}; if (NULL == msg || sizeof(DHCPC_MSG) != mlen) { DHCPC_WARNING("call back parameter error."); return ERROR; } if (DHCPC_CTRL_START == msg->ctrl) { if(!strncmp(dhcpc_params.dev_name, DHCPC_4G_IPC_DEV_NAME, sizeof(dhcpc_params.dev_name))) { DHCPC_DEBUG("Now start dhcpc progress."); if(0 > read_interface_info(dhcpc_params.dev_name, NULL, dev_mac)) { DHCPC_ERROR("read usb0 device info error"); return ERROR; } if(memcmp(dhcpc_params.mac, dev_mac, sizeof(dhcpc_params.mac))) { DHCPC_ERROR("usb0 device mac change, reload dhcpc params."); if(ERROR == dhcpc_param_reload(DHCPC_4G_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } } link_up_inner(); }else { DHCPC_DEBUG("Change dhcpc device first"); DHCPC_DEBUG("Now start dhcpc progress."); if(ERROR == dhcpc_param_reload(DHCPC_4G_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } link_up_inner(); } dhcpc_params.call_bk_id = msg->call_bk_id; return OK; } if (DHCPC_CTRL_STOP == msg->ctrl) { DHCPC_DEBUG("Now stop dhcpc progress."); link_down_inner(msg->code); return OK; } DHCPC_WARNING("Unknown command."); return ERROR; } #endif LOCAL S32 dhcpc_socket_init() { S32 fd = -1; struct sockaddr_in addr; S32 option = 1; S32 buf_size = 0; if (0 > (fd = socket(AF_INET, SOCK_DGRAM, 0))) { DHCPC_ERROR("client socket call failed"); goto dhcpc_error_exit; } if (0 > setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option))) { DHCPC_ERROR("client socket set reuseaddr option failed"); goto dhcpc_error_exit; } if (0 > setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &option, sizeof(option))) { DHCPC_ERROR("client socket set broadcast option failed"); goto dhcpc_error_exit; } /* 设置缓存大小 */ buf_size = DHCPC_SOCKET_RECV_BUF_SIZE; if (ERROR == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size))) { DHCPC_ERROR("Set sock rcv buf error."); } buf_size = DHCPC_SOCKET_SEND_BUF_SIZE; if (ERROR == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size))) { DHCPC_ERROR("Set sock rcv buf error."); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(CLIENT_PORT); addr.sin_addr.s_addr = INADDR_ANY; if (0 > bind(fd, (struct sockaddr *)&addr, sizeof(addr))) { DHCPC_ERROR("server socket set broadcast option failed"); goto dhcpc_error_exit; } return fd; dhcpc_error_exit: if (-1 != fd) { close(fd); fd = -1; } return fd; } LOCAL void dhcpc_param_init() { IF_CONF if_conf = {0}; DHCPC dhcpc_data; if (0 == ds_read(IF_CONF_PATH, &if_conf, sizeof(IF_CONF))) { DHCPC_ERROR("Read wan config error"); return; } /* 无论是否为bridge ifname都存放我们需要的值 */ if (0 == if_conf.ifname[0]) { DHCPC_ERROR("Get ifname failed."); return; } memset(&dhcpc_params, 0, sizeof(DHCPC_PARAMS)); /* 智能ip,设置ip为0xFFFFFFFF 标记是开机后首次获取ip */ dhcpc_params.yiaddr = 0xFFFFFFFF; dhcpc_params.call_bk_id_new = -1; dhcpc_params.call_bk_id = -1; dhcpc_params.mac[0] = 0x00; dhcpc_params.mac[1] = 0x11; dhcpc_params.mac[2] = 0x22; dhcpc_params.mac[3] = 0x33; dhcpc_params.mac[4] = 0x44; dhcpc_params.mac[5] = 0x55; dhcpc_params.path = DHCPC_PATH; /* IPC使用br-wan */ snprintf(dhcpc_params.dev_name, sizeof(dhcpc_params.dev_name), "%s", if_conf.ifname); if (0 > read_interface_info(dhcpc_params.dev_name, &dhcpc_params.dev, dhcpc_params.mac)) { return; } /* 智能ip,IPC断开dhcp时不释放租约 */ dhcpc_params.send_release = FALSE; dhcpc_params.support_un_cast = TRUE; dhcpc_params.mtu = 1500; dhcpc_params.state = INIT; dhcpc_params.flags = FALSE; /* 默认广播。 */ if (NULL != dhcpc_params.path) { memset(&dhcpc_data, 0, sizeof(DHCPC)); ds_read(dhcpc_params.path, (U8*)&dhcpc_data, sizeof(DHCPC)); dhcpc_params.name[OPT_CODE] = DHCP_HOST_NAME; dhcpc_params.name[OPT_LEN] = strlen(dhcpc_data.hostname); strncpy(&(dhcpc_params.name[OPT_DATA]), dhcpc_data.hostname, MAX_HOST_NAME_LEN); dhcpc_params.name[dhcpc_params.name[OPT_LEN] + 2] = '\0'; } dhcpc_params.client[OPT_CODE] = DHCP_CLIENT_ID; dhcpc_params.client[OPT_LEN] = 7; dhcpc_params.client[OPT_DATA] = 1; memcpy(&(dhcpc_params.client[OPT_DATA + 1]), dhcpc_params.mac, MAC_ADDR_SIZE); dhcpc_params.client[dhcpc_params.client[OPT_LEN] + 2] = '\0'; dhcpc_params.packet = 0; /* start things over */ dhcpc_params.timeout = 0xFFFFFFFF; /* Kill any timeouts because the user wants this to hurry along */ dhcpc_params.retry = 0; dhcpc_params.re_dial = FALSE; dhcpc_params.code = LINK_CODE_NORMAL; dhcpc_params.sock = dhcpc_socket_init(); } LOCAL S32 dhcpc_init() { S32 idx = -1; dhcpc_param_init(); if (0 > dhcpc_params.sock) { DHCPC_ERROR("dhcp client socket init failed"); return ERROR; } idx = inet_add_socket(dhcpc_params.sock, (void*)dhcpc_handle, NULL, NULL); if (0 > idx) { DHCPC_ERROR("add dhcp client socket to inetd failed"); close(dhcpc_params.sock); dhcpc_params.sock = -1; return ERROR; } if (0 > inet_add_timer((void*)dhcpc_check_timer, 0, 1, EXECUTE_FOREVER)) { DHCPC_ERROR("add dhcp timer to inetd failed"); inet_del_socket(idx); close(dhcpc_params.sock); dhcpc_params.sock = -1; return ERROR; } msg_attach_handler(NSD_DHCPC_CTRL, dhcpc_ctrl_callback); #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT g_sock_idx = idx; msg_attach_handler(LTE_DHCPC_CTRL, lte_dhcpc_ctrl_callback); #endif DHCPC_ERROR("DHCPC init over."); return OK; } LOCAL S32 dhcpc_reload(DS_MSG *msg) { if (NULL == msg) { return ERROR; } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT if(!get_lte_config_data_flag) { if(0 == ds_read(LTE_INFO_DATA_PATH, (U8*)&g_lte_config_data, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("ds read path [%s] failed.", LTE_INFO_DATA_PATH); return ERROR; } get_lte_config_data_flag = 1; } #endif if (ds_path_id_exist(msg->id, msg->num, DHCPC_PATH)) { DHCPC dhcpc_data; memset(&dhcpc_data, 0, sizeof(DHCPC)); if (0 == ds_read(DHCPC_PATH, (U8 *)&dhcpc_data, sizeof(DHCPC))) { DHCPC_ERROR("Read dhcpc data ERROR"); return ERROR; } dhcpc_params.mtu = dhcpc_data.mtu; dhcpc_params.flags = !dhcpc_data.enable_broadcast; dhcpc_params.manual_dns = (dhcpc_data.dns_mode == DNS_MODE_MANUAL); /*TODO: 目前只考虑为非手动获取dns的情况 */ #if 0 dhcpc_params[iface].dns[0] = dhcpc_params[iface].manual_dns ? dhcpc_data.dns[0] : 0; dhcpc_params[iface].dns[1] = dhcpc_params[iface].manual_dns ? dhcpc_data.dns[1] : 0; #endif dhcpc_params.name[OPT_CODE] = DHCP_HOST_NAME; dhcpc_params.name[OPT_LEN] = strlen(dhcpc_data.hostname); strncpy(&(dhcpc_params.name[OPT_DATA]), dhcpc_data.hostname, MAX_HOST_NAME_LEN); dhcpc_params.name[dhcpc_params.name[OPT_LEN] + 2] = '\0'; } #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT if(ds_path_id_exist(msg->id, msg->num, INFO_INTERNET_PATH)) { INFO_INTERNET info_internet = {0}; if(0 == ds_read(INFO_INTERNET_PATH, (U8*)&info_internet, sizeof(INFO_INTERNET))) { DHCPC_ERROR("ds read path [%s] failed.", INFO_INTERNET_PATH); return ERROR; } LTE_CONFIG_INFO_DATA lte_config; memset(&lte_config, 0, sizeof(LTE_CONFIG_INFO_DATA)); if(info_internet.link_status == INTERNET_4G_DISCONNECTED) { if(0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("Read lte config data ERROR"); return ERROR; } if(lte_config.internet_wired_enable == 0) { if(lte_config.internet_wired_enable != g_lte_config_data.internet_wired_enable) { g_lte_config_data.internet_wired_enable = lte_config.internet_wired_enable; if(ERROR == dhcpc_param_reload(DHCPC_4G_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } } } else { if(lte_config.internet_wired_enable != g_lte_config_data.internet_wired_enable) { g_lte_config_data.internet_wired_enable = lte_config.internet_wired_enable; if(ERROR == dhcpc_param_reload(DHCPC_WIRED_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } } } }else if(info_internet.link_status == INTERNET_4G_CONNECTING) { if(0 == ds_read(LTE_INFO_DATA_PATH, &lte_config, sizeof(LTE_CONFIG_INFO_DATA))) { DHCPC_ERROR("Read lte config data ERROR"); return ERROR; } if(lte_config.internet_wired_enable == 0) { if(lte_config.internet_wired_enable != g_lte_config_data.internet_wired_enable) { g_lte_config_data.internet_wired_enable = lte_config.internet_wired_enable; if(ERROR == dhcpc_param_reload(DHCPC_4G_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } } } else { if(lte_config.internet_wired_enable != g_lte_config_data.internet_wired_enable) { g_lte_config_data.internet_wired_enable = lte_config.internet_wired_enable; if(ERROR == dhcpc_param_reload(DHCPC_WIRED_INTERNET_MODE)) { DHCPC_ERROR("reload dhcpc param failed"); return ERROR; } } } } } #endif return OK; } LOCAL void dhcpc_main() { DS_DAT_MON_DESC dhcpc_data_monitor[] = { DS_DAT_MON(DHCPC_PATH, DATA_ATTRI_NOTIFY), #ifdef CONFIG_MOBILE_ACCESS_SET_SUPPORT DS_DAT_MON(INFO_INTERNET_PATH, DATA_ATTRI_NOTIFY), #endif }; DS_MOD_DESC dhcpc_module = DS_STRUCT_MOD("dhcpc", dhcpc_init, NULL, dhcpc_reload, NULL, NULL, NULL, dhcpc_data_monitor); MODULE *module_node = ds_register_module("dhcpc", &dhcpc_module); SDM_ASSERT(NULL != module_node); } NSD_INIT(dhcpc_main); 学习一下这个dhcp.c的代码,帮我完成下面的作业,arp和dhcp是同一级文件夹,你可以参考一下DHCP的。 1. 知识点 1.1 熟悉使用IPC功能,熟悉IPC功能; 1.2 阅读DS、DMS、主进程源码 1.3 掌握固件烧录升级方法 1.4 编程实现私有模块添加 1.5 掌握postman的使用方法 1.6 掌握通过WEB调试功能F12调试接口的方法 2. 实验题 课题:ARP扫描功能 要求: 1、基于NVMP平台,为NSD模块添加一个用于定时扫描指定网段的主机的arp子模块。arp子模块的扫描需要通过socket编程收发ARP报文来实现。 2、arp子模块使用DS来保存用户配置,用户配置参数包括:功能开关、扫描周期(秒)、有效期(秒)、发包间隔(毫秒)、起始IP、结束IP。 例如可以指定192.168.1.100-192.168.1.200,每格60秒扫描一遍,发包间隔100毫秒,如果网络中有192.168.1.101和192.168.1.102两台主机,则扫描结果就是这两个IP地址及对应的MAC地址。扫描功能需在开关开启对情况下才进行; 扫描的结果需要在内存中管理维护,一个ARP条目如果超过有效期时间都未被再次扫描到则删除掉该条目。 3、arp子模块需要提供基于DMS的ubus服务接口,至少提供以下接口用于客户端调用,使用TDCP协议: set_arp_config(设置功能开关、扫描周期、有效期、发包间隔、起始IP、结束IP地址) get_arp_config(获取功能开关、扫描周期、有效期、发包间隔、起始IP、结束IP地址) start_scan(开始一次扫描) stop_scan(停止扫描) get_scan_status(扫描状态) get_scan_result(获取最近一次的扫描结果) clear_result(清除历史结果) 其次需要提供基于ubus工具的调测命令,用于在串口执行扫描,停止扫描,获取扫描结果,获取扫描状态,清除历史扫描结果等。 4、每次发现一台新的主机(之前扫描时未发现的),将主机信息打印到串口,同时在内存中进行存储。 5、写一个测试程序test_arpsd,通过C代码调用DMS/DS库API的方式(不能直接调用ubus命令),对各部分功能和接口进行测试。 6、在Network标签下添加一个子页面,标题为ARP Scanner。可以在该web页面上进行以下操作: 修改上述配置参数并生效、执行或终止一次扫描、获取并显示上一次扫描结果。 7、编写为NVMP平台NSD的一个子模块软件包,包含所有的c、shell、html代码及Makefile文件。 备注:WEB部分(上述第6点)是可选的,请先完成与web无关的部分。
08-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值