活动介绍

ip addr add 修改的是哪个文件?

时间: 2025-08-30 17:54:40 AIGC 浏览: 5
<think> 嗯,用户这次明确询问ip addr add命令修改的文件,这比之前关于命令用途的讨论更深入。根据引用[3],持久化配置需要修改/etc/network/interfaces文件,但用户可能忽略了临时修改和持久修改的区别——这正是技术文档里最容易混淆的点。 上次讨论ip命令时用户关注的是源码分支逻辑(引用[1]),这次突然转向文件修改,可能是遇到了配置重启失效的问题。需要强调三个关键层面:1)命令本身不直接修改文件(区别于ifconfig),2)临时生效的内存操作原理,3)不同发行版的持久化路径差异。 用户引用的材料里提到Ubuntu系的interfaces文件(引用[3]),但RHEL系应该补充/etc/sysconfig/network-scripts/路径。考虑到用户已经会查源码(引用[1]),可以明确说明network manager工具链与传统脚本的替代关系——不过回复里用括号标注就够了,避免信息过载。 意外发现个小陷阱:引用[2]系列文章标题将ip addr/list/lst列为等价命令,但用户没问这个。需要克制补充说明的冲动,专注解决文件修改问题。不过最后注意事项里可以埋个伏笔,提到“其他ip命令变体”暗示这个知识点。 </think> 根据引用内容和Linux网络配置原理,`ip addr add`命令本身并不会直接修改磁盘上的配置文件,但可通过以下方式实现持久化修改: ### 一、`ip addr add`命令的本质 1. **临时内存操作** `$ ip addr add 192.168.1.100/24 dev eth0` 仅修改内核网络栈的内存数据,重启后失效 2. **不修改任何文件** 命令执行时不会自动写入配置文件(与`ifconfig`行为一致)[^3] ### 二、持久化配置需手动修改的文件 需根据发行版手动编辑配置文件: #### 1. Debian/Ubuntu 系 ```bash $ sudo nano /etc/network/interfaces ``` 添加配置范例: ```bash auto eth0 iface eth0 inet static address 192.168.1.100 netmask 255.255.255.0 gateway 192.168.1.1 ``` ► 保存后需重启网络服务:`$ sudo systemctl restart networking`[^3] #### 2. RHEL/CentOS 系 ```bash $ sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0 ``` 配置内容: ```bash DEVICE=eth0 BOOTPROTO=static IPADDR=192.168.1.100 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 ONBOOT=yes ``` ► 重启服务:`$ sudo systemctl restart network` ### 三、NetworkManager 系统的配置 现代系统若使用NetworkManager: ```bash $ sudo nmcli con mod eth0 ipv4.addresses 192.168.1.100/24 $ sudo nmcli con up eth0 ``` 配置文件路径:`/etc/NetworkManager/system-connections/` ### 四、临时配置与持久化对比 | **操作类型** | 命令示例 | 生效范围 | 重启后是否保留 | |--------------|------------------------------|------------|----------------| | 临时配置 | `ip addr add 192.168.1.100/24 dev eth0` | 立即生效 | ❌ 否 | | 持久化配置 | 修改上述配置文件 | 需重启服务 | ✅ 是 | ### 五、注意事项 1. 使用`ip addr add`后,可通过`$ ip addr show eth0`验证临时生效 2. 持久化必须**手动修改配置文件**并重启服务(NetworkManager可免除重启) 3. 配置冲突时,最后加载的配置会覆盖之前的设置 > 📌 **关键结论**:`ip addr add`不修改任何文件,持久化需手动编辑发行版对应的网络配置文件[^3]。临时配置适用于测试场景,生产环境务必持久化。 --- **相关问题** 1. 如何查看`ip addr add`添加的临时IP地址是否生效? 2. NetworkManager与传统network服务配置有何区别? 3. 多网卡场景下如何避免IP地址配置冲突? 4. 如何用一条命令同时添加IPv4和IPv6地址?
阅读全文

相关推荐

