/******************************************************************************
* Copyright (c) 2015-2017 TP-Link Technologies CO.,LTD.
*
* �����: chm_ipaddr_manager.c
* �� ��: 1.0
* ժ Ҫ: ���������豸IP��ַ
* �� ��: qingbo<qingbo@tp-link.net>
* ����ʱ��: 2015-11-06
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/times.h>
#include <time.h>
#include <net/ethernet.h>
#include <linux/if_ether.h>
#include <net/if_arp.h>
#include "tp_timer.h"
#include "comm.h"
#include "raw_sock.h"
#include "arp.h"
#include "api.h"
#include "protocol.h"
#include "chm_default.h"
#include "chm_ubus.h"
#include "chm_common.h"
#include "chm_ipaddr_manager.h"
#include "chm_dev_manager.h"
#include "chm_dbg.h"
#include "recv_center.h"
/* IP��鳬ʱʱ�� 300ms */
#define IP_CHECK_TIMEOUT 300 * 1000
/*!<localnode��ubus���ø��£��˻���������g_node_buf{local_node/count/node_list} */
static pthread_mutex_t timer_lock = PTHREAD_MUTEX_INITIALIZER;
/*!<����ip��ͻ��Ϣ */
pthread_mutex_t ipcnflctinfo_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ipcnflctinfo_cond = PTHREAD_COND_INITIALIZER;
int localnode_freshed = 1;
/* ��㻺�棬��¼�����п��ýڵ��IP��MAC��ַ��Ϣ */
NODE_BUF g_node_buf[MAX_NETIF_NUM];
static RAW_SOCK g_raw_arp[MAX_NETIF_NUM];
/****************************************************************************
* Function : get_node_localhost
* Description: ��ñ�����ǰʵ�ʵ�IP�����������MAC��ַ
* Input : local : �����豸�����ṹָ��
* Output : N/A
* Return : ���ز������
****************************************************************************/
CHM_STATUS get_node_localhost(int ifidx, NET_NODE *local)
{
char ip_str[STR_IP_LEN] = {0};
char mask_str[STR_IP_LEN] = {0};
char mac_str[STR_MAC_LEN] = {0};
int32 ret = CHM_STATUS_ERROR;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx || !local)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument, node %p, ifidx %d\n", local, ifidx);
return CHM_STATUS_ARGS_INVALID;
}
if (!strlen(g_netif_info[ifidx].ifname))
{
CHM_DPRINTF(MSG_NOTICE, "eth %d not used\n", ifidx);
return CHM_STATUS_ERROR;
}
ret = get_local_ipaddr(g_netif_info[ifidx].ifname, ip_str);
if (ret != OK)
{
strncpy(ip_str, g_netif_info[ifidx].ip, STR_IP_LEN);
CHM_DPRINTF(MSG_NOTICE, "get local ip from g_netifd_info, ip = %s\n", ip_str);
}
else
{
strncpy(g_netif_info[ifidx].ip, ip_str, STR_IP_LEN);
CHM_DPRINTF(MSG_NOTICE, "g_netifd_info, ip = %s\n", ip_str);
}
IPv4_string2IPv4_dec(ip_str, &local->ip);
ret = get_local_netmask(g_netif_info[ifidx].ifname, mask_str);
if (ret != OK)
{
strncpy(mask_str, g_netif_info[ifidx].netmask, STR_IP_LEN);
CHM_DPRINTF(MSG_NOTICE, "get local netmask from g_netifd_info, mask = %s\n", mask_str);
}
else
{
strncpy(g_netif_info[ifidx].netmask, mask_str, STR_IP_LEN);
CHM_DPRINTF(MSG_NOTICE, "g_netifd_info, mask = %s\n", mask_str);
}
IPv4_string2IPv4_dec(mask_str, &local->mask);
ret = get_local_macaddr(g_netif_info[ifidx].ifname, mac_str);
if (ret != OK)
{
CHM_DPRINTF(MSG_NOTICE, "get local macaddr error\n");
return CHM_STATUS_ERROR;
}
mac_string2mac_hex(mac_str, local->mac_hex);
return CHM_STATUS_OK;
}
/****************************************************************************
* Function : find_node_buf_by_ip_addr
* Description: ��ѯָ��IP��ַ�Ƿ��ڽ�㻺����
* Input : ip : ָ��IP��ַ��ʮ������ʽ�������ֽ���
* Output : N/A
* Return : �ڻ����з��ض�Ӧ�����±꣬����-1
****************************************************************************/
int32 find_node_buf_by_ip_addr(int ifidx, u_int32 ip)
{
int32 id = -1;
u_int32 i = 0;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx)
{
return -1;
}
for (i = 0; i < g_node_buf[ifidx].count; i++)
{
if (g_node_buf[ifidx].node_list[i].node.ip == ip)
{
id = i;
break;
}
}
return id;
}
/****************************************************************************
* Function : ip_address_allocate
* Description: ��ڵ㻺��������õĽڵ�
* Input : ����IP(�������IP��С�ڸ�IP��ַ)��IP��ַָ��
* Output : N/A
* Return : �ɹ�����node_buf�±꣬����-1
****************************************************************************/
int32 ip_address_allocate(int ifidx, u_int32 base, u_int32 *ip)
{
struct in_addr in;
char ip_str[MAX_IP_STR_LEN] = {0};
char gateway_str[MAX_IP_STR_LEN] = {0};
int32 ret = -1;
int32 id = -1;
u_int32 i = 0;
u_int32 j = 0;
DEVICE_CONFIG *device = NULL;
if (!ip)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument\n");
return -1;
}
for (i = 0; i < g_node_buf[ifidx].count; i++)
{
if ((g_node_buf[ifidx].node_list[i].node.ip >= base))
{
break;
}
}
/* ��ȡNVR�����ص�ַ */
ret = get_local_gateway(ifidx, gateway_str);
if (ret != OK)
{
CHM_DPRINTF(MSG_DEBUG, "get local gateway failed.\n");
gateway_str[0] = '\0';
}
for (j = 0; j < g_node_buf[ifidx].count; j++)
{
i = i % g_node_buf[ifidx].count;
if (!g_node_buf[ifidx].node_list[i].flag)
{
memset(&in, 0, sizeof(in));
in.s_addr = htonl(g_node_buf[ifidx].node_list[i].node.ip);
inet_ntop(AF_INET, &in, ip_str, sizeof(ip_str));
/* ������IPC��IP��ַ��NVR��������ͬ */
if (!strcmp(gateway_str, ip_str))
{
i++;
continue;
}
device = device_find_in_device_list(SRH_KEY_TYPE_IP, ip_str);
if (device)
{
g_node_buf[ifidx].node_list[i].flag |= NODE_IP_ALLOCED;
i++;
continue;
}
ret = device_find_in_channel_list(SRH_KEY_TYPE_IP, ip_str);
if (ret < 0)
{
id = i;
*ip = g_node_buf[ifidx].node_list[i].node.ip;
g_node_buf[ifidx].node_list[i].flag |= NODE_IP_ALLOCED;
break;
}
}
i++;
}
return id;
}
/****************************************************************************
* Function : ip_address_clear_flag
* Description: ���flag
* Input : mask
* Output : N/A
* Return : �ɹ�����node_buf�±꣬����-1
****************************************************************************/
void ip_address_clear_flag(int ifidx, u_int32 mask)
{
u_int32 i = 0;
for (i = 0; i < g_node_buf[ifidx].count; i++)
{
g_node_buf[ifidx].node_list[i].flag &= (~mask);
}
return;
}
/****************************************************************************
* Function : ip_address_pool_reserve
* Description: Ԥ����IP��ַ�أ���ͨ��IP��ͻ�����ЩIP��ַ�Ƿ����
* Input : node_buf�ڵ㻺��
* Output : N/A
* Return : �������ɵ�IP��ַ
****************************************************************************/
void ip_address_pool_reserve(int ifidx, NODE_BUF *node_buf)
{
u_int32 i = 0;
u_int32 host = 0;
u_int32 max_count = MAX_IP_ADDR_NUM;
u_int32 gw_dec = 0;
NET_NODE *local = NULL;
char gateway_str[STR_IP_LEN] = {0};
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx || !node_buf)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument, node = NULL\n");
return;
}
local = &node_buf->local_node;
if (OK != get_local_gateway(ifidx, gateway_str))
{
return;
}
IPv4_string2IPv4_dec(gateway_str, &gw_dec);
/* ��������Ϊ32��ֱ�ӷ��� */
if ((~local->mask) == 0)
{
node_buf->count = 0;
CHM_DPRINTF(MSG_ERROR, "mask is 32 bits %02x\n", local->mask);
return;
}
/* Ԥ����IP��ַ������С��255������IP��ַ���� */
if (max_count > (~local->mask - 1))
{
max_count = ~local->mask - 1;
}
node_buf->count = 0;
host = local->ip & local->mask;
for (i = 0; i < max_count; i++)
{
host++;
/* Ԥ����IP��ַ������NVR��ַ��ͬ */
if (host == local->ip)
{
continue;
}
/* Ԥ����IP��ַ������������ͬ */
if (host == gw_dec)
{
continue;
}
node_buf->node_list[node_buf->count].node.ip = host;
node_buf->node_list[node_buf->count].node.mask = local->mask;
node_buf->node_list[node_buf->count].flag = 0;
memset((void *)node_buf->node_list[node_buf->count].node.mac_hex, 0, MAC_HEX_LEN);
node_buf->count++;
}
return;
}
/*!
*\fn ipcnflctinfo_add()
*\brief ip��ͻ��Ϣ��������mac.
*\details
*
*\param[in] node - �����ӽڵ��IP.
*\param[in] newmac - ������MAC.
*\param[out] N/A.
*
*\return int.
*\retval OK - �����ɹ�
*\ ERROR - ����ʧ��
*
*\note
*/
int ipcnflctinfo_add(int ifidx, u_int32 ip, char *newmac)
{
int id = 0;
int ret = 0;
int notify = 0;
NET_NODE_INFO *node = NULL;
IPCNFLCTINFO_NODE_T *p = NULL;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx)
{
return -1;
}
pthread_mutex_lock(&ipcnflctinfo_lock);
id = find_node_buf_by_ip_addr(ifidx, ip);
if ((id >= 0) && (id < MAX_IP_ADDR_NUM))
{
node = g_node_buf[ifidx].node_list + id;
if (!node)
{
ret = -1;
goto done;
}
}
else
{
ret = -1;
goto done;
}
/*!<��һ���ڵ�Ϊnode->node.mac_hex�����ⲻ������ͻҲ��̬���� */
if (memcmp(newmac, node->node.mac_hex, MAC_HEX_LEN) == 0)
{
ret = 0;
goto done;
}
p = node->head;
/*!<�Ȳ����Ƿ��Ѵ��� */
while (p != NULL)
{
if (memcmp(newmac, p->mac_hex, MAC_HEX_LEN) == 0)
{
break;
}
p = p->next;
}
/*!<�����ڣ������� */
if (p == NULL)
{
/*!<�����ӣ������������Ϣ */
notify = 1;
node->hostno++;
/*!<�յ���һ��mac */
if (node->hostno == 1)
{
node->flag |= NODE_RCV_ARP_RSP;
memcpy(node->node.mac_hex, newmac, MAC_HEX_LEN);
}
/*!<������ͻ */
else if (node->hostno >= 2)
{
p = (IPCNFLCTINFO_NODE_T *)chm_calloc(1, sizeof(IPCNFLCTINFO_NODE_T));
if (p == NULL)
{
CHM_DPRINTF(MSG_ERROR, "Calloc failed.");
ret = -1;
goto done;
}
memcpy(p->mac_hex, newmac, MAC_HEX_LEN);
p->next = node->head;
node->head = p;
node->flag |= NODE_IP_CONFLICT;
}
}
done:
pthread_mutex_unlock(&ipcnflctinfo_lock);
if (notify)
{
if (node)
{
CHM_DPRINTF(MSG_DEBUG, "ip %#x node->hostno %d, flag %d\r\n",
ip, node->hostno, node->flag);
}
else
{
CHM_DPRINTF(MSG_WARNING, "NULL node. ip %#x", ip);
}
}
return ret;
}
/*!
*\fn ipcnflctinfo_tobedel_tag()
*\brief ip��ͻ��Ϣ��ɾ��host mac����Ϊ����IP��δ��ɣ��������յ�host arp�ظ����ּӻ���������
* ��stage������IP��ɺ����ύ.
*\details
*
*\param[in] id - ����ǽڵ��ip.
*\param[in] hostmac - ���������MAC.
*\param[out] N/A.
*
*\return int.
*\retval OK - �����ɹ�
*\ ERROR - ����ʧ��
*
*\note
*/
int ipcnflctinfo_del_staged(int ifidx, u_int32 ip, char *hostmac)
{
int id = 0;
int ret = 0;
NET_NODE_INFO *node = NULL;
IPCNFLCTINFO_NODE_T *p = NULL;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx)
{
return -1;
}
pthread_mutex_lock(&ipcnflctinfo_lock);
id = find_node_buf_by_ip_addr(ifidx, ip);
if ((id >= 0) && (id < MAX_IP_ADDR_NUM))
{
node = g_node_buf[ifidx].node_list + id;
if (!node)
{
ret = -1;
goto done;
}
}
else
{
ret = -1;
goto done;
}
/*!<���ж��Ƿ�Ϊ��̬node */
if (memcmp(hostmac, node->node.mac_hex, MAC_HEX_LEN) == 0)
{
/*!<����ǣ���ʣ��ڵ����0�����ƶ�λ�� */
node->hostno--;
if (node->hostno > 0)
{
p = node->head;
/*!<�ҵ�һ��δstage�Ķ�̬�ڵ� */
while (p != NULL)
{
if (p->del_staged == 0)
{
break;
}
p = p->next;
}
/*!<�������� */
if (p != NULL)
{
char tmpmac[MAC_HEX_LEN];
memcpy(tmpmac, node->node.mac_hex, MAC_HEX_LEN);
memcpy(node->node.mac_hex, p->mac_hex, MAC_HEX_LEN);
memcpy(p->mac_hex, tmpmac, MAC_HEX_LEN);
p->del_staged = 1;
}
else
{
/*!<this should not happed, as node->hostno > 0 */
CHM_DPRINTF(MSG_ERROR, "Fatal error: NULL node. ip %#x.", ip);
node->node_del_staged = 1;
}
}
else
{
node->node_del_staged = 1;
}
}
/*!<���Ǿ�̬�ڵ㣬�ڶ�̬�ڵ��в��� */
else
{
p = node->head;
while (p != NULL)
{
if (memcmp(hostmac, p->mac_hex, MAC_HEX_LEN) == 0)
{
break;
}
p = p->next;
}
/*!<���ڣ����� */
if (p != NULL)
{
p->del_staged = 1;
node->hostno--;
}
}
/*!<ֻ����FLAG������ɾ���ڵ㣬Ҳ�����ͷ��ڴ� */
/*!<ֻʣ���һ��IP */
if (node->hostno == 1)
{
node->flag &= ~NODE_IP_CONFLICT;
}
/*!<���һ����ɾ���� */
else if (node->hostno == 0)
{
node->flag &= ~NODE_RCV_ARP_RSP;
}
done:
pthread_mutex_unlock(&ipcnflctinfo_lock);
if (node)
{
CHM_DPRINTF(MSG_DEBUG, "ip %#x node->hostno %d, flag %d\r\n",
ip, node->hostno, node->flag);
}
else
{
CHM_DPRINTF(MSG_WARNING, "NULL node. ip %#x\n", ip);
}
return ret;
}
/*!
*\fn ipcnflctinfo_del_revert()
*\brief ����del stage������ʹ�ָ�ԭ״̬.
*\details
*
*\param[in] N/A.
*\param[out] N/A.
*
*\return int.
*\retval OK - �����ɹ�
*\ ERROR - ����ʧ��
*
*\note
*/
int ipcnflctinfo_del_revert(int ifidx)
{
int i = 0;
int need_refresh = 0;
NET_NODE_INFO *node = NULL;
IPCNFLCTINFO_NODE_T *p = NULL;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx)
{
return -1;
}
pthread_mutex_lock(&ipcnflctinfo_lock);
for (i = 0; i < g_node_buf[ifidx].count; i++)
{
node = g_node_buf[ifidx].node_list + i;
/*!<����staged����Ϣ���ָ�hostno */
/*!<��һ���ڵ� */
if (node->node_del_staged)
{
node->node_del_staged = 0;
node->hostno++;
need_refresh = 1;
}
/*!<��ͻ��Ϣ�ڵ� */
p = node->head;
while (p != NULL)
{
if (p->del_staged)
{
p->del_staged = 0;
node->hostno++;
need_refresh = 1;
}
p = p->next;
}
/*!<����hostno������flag */
if (node->hostno >= 1)
{
node->flag |= NODE_RCV_ARP_RSP;
if (node->hostno >= 2)
{
node->flag |= NODE_IP_CONFLICT;
}
}
}
if (need_refresh) g_node_buf[ifidx].is_need_refreshall = 1;
pthread_mutex_unlock(&ipcnflctinfo_lock);
CHM_DPRINTF(MSG_DEBUG, "ipcnflctinfo_del_revert\r\n");
return 0;
}
/*!
*\fn ipcnflctinfo_free()
*\brief �ͷ�ip��ͻ��Ϣ.
*\details
*
*\param[in] node - IP�ڵ�.
*\param[out] N/A.
*
*\return int.
*\retval OK - �����ɹ�
*\ ERROR - ����ʧ��
*
*\note
*/
int ipcnflctinfo_free(NET_NODE_INFO *node)
{
IPCNFLCTINFO_NODE_T *q = NULL;
IPCNFLCTINFO_NODE_T *p = node->head;
pthread_mutex_lock(&ipcnflctinfo_lock);
while (p != NULL)
{
q = p;
p = p->next;
chm_free(q);
}
node->head = NULL;
node->hostno = 0;
pthread_mutex_unlock(&ipcnflctinfo_lock);
return 0;
}
/*!
*\fn ipcnflctinfo_freeall()
*\brief �ͷ����е�ipcnflctinfo�ڵ�.
*\details
*
*\param[in] N/A.
*\param[out] N/A.
*
*\return int.
*\retval OK - �����ɹ�
*\ ERROR - ����ʧ��
*
*\note
*/
int ipcnflctinfo_freeall(void)
{
int i = 0;
int j = 0;
for (i = 0; i < MAX_NETIF_NUM; i++)
{
for (j = 0; j < g_node_buf[i].count; j++)
{
ipcnflctinfo_free(g_node_buf[i].node_list + j);
}
}
return 0;
}
/****************************************************************************
* Function : device_ip_addr_configure
* Description: ���ý���б��е��豸IP��ַ�����֧����MAX_DEVICE_NUM·
�豸IP��ַ
* Input : list : �豸�б�
result : ��¼���ý����OK:�ɹ���ERROR:����
count : �����
* Output : N/A
* Return : �ɹ�����OK������ERROR
****************************************************************************/
CHM_STATUS device_ip_addr_configure(int ifidx, NET_NODE list[], int32 result[], u_int32 count)
{
int64 delta = 0;
int64 remain = 0;
u_int32 ah_sip = 0;
int32 i = 0;
int32 ret = OK;
chm_bool finished = false;
NET_NODE local;
RAW_SOCK raw_arp;
ARP_REQUEST request;
SET_IP_ADDR_PARAM param;
struct timeval tv;
struct timespec recv_bgn;
struct timespec recv_end;
ARP_HDR *ah = NULL;
if (ifidx < 0 || MAX_NETIF_NUM <= ifidx || !list || !result || count > MAX_DEVICE_NUM)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument\n");
return CHM_STATUS_ARGS_INVALID;
}
if (count == 0 || !strlen(g_netif_info[ifidx].ifname))
{
return CHM_STATUS_OK;
}
raw_arp.sock = raw_socket_init(ETH_P_ARP, g_netif_info[ifidx].ifname);
if (raw_arp.sock < 0)
{
CHM_DPRINTF(MSG_ERROR, "raw socket init error\n");
return CHM_STATUS_ALLOC_ERROR;
}
get_local_ipaddr(g_netif_info[ifidx].ifname, g_netif_info[ifidx].ip);
get_node_localhost(ifidx, &local);
get_local_gateway(ifidx, param.gateway_str);
IPv4_dec2IPv4_string(local.mask, param.mask_str);
mac_hex2mac_string(local.mac_hex, param.smac_str);
/* ����IPC IP��ַ */
for (i = 0; i < count; i++)
{
/* Ĭ������ʧ�� */
if (ifidx == list[i].ifidx)
{
result[i] = ERROR;
}
else
{
/*if not from this interface, ignore*/
//result[i] = OK;
continue;
}
if (strlen(list[i].password) == 0 && list[i].vender == VENDER_ID_HIKVISION
&& !strncmp(list[i].activate_status, "true", 4))
{
CHM_DPRINTF(MSG_DEBUG, "hikvision set ip with no password. \n");
continue;
}
IPv4_dec2IPv4_string(list[i].ip, param.ip_str);
mac_hex2mac_string(list[i].mac_hex, param.dmac_str);
param.vender = list[i].vender;
param.username = list[i].username;
param.password = list[i].password;
param.verify_data = list[i].veridy_data;
param.serial_number = list[i].serial_number;
param.encrypt_level = list[i].encrypt_level;
param.http_port = list[i].http_port;
param.ifidx = list[i].ifidx;
param.setip_with_pwd = list[i].setip_with_pwd;
CHM_DPRINTF(MSG_DEBUG, "send set ip:%s, mac = %s\n", param.ip_str, param.dmac_str);
ret = send_set_ipaddr_frame(¶m);
if (ret != OK)
{
CHM_DPRINTF(MSG_ERROR, "send set ip frame failed, mac = %s\n", param.dmac_str);
}
if (param.setip_with_pwd && ret == OK)
{
result[i] = param.error_code;
list[i].max_retry_count = param.max_retry_count;
list[i].remain_retry_count = param.remain_retry_count;
list[i].remain_time = param.remain_time;
}
}
/* ͨ��ARP��������Ƿ���� */
request.sip_dec = local.ip;
memcpy(request.smac_hex, local.mac_hex, MAC_HEX_LEN);
remain = sec2nanosec(IPADDR_SET_WAIT_TIMEOUT);
clock_gettime(CLOCK_MONOTONIC, &recv_bgn);
while (remain > 0)
{
/* ���ü����ɱ�־ */
finished = TRUE;
for (i = 0; i < count; i++)
{
/*if set ip success or not from this interface, don't send arp.*/
if (result[i] == OK || ifidx != list[i].ifidx)
{
continue;
}
if (strlen(list[i].password) == 0 && list[i].vender == VENDER_ID_HIKVISION
&& !strncmp(list[i].activate_status, "true", 4))
{
CHM_DPRINTF(MSG_DEBUG, "hikvision set ip with no password. don't send arp\n");
continue;
}
if (list[i].setip_with_pwd)
{
continue;
}
finished = FALSE;
request.tip_dec = list[i].ip;
ret = send_arp_request(&raw_arp, &request);
if (ret != OK)
{
CHM_DPRINTF(MSG_ERROR, "send arp frame failed, ip = %x\n", request.tip_dec);
}
}
if (finished == TRUE)
{
break;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
/* ����ARP���ģ�����Ƿ��г�ͻ���� */
while (1)
{
ret = recv_arp_packet(&raw_arp, &tv);
if (ret != OK)
{
break;
}
/* ��ʱ����δ�յ�ARP���� */
if (raw_arp.len == 0)
{
break;
}
ah = (ARP_HDR *)(raw_arp.rcv_buffer + sizeof(ETH_HEADER));
if (ntohs(ah->ar_op) == ARPOP_REPLY || ntohs(ah->ar_op) == ARPOP_REQUEST)
{
memcpy(&ah_sip, ah->ar_sip, IPv4_DEC_LEN);
ah_sip = ntohl(ah_sip);
}
else
{
continue;
}
for (i = 0; i < count; i++)
{
if (list[i].setip_with_pwd)
{
continue;
}
if (list[i].ip == ah_sip && !memcmp(list[i].mac_hex, ah->ar_sha, MAC_HEX_LEN))
{
result[i] = OK;
break;
}
}
}
clock_gettime(CLOCK_MONOTONIC, &recv_end);
delta = sec2nanosec(recv_end.tv_sec) + recv_end.tv_nsec
- (sec2nanosec(recv_bgn.tv_sec) + recv_bgn.tv_nsec);
recv_bgn.tv_sec = recv_end.tv_sec;
recv_bgn.tv_nsec = recv_end.tv_nsec;
remain -= delta;
}
close(raw_arp.sock);
return CHM_STATUS_OK;
}
/****************************************************************************
* Function : arp_request_send_timer
* Description: 1��IP��ͻ��ⶨʱ����������ARP Request���ͣ�target IPΪNVR IP
��node_buff IP��ַ��IP��
2����һ�߳��н���ARP RSP���IJ�����
* Input : param : �������
* Output : N/A
* Return : N/A
****************************************************************************/
void *arp_request_send_timerfunc(void *param)
{
int32 ret = CHM_STATUS_ERROR;
int32 i = 0;
chm_bool enabled = FALSE;
RTSP_CONN_STATUS conn_status = RTSP_CONN_S_UNKNOWN;
RAW_SOCK *temp = NULL;
RAW_SOCK raw_arp;
ARP_REQUEST request;
NET_NODE local;
/* node_buf IP�������Ϊ600s����ʱ����ʱ600/12�Σ��ŷ���ARP���� */
static u_int32 timer_counts = 0;
pthread_mutex_lock(&timer_lock);
temp = (RAW_SOCK *)param;
if (NULL == temp)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument\n");
goto done;
}
if (temp->sock == -1)
{
CHM_DPRINTF(MSG_ERROR, "invalid argument\n");
goto done;
}
raw_arp.sock = temp->sock;
raw_arp.ifidx = temp->ifidx;
timer_counts++;
if (temp->sock_reopen)
{
timer_counts = 0;
temp->sock_reopen = 0;
}
memset((void *)&local, 0, sizeof(local));
ret = get_node_localhost(raw_arp.ifidx, &local);
if (ret != CHM_STATUS_OK)
{
CHM_DPRINTF(MSG_DEBUG, "get_node_localhost failed\n");
if (CHM_STATUS_ARGS_INVALID == ret)
{
goto done;
}
/* �������IP��ͻ�澯�����澯ȡ�� */
if (g_node_buf[raw_arp.ifidx].cur_conflict == IP_CONFLICT_STATUS_TRUE)
{
g_node_buf[raw_arp.ifidx].cur_conflict = IP_CONFLICT_STATUS_FALSE;
record_ip_conflict_report(IP_CONFLICT_STATUS_FALSE);
}
goto done;
}
/* NVR IP��ַ�����������Ҫ���¸��µ�ַ�� */
if ((g_node_buf[raw_arp.ifidx].local_node.ip != local.ip)
|| (g_node_buf[raw_arp.ifidx].local_node.mask != local.mask)
|| g_node_buf[raw_arp.ifidx].is_need_refreshall)
{
g_node_buf[raw_arp.ifidx].is_need_refreshall = 0;
memcpy(&g_node_buf[raw_arp.ifidx].local_node, &local, sizeof(local));
g_node_buf[raw_arp.ifidx].cur_conflict = IP_CONFLICT_STATUS_FALSE;
ipcnflctinfo_freeall();
g_node_buf[raw_arp.ifidx].count = 0;
memset((void *)&g_node_buf[raw_arp.ifidx].node_list, 0, sizeof(g_node_buf[raw_arp.ifidx].node_list));
ip_address_pool_reserve(raw_arp.ifidx, &g_node_buf[raw_arp.ifidx]);
timer_counts = 0;
}
/* NVR IP��ͻ״̬��������澯 */
if (g_node_buf[raw_arp.ifidx].pre_conflict != g_node_buf[raw_arp.ifidx].cur_conflict)
{
record_ip_conflict_report(g_node_buf[raw_arp.ifidx].cur_conflict);
}
g_node_buf[raw_arp.ifidx].pre_conflict = g_node_buf[raw_arp.ifidx].cur_conflict;
g_node_buf[raw_arp.ifidx].cur_conflict = IP_CONFLICT_STATUS_FALSE;
/* ����NVR����ARP̽������ */
request.sip_dec = 0;
request.tip_dec = local.ip;
memcpy(request.smac_hex, local.mac_hex, MAC_HEX_LEN);
ret = send_arp_request(&raw_arp, &request);
if (ret != OK)
{
CHM_DPRINTF(MSG_NOTICE, "send arp request failed\n");
}
/* ����node_buf IP��ַ��IP ARP̽������ */
if (0 == timer_counts % (RESELVE_IP_DETECT_PERIOD / IP_CONFLICT_DETECT_PERIOD))
{
request.sip_dec = local.ip;
memcpy(request.smac_hex, local.mac_hex, MAC_HEX_LEN);
for (i = 0; i < g_node_buf[raw_arp.ifidx].count; i++)
{
g_node_buf[raw_arp.ifidx].node_list[i].flag = 0;
ipcnflctinfo_free(g_node_buf[raw_arp.ifidx].node_list + i);
memset((void *)&g_node_buf[raw_arp.ifidx].node_list[i].node.mac_hex, 0, MAC_HEX_LEN);
request.tip_dec = g_node_buf[raw_arp.ifidx].node_list[i].node.ip;
ret = send_arp_request(&raw_arp, &request);
if (ret != OK)
{
CHM_DPRINTF(MSG_ERROR, "send arp request failed, tip is %x\n", request.tip_dec);
}
}
}
/* ���NVR IP��ַ�����������Ҫ֪ͨRTSPֹͣ���� */
if ( (g_node_buf[raw_arp.ifidx].local_node.ip != 0)
&& (g_node_buf[raw_arp.ifidx].local_node.ip != local.ip || g_node_buf[raw_arp.ifidx].local_node.mask != local.mask) )
{
for (i = 0; i < MAX_CHANNEL_NUM; i++)
{
get_channel_enable(i, &enabled);
get_channel_connect_status(i, &conn_status);
if (enabled == TRUE && conn_status == RTSP_CONN_S_SUCCESS)
{
channel_rtsp_connect(i, CHANNEL_RTSP_M_STOP);
}
}
}
done:
pthread_mutex_unlock(&timer_lock);
if (0 == localnode_freshed)
{
pthread_mutex_lock(&ipcnflctinfo_lock);
localnode_freshed = 1;
pthread_cond_signal(&ipcnflctinfo_cond);
pthread_mutex_unlock(&ipcnflctinfo_lock);
}
return OK;
}
/****************************************************************************
* Function : arp_request_send_timer
* Description: ��ʼ��NVR IP��ַ��ͻ��ⶨʱ������ʱ���Ͳ�ѯ����IP��ַ��
ARP����
* Input :
* Output : N/A
* Return : �ɹ�����OK����������ERROR
****************************************************************************/
void *arp_request_send_timer(void *param)
{
if (!param)
{
CHM_DPRINTF(MSG_ERROR, "invalid ptr param:%p\n", param);
return NULL;
}
arp_request_send_timerfunc(param);
recv_center_add(RECV_CENTER_TIMER_FD, param, NULL, NULL, IP_CONFLICT_DETECT_PERIOD, arp_request_send_timer, RECV_CENTER_PRIO_UBUS);
return NULL;
}
/****************************************************************************
* Function : arp_request_send_timer_init
* Description: ��ʼ��NVR IP��ַ��ͻ��ⶨʱ������ʱ���Ͳ�ѯ����IP��ַ��
ARP����
* Input : timer : ��ʱ���ṹ
param : ��ʱ������
* Output : N/A
* Return : �ɹ�����OK����������ERROR
****************************************************************************/
CHM_STATUS arp_request_send_timer_init(void *param)
{
if (!param)
{
CHM_DPRINTF(MSG_ERROR, "invalid ptr param:%p\n", param);
return CHM_STATUS_ARGS_INVALID;
}
/* ����IP��ͻ��ⶨʱ�� */
recv_center_add(RECV_CENTER_TIMER_FD, param, NULL, NULL, 0, arp_request_send_timer, RECV_CENTER_PRIO_UBUS);
return CHM_STATUS_OK;
}
/****************************************************************************
* Function : ip_conflict_detect_thread
* Description: IP��ͻ����̣߳���ͻ������������:
(1) �������:��ʱ��ͨ��ARPЭ��������Ƿ����IP��ͻ
(2) �������:ʼ�ս��վ������ڵ�ARP�������ж��Ƿ����IP��ͻ
* Input : N/A
* Output : N/A
* Return : ��������±��̲߳��˳�
****************************************************************************/
void *ip_conflict_detect_thread(void *param)
{
NETIF_INFO *info = NULL;
RAW_SOCK *raw_arp;
struct timeval tv;
u_int32 ah_sip = 0;
u_int32 ah_tip = 0;
u_int32 ah_op = 0;
ARP_HDR *ah = NULL;
char rcv_buffer[RAW_PACKET_LEN_MAX];
int32 ret = CHM_STATUS_OK;
int index = 0;
pthread_detach(pthread_self());
set_thread_name("ipConflictDet");
if (!param)
{
return NULL;
}
index = *((int*)param);
chm_free(param);
info = &g_netif_info[index];
raw_arp = &g_raw_arp[index];
if (!strlen(info->ifname))
{
goto exit;
}
raw_arp->ifidx = get_netif_index(info);
if (-1 == raw_arp->ifidx)
{
goto exit;
}
raw_arp->sock = raw_socket_init(ETH_P_ARP, info->ifname);
if (raw_arp->sock < 0)
{
CHM_DPRINTF(MSG_ERROR, "raw socket init error\n");
goto exit;
}
/* ��ʼ��IP��ͻ��ⶨʱ�� */
arp_request_send_timer_init((void *)raw_arp);
while (1)
{
/* IP��ͻ��� */
tv.tv_sec = ARP_RECV_TIMEOUT_SEC;
tv.tv_usec = ARP_RECV_TIMEOUT_USEC;
/* ����ARP���ģ�����Ƿ��г�ͻ���� */
if (raw_arp->sock < 0)
{
raw_arp->sock = raw_socket_init(ETH_P_ARP, info->ifname);
if (raw_arp->sock < 0)
{
continue;
}
}
ret = recv_arp_packet(raw_arp, &tv);
if (ret != OK)
{
continue;
}
/* ��ʱ����δ�յ�ARP���� */
if (raw_arp->len == 0)
{
continue;
}
memcpy(rcv_buffer, raw_arp->rcv_buffer, sizeof(rcv_buffer));
ah = (ARP_HDR *)(rcv_buffer + sizeof(ETH_HEADER));
/* ��������������ΪREPLY��REQUEST��ARP���� */
ah_op = ntohs(ah->ar_op);
if (ah_op != ARPOP_REPLY
&& ah_op != ARPOP_REQUEST)
{
continue;
}
memcpy(&ah_sip, ah->ar_sip, IPv4_DEC_LEN);
ah_sip = ntohl(ah_sip);
memcpy(&ah_tip, ah->ar_tip, IPv4_DEC_LEN);
ah_tip = ntohl(ah_tip);
/* ������豸�б��Ƿ���ڳ�ͻ */
if (ah_sip == g_node_buf[raw_arp->ifidx].local_node.ip)
{
if (memcmp(g_node_buf[raw_arp->ifidx].local_node.mac_hex, ah->ar_sha, MAC_HEX_LEN))
{
g_node_buf[raw_arp->ifidx].cur_conflict = IP_CONFLICT_STATUS_TRUE;
}
continue;
}
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
else if(0 == ah_sip
&& ARPOP_REQUEST == ah_op
&& ah_tip == g_node_buf[raw_arp->ifidx].local_node.ip
&& memcmp(g_node_buf[raw_arp->ifidx].local_node.mac_hex, ah->ar_sha, MAC_HEX_LEN))
{
g_node_buf[raw_arp->ifidx].cur_conflict = IP_CONFLICT_STATUS_TRUE;
continue;
}
/* ����node IP��ַ�б�����ʾ�Ƿ��ͻ */
ipcnflctinfo_add(raw_arp->ifidx, ah_sip, (char*)ah->ar_sha);
}
close(raw_arp->sock);
exit:
pthread_exit(NULL);
return NULL;
}
/****************************************************************************
* Function : localnode_change_handler
* Description: IP��ͻ����̣߳���ͻ������������:
(1) �������:��ʱ��ͨ��ARPЭ��������Ƿ����IP��ͻ
(2) �������:ʼ�ս��վ������ڵ�ARP�������ж��Ƿ����IP��ͻ
* Input : N/A
* Output : N/A
* Return : ��������±��̲߳��˳�
****************************************************************************/
int localnode_change_handler(void)
{
int i = 0;
for (i = 0; i < MAX_NETIF_NUM; i++)
{
if (!strlen(g_netif_info[i].ifname))
{
continue;
}
g_raw_arp[i].ifidx = get_netif_index(&g_netif_info[i]);
if (-1 == g_raw_arp[i].ifidx)
{
continue;
}
if (g_raw_arp[i].sock)
{
close(g_raw_arp[i].sock);
}
g_raw_arp[i].sock = raw_socket_init(ETH_P_ARP, g_netif_info[i].ifname);
g_raw_arp[i].ifidx = i;
g_raw_arp[i].sock_reopen = 1;
localnode_freshed = 0;
/*!<��recv center����ִ��arp request func */
if (recv_center_add(RECV_CENTER_TIMER_FD, (void*)&g_raw_arp[i], NULL, NULL, 1, arp_request_send_timerfunc, RECV_CENTER_PRIO_UBUS))
{
CHM_DPRINTF(MSG_ERROR, "Add func to recv center failed.\n");
}
}
return OK;
}
/****************************************************************************
* Function : chm_ipaddr_manager_data_init
* Description: ��ʼ���������Լ�ȫ�ֱ���ֵ
* Input : N/A
* Output : N/A
* Return : �ɹ�����OK������ERROR
****************************************************************************/
static CHM_STATUS chm_ipaddr_manager_data_init()
{
int i = 0;
memset(g_node_buf, 0, sizeof(g_node_buf));
for (i = 0; i < MAX_NETIF_NUM; i++)
{
if (!strlen(g_netif_info[i].ifname))
{
continue;
}
ip_address_pool_reserve(i, &g_node_buf[i]);
}
return CHM_STATUS_OK;
}
/****************************************************************************
* Function : chm_ipaddr_manager_init
* Description: IP��ַ��ͻ���ģ���ʼ��
* Input : N/A
* Output : N/A
* Return : �ɹ�����OK,��������ERROR
****************************************************************************/
CHM_STATUS chm_ipaddr_manager_init()
{
pthread_t tid = -1;
int32 ret = CHM_STATUS_OK;
int i = 0;
/* ��ȡ�����豸���� */
load_network_config();
ret = chm_ipaddr_manager_data_init();
if (ret != CHM_STATUS_OK)
{
CHM_DPRINTF(MSG_FATAL, "chm ipaddr manager data lock init error\n");
return CHM_STATUS_ERROR;
}
for (i = 0; i < MAX_NETIF_NUM; i++)
{
memset(&g_raw_arp[i], 0, sizeof(RAW_SOCK));
}
for (i = 0; i < MAX_NETIF_NUM; i++)
{
int *p = (int *)chm_calloc(1, sizeof(int));
*p = i;
ret = pthread_create(&tid, NULL, ip_conflict_detect_thread, (void *)p);
if (ret)
{
CHM_DPRINTF(MSG_FATAL, "create thread \"ip_conflict_detect_thread\" failed\n");
return CHM_STATUS_ERROR;
}
}
return CHM_STATUS_OK;
}
int check_ip_conflict(u_int32 *ip_list, int *result, int num)
{
int ifidx;
RAW_SOCK raw_arp[MAX_NETIF_NUM] = {0};
ARP_REQUEST request;
NET_NODE local;
int ret;
int i;
struct timeval tv;
ARP_HDR *ah = NULL;
u_int32 ah_sip = 0;
int recv_num;
struct timespec recv_bgn;
struct timespec recv_end;
int64 time_use = 0;
if (!ip_list || !result)
{
return CHM_STATUS_ERROR;
}
for (ifidx = 0; ifidx < MAX_NETIF_NUM; ifidx++)
{
raw_arp[ifidx].sock = raw_socket_init(ETH_P_ARP, g_netif_info[ifidx].ifname);
if (raw_arp[ifidx].sock < 0)
{
CHM_DPRINTF(MSG_ERROR, "ifidx:%d raw socket init error\n", ifidx);
continue;
}
raw_arp[ifidx].ifidx = ifidx;
memset((void *)&local, 0, sizeof(local));
ret = get_node_localhost(raw_arp[ifidx].ifidx, &local);
if (ret != CHM_STATUS_OK)
{
CHM_DPRINTF(MSG_DEBUG, "get_node_localhost failed\n");
continue;
}
request.sip_dec = local.ip;
memcpy(request.smac_hex, local.mac_hex, MAC_HEX_LEN);
for (i = 0; i < num; i++)
{
request.tip_dec = ip_list[i];
ret = send_arp_request(&raw_arp[ifidx], &request);
if (ret != OK)
{
CHM_DPRINTF(MSG_ERROR, "send arp request failed, tip is %x\n", request.tip_dec);
}
}
}
for (ifidx = 0; ifidx < MAX_NETIF_NUM; ifidx++)
{
if (raw_arp[ifidx].sock < 0)
{
continue;
}
recv_num = 0;
clock_gettime(CLOCK_MONOTONIC, &recv_bgn);
while(1)
{
tv.tv_sec = 0;
tv.tv_usec = IP_CHECK_TIMEOUT;
ret = recv_arp_packet(&raw_arp[ifidx], &tv);
if (ret != OK)
{
CHM_DPRINTF(MSG_ERROR, "ifidx:%d recv err\n", ifidx);
break;
}
/* ��ʱ����δ�յ�ARP���� */
if (raw_arp[ifidx].len == 0)
{
CHM_DPRINTF(MSG_ERROR, "ifidx:%d recv none\n", ifidx);
break;
}
ah = (ARP_HDR *)(raw_arp[ifidx].rcv_buffer + sizeof(ETH_HEADER));
if (ntohs(ah->ar_op) == ARPOP_REPLY)
{
memcpy(&ah_sip, ah->ar_sip, IPv4_DEC_LEN);
ah_sip = ntohl(ah_sip);
}
else
{
continue;
}
for (i = 0; i < num; i++)
{
if (ip_list[i] == ah_sip)
{
result[i] = UBUS_ECODE_IP_CONFLICT;
CHM_DPRINTF(MSG_ERROR, "ifidx:%d i:%d target recv\n", ifidx, i);
recv_num++;
break;
}
}
if (recv_num == num)
{
CHM_DPRINTF(MSG_ERROR, "recv_num == num break\n");
break;
}
clock_gettime(CLOCK_MONOTONIC, &recv_end);
time_use = sec2nanosec(recv_end.tv_sec) + recv_end.tv_nsec - (sec2nanosec(recv_bgn.tv_sec) + recv_bgn.tv_nsec);
if (time_use > IP_CHECK_TIMEOUT*2)
{
CHM_DPRINTF(MSG_ERROR, "timeout break\n");
break;
}
}
close(raw_arp[ifidx].sock);
}
return CHM_STATUS_OK;
}
最新发布