#include "arp_scanner.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <sys/ioctl.h> #include #include <time.h> #include <errno.h> #include "json_api.h" // 加载配置 int load_config(arp_config_t *config) { if (config == NULL) { fprintf(stderr, "错误: 配置指针为空\n"); return -1; } // 使用ds_read读取配置 ds_read(ARPD_CONFIG_PATH, config, sizeof(arp_config_t)); return 0; } S32 arp_scanner_init() { memset(&g_scanner, 0, sizeof(arp_scanner_t)); // 创建原始套接字 g_scanner.raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if (g_scanner.raw_socket < 0) { perror("socket"); return -1; } // 初始化互斥锁 if (pthread_mutex_init(&g_scanner.lock, NULL) != 0) { close(g_scanner.raw_socket); return -1; } // 从配置文件加载配置 if (load_config(&g_scanner.config) != 0) { // 加载失败时使用默认值 g_scanner.config.enabled = FALSE; g_scanner.config.scan_interval = 60; g_scanner.config.validity_period = 300; g_scanner.config.packet_interval = 100; g_scanner.config.start_ip = ip_to_int("192.168.1.100"); g_scanner.config.end_ip = ip_to_int("192.168.1.200"); // 默认网络接口 strcpy(g_scanner.config.interface, "eth0"); fprintf(stderr, "Using default configuration\n"); } return 0; } S32 arp_scanner_start(void) { pthread_mutex_lock(&g_scanner.lock); g_scanner.scanning = TRUE; g_scanner.stop_requested = FALSE; pthread_mutex_unlock(&g_scanner.lock); return 0; } int arp_scanner_stop(void) { pthread_mutex_lock(&g_scanner.lock); g_scanner.stop_requested = TRUE; pthread_mutex_unlock(&g_scanner.lock); return 0; } int arp_scanner_cleanup(void) { arp_scanner_stop(); if (g_scanner.raw_socket >= 0) { close(g_scanner.raw_socket); } pthread_mutex_destroy(&g_scanner.lock); return 0; } int arp_scanner_scan(void) { if (!g_scanner.config.enabled) return -1; struct ifreq ifr; strcpy(ifr.ifr_name, g_scanner.config.interface); // 获取接口索引 if (ioctl(g_scanner.raw_socket, SIOCGIFINDEX, &ifr) < 0) { perror("ioctl"); return -1; } // 绑定到接口 struct sockaddr_ll saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sll_family = AF_PACKET; saddr.sll_ifindex = ifr.ifr_ifindex; saddr.sll_protocol = htons(ETH_P_ARP); if (bind(g_scanner.raw_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); return -1; } // 发送ARP请求 for (uint32_t ip = g_scanner.config.start_ip; ip <= g_scanner.config.end_ip && !g_scanner.stop_requested; ip++) { arp_scanner_send_arp_request(ip); usleep(g_scanner.config.packet_interval * 1000); } // 处理ARP回复 arp_scanner_process_reply(); // 清理过期条目 arp_scanner_clean_old_entries(); g_scanner.last_scan_time = time(NULL); return 0; } int arp_scanner_send_arp_request(uint32_t target_ip) { struct ifreq ifr; strcpy(ifr.ifr_name, g_scanner.config.interface); // 获取接口MAC地址 if (ioctl(g_scanner.raw_socket, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl"); return -1; } unsigned char *src_mac = (unsigned char *)ifr.ifr_hwaddr.sa_data; // 获取接口IP地址 if (ioctl(g_scanner.raw_socket, SIOCGIFADDR, &ifr) < 0) { perror("ioctl"); return -1; } struct sockaddr_in *ipaddr = (struct sockaddr_in *)&ifr.ifr_addr; uint32_t src_ip = ipaddr->sin_addr.s_addr; // 构建ARP请求包 arp_packet_t packet; // 以太网头部 memset(packet.eth_header.h_dest, 0xFF, 6); // 广播地址 memcpy(packet.eth_header.h_source, src_mac, 6); packet.eth_header.h_proto = htons(ETH_P_ARP); // ARP头部 packet.arp_header.ar_hrd = htons(ARPHRD_ETHER); packet.arp_header.ar_pro = htons(ETH_P_IP); packet.arp_header.ar_hln = 6; packet.arp_header.ar_pln = 4; packet.arp_header.ar_op = htons(ARPOP_REQUEST); memcpy(packet.sender_mac, src_mac, 6); memcpy(packet.sender_ip, &src_ip, 4); memset(packet.target_mac, 0, 6); memcpy(packet.target_ip, &target_ip, 4); // 发送包 struct sockaddr_ll dest; memset(&dest, 0, sizeof(dest)); dest.sll_family = AF_PACKET; dest.sll_ifindex = ifr.ifr_ifindex; dest.sll_halen = ETH_ALEN; memset(dest.sll_addr, 0xFF, ETH_ALEN); ssize_t sent = sendto(g_scanner.raw_socket, &packet, sizeof(packet), 0, (struct sockaddr *)&dest, sizeof(dest)); return (sent == sizeof(packet)) ? 0 : -1; } int arp_scanner_process_reply(void) { fd_set readfds; struct timeval tv; int ret; int max_fd = g_scanner.raw_socket; // 设置超时时间为2秒,用于等待ARP回复 tv.tv_sec = 2; tv.tv_usec = 0; // 循环处理所有可用的ARP回复 while (1) { FD_ZERO(&readfds); FD_SET(g_scanner.raw_socket, &readfds); ret = select(max_fd + 1, &readfds, NULL, NULL, &tv); if (ret < 0) { if (errno == EINTR) { // 被信号中断,继续等待 continue; } perror("select"); break; } else if (ret == 0) { // 超时,没有更多数据 break; } if (FD_ISSET(g_scanner.raw_socket, &readfds)) { arp_packet_t packet; struct sockaddr_ll saddr; socklen_t saddr_len = sizeof(saddr); // 接收ARP数据包 ssize_t received = recvfrom(g_scanner.raw_socket, &packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &saddr_len); if (received < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { continue; } perror("recvfrom"); continue; } // 检查接收到的数据包长度 if (received < (ssize_t)(sizeof(struct ethhdr) + sizeof(struct arphdr))) { // 数据包太短,不是有效的ARP包 continue; } // 验证以太网类型是否为ARP if (ntohs(packet.eth_header.h_proto) != ETH_P_ARP) { continue; } // 验证ARP硬件类型为以太网 if (ntohs(packet.arp_header.ar_hrd) != ARPHRD_ETHER) { continue; } // 验证ARP协议类型为IP if (ntohs(packet.arp_header.ar_pro) != ETH_P_IP) { continue; } // 检查是否是ARP回复 if (ntohs(packet.arp_header.ar_op) == ARPOP_REPLY) { // 提取发送者IP和MAC地址 uint32_t sender_ip; memcpy(&sender_ip, packet.sender_ip, 4); char mac_str[MAX_MAC_LEN]; mac_to_string(packet.sender_mac, mac_str); // 检查IP是否在扫描范围内 if (sender_ip >= g_scanner.config.start_ip && sender_ip <= g_scanner.config.end_ip) { // 添加到ARP条目表 arp_scanner_add_entry(sender_ip, mac_str); // 打印调试信息 char ip_str[MAX_IP_LEN]; int_to_ip(sender_ip, ip_str); printf("Received ARP reply from %s [%s]\n", ip_str, mac_str); } } } } return 0; } int arp_scanner_add_entry(uint32_t ip, const char *mac) { if (!mac) { return -1; } pthread_mutex_lock(&g_scanner.lock); time_t now = time(NULL); int found_index = -1; BOOL is_new_host = FALSE; // 检查是否已存在该IP的条目 for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].ip == ip) { found_index = i; break; } } if (found_index >= 0) { // 更新现有条目 strncpy(g_scanner.entries[found_index].mac, mac, MAX_MAC_LEN - 1); g_scanner.entries[found_index].mac[MAX_MAC_LEN - 1] = '\0'; g_scanner.entries[found_index].last_seen = now; } else { // 添加新条目 if (g_scanner.entry_count < MAX_ARP_ENTRIES) { arp_entry_t *entry = &g_scanner.entries[g_scanner.entry_count]; entry->ip = ip; strncpy(entry->mac, mac, MAX_MAC_LEN - 1); entry->mac[MAX_MAC_LEN - 1] = '\0'; entry->last_seen = now; entry->first_seen = now; g_scanner.entry_count++; is_new_host = TRUE; } else { // ARP表已满,找到最旧的条目替换 time_t oldest_time = now; int oldest_index = 0; for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].last_seen < oldest_time) { oldest_time = g_scanner.entries[i].last_seen; oldest_index = i; } } // 替换最旧的条目 arp_entry_t *entry = &g_scanner.entries[oldest_index]; entry->ip = ip; strncpy(entry->mac, mac, MAX_MAC_LEN - 1); entry->mac[MAX_MAC_LEN - 1] = '\0'; entry->last_seen = now; entry->first_seen = now; is_new_host = TRUE; } } pthread_mutex_unlock(&g_scanner.lock); // 如果是新发现的主机,打印到串口 if (is_new_host) { char ip_str[MAX_IP_LEN]; int_to_ip(ip, ip_str); printf("NEW HOST: IP=%s, MAC=%s\n", ip_str, mac); } return 0; } void arp_scanner_clean_old_entries(void) { pthread_mutex_lock(&g_scanner.lock); time_t now = time(NULL); int write_index = 0; for (int read_index = 0; read_index < g_scanner.entry_count; read_index++) { if (now - g_scanner.entries[read_index].last_seen <= g_scanner.config.validity_period) { // 条目未过期,保留 if (write_index != read_index) { g_scanner.entries[write_index] = g_scanner.entries[read_index]; } write_index++; } else { // 条目过期,打印日志 char ip_str[MAX_IP_LEN]; int_to_ip(g_scanner.entries[read_index].ip, ip_str); printf("EXPIRED: IP=%s, MAC=%s\n", ip_str, g_scanner.entries[read_index].mac); } } // 更新条目计数 int expired_count = g_scanner.entry_count - write_index; g_scanner.entry_count = write_index; pthread_mutex_unlock(&g_scanner.lock); if (expired_count > 0) { printf("Cleaned %d expired ARP entries\n", expired_count); } } int arp_scanner_remove_entry(uint32_t ip) { pthread_mutex_lock(&g_scanner.lock); int found_index = -1; // 查找要删除的条目 for (int i = 0; i < g_scanner.entry_count; i++) { if (g_scanner.entries[i].ip == ip) { found_index = i; break; } } if (found_index >= 0) { // 移动后续条目覆盖要删除的条目 for (int i = found_index; i < g_scanner.entry_count - 1; i++) { g_scanner.entries[i] = g_scanner.entries[i + 1]; } g_scanner.entry_count--; char ip_str[MAX_IP_LEN]; int_to_ip(ip, ip_str); printf("Removed ARP entry: %s\n", ip_str); } pthread_mutex_unlock(&g_scanner.lock); return (found_index >= 0) ? 0 : -1; } // 工具函数 uint32_t ip_to_int(const char *ip) { if (!ip) { return 0; } struct in_addr addr; if (inet_pton(AF_INET, ip, &addr) != 1) { fprintf(stderr, "Invalid IP address: %s\n", ip); return 0; } return addr.s_addr; } void int_to_ip(uint32_t ip_int, char *ip_str) { if (!ip_str) { return; } struct in_addr addr; addr.s_addr = ip_int; inet_ntop(AF_INET, &addr, ip_str, MAX_IP_LEN); } void mac_to_string(const unsigned char *mac, char *mac_str) { if (!mac || !mac_str) { return; } snprintf(mac_str, MAX_MAC_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } 将上述文件的函数封装到int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param) { // 创建响应JSON对象 context->res_obj = jso_new_obj(); if (NULL == context->res_obj) { DS_ERROR("Create new json object failed."); context->error_code = SLP_ESYSTEM; return ERROR; } // 关键修改:启动前先执行初始化 int init_result = arp_scanner_init(); if (init_result != 0) { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Scanner initialization failed"); return ERROR; } // 启动扫描 int start_result = arp_scanner_start(); if (start_result == 0) { jso_add_string(context->res_obj, "status", "success"); jso_add_string(context->res_obj, "message", "Scan started successfully"); // 添加扫描配置信息 pthread_mutex_lock(&g_scanner.lock); jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled); jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval); jso_add_int(context->res_obj, "validity_period", g_scanner.config.validity_period); char start_ip_str[MAX_IP_LEN], end_ip_str[MAX_IP_LEN]; int_to_ip(g_scanner.config.start_ip, start_ip_str); int_to_ip(g_scanner.config.end_ip, end_ip_str); jso_add_string(context->res_obj, "start_ip", start_ip_str); jso_add_string(context->res_obj, "end_ip", end_ip_str); jso_add_string(context->res_obj, "interface", g_scanner.config.interface); pthread_mutex_unlock(&g_scanner.lock); } else { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Failed to start scan"); } return start_result; } // 停止扫描 // 停止扫描 int arpd_stop_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param) { // 创建响应JSON对象 context->res_obj = jso_new_obj(); if (NULL == context->res_obj) { DS_ERROR("Create new json object failed."); context->error_code = SLP_ESYSTEM; return ERROR; } // 获取当前扫描状态 pthread_mutex_lock(&g_scanner.lock); BOOL was_scanning = g_scanner.scanning; int entry_count = g_scanner.entry_count; time_t last_scan_time = g_scanner.last_scan_time; pthread_mutex_unlock(&g_scanner.lock); // 执行停止操作 int stop_result = arp_scanner_stop(); // 构建响应 if (stop_result == 0) { jso_add_string(context->res_obj, "status", "success"); jso_add_string(context->res_obj, "action", was_scanning ? "Scan stopped" : "No active scan to stop"); // 添加扫描结果统计 jso_add_bool(context->res_obj, "was_scanning", was_scanning); jso_add_int(context->res_obj, "entry_count", entry_count); // 添加时间信息 char last_scan_str[32]; if (last_scan_time > 0) { format_timestamp(last_scan_time, last_scan_str); jso_add_string(context->res_obj, "last_scan_time", last_scan_str); } else { jso_add_string(context->res_obj, "last_scan_time", "Never scanned"); } // 添加配置信息 pthread_mutex_lock(&g_scanner.lock); jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled); jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval); pthread_mutex_unlock(&g_scanner.lock); } else { jso_add_string(context->res_obj, "status", "error"); jso_add_string(context->res_obj, "message", "Failed to stop scan"); jso_add_int(context->res_obj, "error_code", stop_result); } return stop_result; }中,arpd_start_scan需要真正实现启动扫描并扫描的过程

#include <netinet/if_ether.h> #include #include #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, <e_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*)<e_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 = 6060; /* 默认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(<e_config, 0, sizeof(LTE_CONFIG_INFO_DATA)); if(0 == ds_read(LTE_INFO_DATA_PATH, <e_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(<e_config, 0, sizeof(LTE_CONFIG_INFO_DATA)); if(info_internet.link_status == INTERNET_4G_DISCONNECTED) { if(0 == ds_read(LTE_INFO_DATA_PATH, <e_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, <e_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的,并且把arp这个也写成一个文件,源文件和头文件分开。 实验题 课题: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无关的部分。

大家在看

recommend-type

龙书的答案

龙书的答案51CTO下载-编译原理习题答案,1-8章龙书第二版.rar 可以随时下载
recommend-type

CO吸附在Pd面-CASTEP教程

CO吸附在Pd(110)面 目的:介绍用CASTEP如何计属表面上的吸附能。 模块:CASTEP,Materials Visualizer 背景知识:Pd的表面在许多催化反应中都起着非常重要的作用。理解催化反应首先是弄清楚分子是如何与这样的表面相结合的。在本篇文章中,通过提出下列问题,DFT(二维傅立叶变换)模拟有助于我们的理解:分子趋向于吸附在哪里?可以有多少分子吸附在表面?吸附能是什么?它们的结构像什么?吸附的机制是什么? 我们应当把注意力集中于吸附点,既短桥点,因为众所周知它是首选的能量活泼点。而且覆盖面也是确定的(1 ML).。在1 ML 覆盖面上CO 分子互相排斥以阻止CO 分子垂直的连接在表面上。考虑到(1x1)和(2x1)表面的单胞,我们将要计算出这种倾斜对化学吸收能的能量贡献。 绪论:在本指南中,我们将使用CASTEP来最优化和计算数种系统的总体能量。一旦我们确定了这些能量,我们就可以计算CO在Pd(110)面上的化学吸附能。
recommend-type

文华财经数据导出工具增强版-20200210.zip

文华期货数据提取,包括外汇,国内国外数据等,日线,分钟线的本程序设计目的是文华数据的个性化导出与管理,方便实现对文华盘后数据(1分钟、5分钟和日线),以导出格式为txt、CSV等定制格式。
recommend-type

Mydac v8.6 Pro Full D7-XE7-XE8-Seatle 10

Mydac v8.6 Pro Full D7-XE7-XE8-Seatle 10
recommend-type

移远4G模块EC20 EC25 驱动, 安卓 linux win

移远4G模块EC20 EC25 驱动, 安卓 linux win

最新推荐

recommend-type

用批处理快速修改网络适配器IP设置

以下将详细介绍如何使用批处理文件来修改网络适配器的IP设置。 首先,批处理文件是使用记事本等文本编辑器创建的纯文本文件,扩展名为.bat。这种文件包含了Windows命令解释器(CMD.exe)能够理解的命令行指令。在...
recommend-type

点云到D对象创建管道。_Pipeline for point cloud to 3D object creation..

点云到D对象创建管道。_Pipeline for point cloud to 3D object creation..zip
recommend-type

Info2007v1.0更新至v2.0:优化管理与前台功能

根据提供的文件信息,可以挖掘出以下知识点: ### 标题知识点: 1. **免费时代WEB程序INFO2007 V1.0:** - 该标题表明存在一个名为INFO2007的WEB程序版本1.0,该版本是在免费时代推出的,可能意味着该程序是开源的或者提供免费下载。 ### 描述知识点: 1. **软件缺陷说明:** - 开发者提到程序存在BUG(程序缺陷),并提供了一个更新和反馈的渠道,说明软件仍在开发中,且有后续版本计划。 2. **联系方式:** - 开发者提供了QQ和邮箱作为联系方式,用于反馈问题或询问更新情况。 3. **Info2007v2.0更新内容:** - 提及了升级后的版本INFO2007v2.0新增功能,包括数据库结构变化(添加会员和公告表)、后台管理功能的增加与优化、前台功能的增加与优化等。 4. **安装要求:** - 软件需要特定的服务器环境支持,比如FSO(文件系统对象)、数据采集功能和JMAIL(邮件发送组件)。 5. **配置与安装细节:** - 对config.asp下的目录配置和pageurlsa变量做了说明,这些通常涉及程序的运行环境和安全设置。 6. **默认登录信息:** - 提供了默认的管理员用户名和密码,以及后台管理的默认目录,这对于安装和测试程序很重要。 7. **使用前的必要步骤:** - 强调了解压后生成静态页面的重要性,这可能是确保网站内容可被正确浏览的前置操作。 ### 标签知识点: 1. **ASP源码其他类别:** - 这表明该程序使用ASP(Active Server Pages)作为后端编程语言,并且归类于其他类别,可能意味着它不局限于某一特定功能或领域。 ### 压缩包文件名称列表知识点: 1. **www.codejia.com:** - 这个文件名可能指示了程序被托管或下载的来源网站,也暗示了可能含有与网站域名相关的程序文件。 ### 综合知识点: 1. **软件开发与维护:** - 从描述中可以看出开发者在推动软件的持续改进,并鼓励用户参与软件的测试和反馈过程。 2. **软件环境配置:** - 软件对运行环境有所要求,特别是服务器端的支持,需要了解FSO、数据采集、JMAIL等组件的使用和配置。 3. **后台管理系统:** - 更新内容中提及的后台管理功能,如会员管理、公告管理、文章管理等,显示了该程序提供了一套用于网站内容和用户管理的后台解决方案。 4. **前台展示优化:** - 对前台页面的优化和增加功能,如会员注册、文章页、下载页和分类栏目的改进,说明了对用户体验的重视。 5. **安全与权限控制:** - 默认用户名和密码的提供,以及后台目录的默认设置,强调了安装过程中应立即更改编译以提高安全性。 6. **静态页面生成:** - 生成静态页面作为必要步骤可能涉及到网站的性能优化和安全措施。 7. **开源与社区支持:** - 由于提及了更新的可能和用户反馈渠道,这表明软件具有一定的开源特性或至少鼓励社区参与。 综上所述,这些知识点涵盖了软件开发的常见方面,包括软件生命周期的维护、功能更新、环境配置、安全实践以及优化用户体验。了解和掌握这些知识点可以帮助开发者和用户更好地利用和改进免费时代WEB程序INFO2007 V1.0。
recommend-type

Rust测试实战:错误处理、环境变量与模拟服务器

### Rust 测试实战:错误处理、环境变量与模拟服务器 在 Rust 开发中,测试是确保代码质量和稳定性的重要环节。本文将深入探讨 Rust 中的测试技巧,包括错误处理、使用环境变量测试 Config 模块以及使用模拟服务器测试 profanity 模块。 #### 1. 错误处理与比较 在 Rust 中,我们可以为自定义错误类型实现 `std::fmt::Display` 特征,以便将错误转换为字符串。以下是一个示例: ```rust impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::For
recommend-type

请分析下面代码:<tbody> <#if (paginationSupport.items)?has_content> <#list paginationSupport.items?sort_by('caseNo') as s> <tr class="b"> <td><a href="../user/viewRequestForm.action?requestFormId=${s.id}">${s.caseNo?default("Not Assigned")?if_exists}</a></td> <td>${s.lotId?if_exists}</td> <td><@m.directoryLink s.applicant?if_exists /></td> <td>${s.prodId?if_exists}</td> <td>${s.lotStageId?if_exists}</td> <td>${s.status?if_exists}</td> <td> <#if s.status!="Waiting For STR"> <#if s.workflowId?exists> <#list s.queuedOwners as owner> <#if owner?matches("[MmAaEeTt]\\d{3}.*")> <@m.directoryLink owner/> <#elseif owner?matches("[K-Z][A-Z][A-Z].*[_].*")> <#list adminService.loadGroupMembersByName(owner) as member> <@m.directoryLink member/><!--by Group--> </#list> <#else> <@m.orgManager owner?if_exists/><!--by Org--> </#if> </#list> </#if> <#else> <#if s.ercCategory=="Input the STR Number"||s.ercCategory=="STR"||s.ercCategory=="MSTR"> STR NO:<a href="${ercService.strLink?if_exists}${s.strEnNo?if_exists}" target="_blank">${s.strEnNo?if_exists}</a> is not effective <#else> EN NO:<a href="${ercService.enLink?if_exists}${s.strEnNo?if_exists}" target="_blank">${s.strEnNo?if_exists}</a> is not effective </#if> </#if> </td> <td><#if s.submitDate?exists>${s.submitDate?datetime?if_exists}</#if></td> <td>${s.purpose?default('')}</td> </tr> </#list> </#if> </tbody>

这段代码是使用 FreeMarker 模板引擎生成 HTML 表格内容的一部分,主要功能是根据分页数据展示请求表单的信息。以下是代码的详细分析: --- ### 1. **条件判断与循环** ```html <#if (paginationSupport.items)?has_content> ``` 判断 `paginationSupport.items` 是否存在且非空,只有存在数据时才执行表格渲染。 ```html <#list paginationSupport.items?sort_by('caseNo') as s> ``` 对 `paginationSupport.item
recommend-type

op-drone:监控未平仓头寸的市场利器

标题中提到的“op-drone”很可能是指一个特定的监控系统或服务的名称,它被用来“持续监控市场中的未平仓头寸”。未平仓头寸是指在金融市场上尚未完成交易结算的买卖双方的持仓数量。监控未平仓头寸对于市场参与者来说至关重要,因为它可以提供有关市场流动性和投资者情绪的重要信息。 在深入探讨之前,需要了解几个基础概念: 1. 未平仓头寸:指交易者在期货、期权、外汇或其他衍生品市场上建立的但尚未平仓的头寸。这些头寸在到期前仍然具有价值,而且市场上的价格变动会对它们的总体价值产生影响。 2. 持续监控:这通常是指使用软件工具或服务不断跟踪和分析市场数据的过程。持续监控可帮助交易者或市场分析师及时捕捉市场的动态变化,并根据最新情况做出交易决策。 3. 市场监控系统:这类系统通常具备收集实时数据、分析市场趋势、识别异常交易行为等多种功能。它们对于投资者了解市场状况、进行风险管理以及制定交易策略至关重要。 从描述中可以推断出,op-drone是一个专门用于持续监控未平仓头寸的系统或服务。这种系统需要具备以下功能: 1. 数据收集:系统需要有能力实时收集金融市场中的数据,包括但不限于期货、期权、股票、债券等金融产品的交易信息。 2. 数据分析:通过算法或机器学习技术分析收集到的数据,识别市场趋势、投资者行为模式以及潜在风险。 3. 异常检测:能够识别出市场中的异常交易活动,比如未平仓头寸的急剧变化,这可能是市场重大变动的前兆。 4. 风险预警:系统应能向用户发出风险预警,告知用户潜在的市场风险,帮助他们进行风险管理。 5. 报告与可视化:提供详细的数据报告和可视化图表,帮助用户更直观地理解市场状况和未平仓头寸变化。 此外,虽然文件中未提供标签和具体的文件名称列表,但可以推测“op-drone-main”可能是系统中的一个核心组件或主程序的名称。这个组件可能是整个op-drone系统运行的基础,负责处理大部分的监控和分析功能。 综合以上信息,我们可以得出一个结论:op-drone是一个专门设计用于监控金融市场上未平仓头寸的系统或服务。它可能具备实时数据收集和分析、异常行为识别、风险预警以及报告和可视化展示等多种功能,从而帮助用户在复杂的市场环境中做出更加明智的决策。对于需要精确把握市场动态、进行风险管理的金融分析师、交易员、投资组合经理等专业人士来说,这样的系统是不可或缺的工具。
recommend-type

RustWeb服务部署与环境变量配置全解析

### Rust Web 服务部署与环境变量配置全解析 在 Rust 开发中,完成业务逻辑编写后,将应用部署到生产环境是关键的下一步。本文将深入探讨 Rust 应用部署过程中的重要环节,包括环境变量的配置、二进制文件的优化以及跨平台编译等内容。 #### 1. 认证与授权相关未覆盖内容 在认证和授权方面,有一些内容未详细涉及。例如,设置会话数据库来存储令牌,以便在数据泄露或用户有其他需求时使令牌失效。可以通过设置 Redis 实例,在生成每个令牌时,不仅将结果返回给客户端,还将其存储在 Redis 键值存储中。 另外,重置用户密码和创建刷新令牌也是重要的话题。重置用户密码可以通过创建一个
recommend-type

消灭病毒 源代码

要查找消灭病毒游戏的源代码,可通过以下几种常见途径获取: ### 开源代码平台 - **GitHub**:作为全球最大的开源代码托管平台,有开发者会将自己开发的消灭病毒游戏源代码分享到上面。在GitHub的搜索框输入“消灭病毒游戏”相关关键词,如“Virus Elimination Game” 、“消灭病毒 Unity”等,就能筛选出相关的代码仓库。有些仓库可能是完整的项目,包含游戏开发所需的全部代码和资源;有些则可能是部分功能的实现,需要进一步整合。 - **Gitee**:国内的开源代码托管平台,很多国内开发者会将自己的项目上传至此。同样使用相关关键词搜索,或许能找到符合需求的消灭病毒游
recommend-type

Apache Directory:Java编写的LDAP v3兼容目录解决方案

标题中所提及的“directory”一词在IT领域有多种含义,而描述中提供了具体的上下文信息,即Apache Directory项目。这个项目是Apache软件基金会下的一个子项目,它提供了使用Java语言开发的开源目录服务解决方案。下面详细说明Apache Directory项目中涉及的知识点。 **Apache Directory项目知识点** 1. **目录服务(Directory Service)** - 目录服务是一种特殊类型的数据库,它主要用于存储关于网络中的对象信息,如用户、组、设备等,并使得这些信息可以被集中管理和查询。与传统的关系数据库不同,目录服务通常是为了读操作比写操作更频繁的应用场景优化的,这使得它特别适合用于存储诸如用户身份验证信息、配置数据、策略信息等。 2. **LDAP(轻量级目录访问协议)** - LDAP是目录服务使用的一种协议标准,它定义了客户端与目录服务进行交互的规则和方法。LDAP v3是LDAP协议的第三个版本,它在功能上比前两个版本更为强大和灵活。LDAP服务器通常被称为目录服务器(Directory Server),用于存储目录信息并提供查询服务。 3. **ApacheDS(Apache Directory Server)** - Apache Directory Server是Apache Directory项目的主要组件之一,是一个完全用Java编写的LDAP v3兼容的目录服务器。它符合LDAP标准的所有基本要求,还提供了丰富的可扩展性,如扩展协议操作、自定义属性类型、自定义操作等。它的设计目标是成为一个轻量级、易于使用且功能强大的目录服务器,特别适用于企业环境中的用户身份管理。 4. **认证和授权** - 在一个目录服务环境中,认证是指验证用户身份的过程,而授权是指授予已认证用户访问资源的权限。Apache Directory Server在设计上提供了对这些安全特性的支持,包括但不限于:密码策略、访问控制列表(ACLs)等。 5. **Eclipse和Apache Directory Studio** - Apache Directory Studio是一个基于Eclipse的开源集成开发环境(IDE),它专门为目录服务的开发和管理提供工具。它包含一个LDAP浏览器、一个LDIF编辑器、一个Schema编辑器等工具。开发者和管理员可以利用Apache Directory Studio来浏览和管理LDAP服务器,以及创建和修改LDAP条目和Schema。 6. **LDIF(LDAP数据交换格式)** - LDIF是LDAP数据交换的文件格式,用于在文本文件中表示LDAP目录的信息。它通常用于备份和恢复LDAP数据,以及将数据导入到LDAP目录中。Apache Directory API允许用户操作LDIF文件,为这些操作提供了丰富的接口。 **网络服务器与网络客户端** 网络服务器是位于服务器端的软件,负责处理来自客户端的请求,并将信息回传给客户端。网络客户端则是发起请求的软件,它连接到服务器并获取服务或数据。Apache Directory Server作为网络服务器的一个例子,为客户端提供目录服务的访问能力。这可能包括身份验证服务、数据检索服务等。网络客户端则需要使用适当的协议和API与目录服务器通信,例如使用LDAP协议。 **压缩包子文件的文件名称列表** 提供的文件名称“apache-ldap-api-1.0.3-bin”表明这是一个可执行的二进制包,其中包含了Apache Directory API的版本1.0.3。API通常包含了一系列用于与目录服务进行交互的类和方法。开发者可以使用这些API来编写代码,实现对LDAP服务器的管理操作,如查询、更新、删除和添加目录信息。 总结上述内容,Apache Directory项目是针对提供目录服务解决方案的开源项目,包括了Apache Directory Server作为服务器组件,和Apache Directory Studio作为客户端工具。项目遵守LDAP v3协议标准,并提供易于使用的API接口,使得开发者能够构建和管理一个高效、安全的目录服务环境。在使用过程中,了解LDAP协议、目录服务的安全机制以及相关的API使用是基础知识点。同时,由于Apache Directory项目采用Java语言编写,了解Java编程语言和其生态系统也对开发和部署相关服务有极大的帮助。
recommend-type

Rust项目中用户认证与登录功能的实现与优化

### Rust 项目中用户认证与登录功能的实现与优化 在开发 Web 应用时,用户认证是一个至关重要的环节。它涉及到用户密码的安全存储、账户注册时的重复错误处理以及登录逻辑的实现等多个方面。下面将详细介绍如何在 Rust 项目中实现这些功能。 #### 1. 密码哈希与加盐 为了确保用户密码的安全,我们不能直接存储明文密码。常见的做法是使用哈希算法对密码进行处理。不过,单纯的哈希还不够,因为攻击者可能通过比对已知破解的哈希列表来获取明文密码。因此,我们还需要对密码进行加盐处理,即在哈希之前添加一个随机生成的序列。 我们引入了两个新的 crate 来实现这个功能: - `rand`:用于