/* Copyright(c) 2009-2025 Shenzhen TP-LINK Technologies Co.Ltd.
*
* file poe.c
* brief
* details
*
* author Liao Jinlei
* version 1.0.0
* date 04Mar25
*
* warning
*
* history \arg 1.0.0, 04Mar25, Liao Jinlei, Create the file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "type_pub.h"
#include "utility_debug.h"
#include "opLanPort_info.h"
#include "unix_sock_msgDef.h"
#include "apiPoeMP3924.h"
#include "poe_recovery.h"
/**************************************************************************************************/
/* DEFINES */
/**************************************************************************************************/
// #define DBG(args...) printf(args...)
// #define ERR(args...) printf(args...)
#define MAX_THREADS get_poe_last_uport() // 最大线程数限制: 2
#define ICMP_DATA_SIZE 56
#define MAX_ICMP_SIZE 1024
#define TIMEOUT 1000 // 超时时间(毫秒)
// @wxh dbg
// #define poe_recovery_init_setByWxh_l_array_poe_recovery_cfgs
/**************************************************************************************************/
/* TYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* EXTERN_PROTOTYPES */
/**************************************************************************************************/
/**************************************************************************************************/
/* LOCAL_PROTOTYPES */
/**************************************************************************************************/
// void poe_recovery_task(int *arg);
// static int _poe_auto_recovery_config_set(int user_port, const POE_PORTRECOVERYCFG_STRUCT* recovery_cfg); //@wxh 已重构优化,调用此函数处直接调用 ppoe_recovery_set_port_config 函数
// static int _poe_auto_recovery_config_del(int user_port); //@wxh 已重构优化,调用处直接赋值默认参数,并调用 ppoe_recovery_set_port_config
/**************************************************************************************************/
/* VARIABLES */
/**************************************************************************************************/
// 静态变量:指定IP地址
// static char* TARGET_IP_1 = "192.168.0.253"; //650-dt
// static char* TARGET_IP_2 = "192.168.0.26";
// 线程数组
pthread_t* l_array_poe_recovery_threads = NULL;
int* l_array_poe_recovery_ids = NULL; // 存储线程ID
POE_PORTRECOVERYCFG_STRUCT* l_array_poe_recovery_cfgs = NULL;
static int l_thread_count = 0; // 当前线程数量
static int l_poe_recovery_global_status = POE_RECOVERY_DISABLE_UC; /* 默认Disable */
/**************************************************************************************************/
/* LOCAL_FUNCTIONS */
/**************************************************************************************************/
// 创建原始套接字
static int _create_raw_socket() {
int raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (raw_socket < 0) {
perror("Socket creation failed");
return -1;
}
return raw_socket;
}
// 计算校验和
static unsigned short _calculate_checksum(void* b, int len) {
unsigned short* buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0; len > 1; len -= 2)
sum += *buf++;
if (len == 1)
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
// 发送 ICMP 回显请求
static int _ping_ip(int raw_socket, const char* ip_address, int seq,int user_port) {
struct sockaddr_in dest_addr;
struct icmp icmp_hdr;
char buffer[MAX_ICMP_SIZE];
int sent_bytes;
// 设置目标地址
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, ip_address, &dest_addr.sin_addr) <= 0) {
perror("Invalid IP address");
return -1;
}
// 构造 ICMP 数据包
memset(&icmp_hdr, 0, sizeof(icmp_hdr));
icmp_hdr.icmp_type = ICMP_ECHO;
icmp_hdr.icmp_code = 0;
icmp_hdr.icmp_id = getpid()+user_port*1000;
icmp_hdr.icmp_seq = seq;
icmp_hdr.icmp_cksum = 0;
// 填充数据部分
memset(buffer, 0, MAX_ICMP_SIZE);
memcpy(buffer, &icmp_hdr, sizeof(icmp_hdr));
memset(buffer + sizeof(icmp_hdr), 'E', ICMP_DATA_SIZE);
icmp_hdr.icmp_cksum = _calculate_checksum(buffer, sizeof(icmp_hdr) + ICMP_DATA_SIZE);
memcpy(buffer, &icmp_hdr, sizeof(icmp_hdr));
// 发送 ICMP 数据包
sent_bytes = sendto(raw_socket, buffer, sizeof(icmp_hdr) + ICMP_DATA_SIZE, 0,
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
if (sent_bytes < 0) {
perror("Sendto failed");
return -1;
}
return ERR_NO_ERROR;
}
// 获取 ICMP 回显应答
static int _get_ping_result(int raw_socket, const char* ip_address, int seq, int user_port) {
struct sockaddr_in from_addr;
struct icmp icmp_hdr;
char buffer[MAX_ICMP_SIZE];
int recv_bytes;
socklen_t from_len;
fd_set readfds;
struct timeval timeout;
// 设置超时时间
timeout.tv_sec = TIMEOUT / 1000;
timeout.tv_usec = (TIMEOUT % 1000) * 1000;
int retry = 5;
while(retry--)
{
// 等待 ICMP 回显应答
FD_ZERO(&readfds);
FD_SET(raw_socket, &readfds);
int activity = select(raw_socket + 1, &readfds, NULL, NULL, &timeout);
if ((activity < 0) && (errno != EINTR)) {
printf("Select error");
return -1;
}
if (activity == 0) {
printf("Ping request timed out\n");
return -1;
}
if (FD_ISSET(raw_socket, &readfds)) {
from_len = sizeof(from_addr);
recv_bytes = recvfrom(raw_socket, buffer, MAX_ICMP_SIZE, 0, (struct sockaddr*)&from_addr, &from_len);
if (recv_bytes < 0) {
perror("Recvfrom failed");
return -1;
}
// 解析 ICMP 数据包
memcpy(&icmp_hdr, buffer + sizeof(struct iphdr), sizeof(icmp_hdr));
if (icmp_hdr.icmp_type == ICMP_ECHOREPLY && icmp_hdr.icmp_id == (getpid()+user_port*1000) && icmp_hdr.icmp_seq == seq)
// if (icmp_hdr.icmp_type == ICMP_ECHOREPLY && icmp_hdr.icmp_id == (getpid()+user_port*1000))
{
printf("[success][PORT %d] Ping reply from %s: icmp_seq=%d\n",
user_port,inet_ntoa(from_addr.sin_addr), icmp_hdr.icmp_seq);
printf("[success][PORT %d] [actual] icmp_type: %d, icmp_id: %d, icmp_seq: %d\n", user_port,icmp_hdr.icmp_type,icmp_hdr.icmp_id ,icmp_hdr.icmp_seq );
printf("[success][PORT %d] [supose] icmp_type: %d, icmp_id: %d, icmp_seq: %d\n",user_port,ICMP_ECHOREPLY,(getpid()+user_port*1000),seq );
return ERR_NO_ERROR;
}
else
{
printf("[failed][PORT %d] Received unexpected ICMP packet\n",user_port);
printf("[failed][PORT %d] [actual] icmp_type: %d, icmp_id: %d, icmp_seq: %d\n", user_port,icmp_hdr.icmp_type,icmp_hdr.icmp_id ,icmp_hdr.icmp_seq );
printf("[failed][PORT %d] [supose] icmp_type: %d, icmp_id: %d, icmp_seq: %d\n",user_port,ICMP_ECHOREPLY,(getpid()+user_port*1000),seq );
// return -1;
}
}
}
return -1;
}
static int _poe_recovery_counter_command(int user_port, POE_RECOVERY_COUNTER_CMD cmd)
{
int rv = ERR_NO_ERROR;
if (user_port > get_poe_last_uport() || user_port < get_poe_first_uport() || l_array_poe_recovery_cfgs == NULL)
{
return ERR_BAD_PARAM;
}
// RECOVERY_TASK_LOCK();
switch (cmd)
{
case CLR_FAILURE:
l_array_poe_recovery_cfgs[user_port-1].failure = 0;
break;
case INC_FAILURE:
l_array_poe_recovery_cfgs[user_port-1].failure = (l_array_poe_recovery_cfgs[user_port-1].failure++ == POE_RECOVERY_FAILURE_MAX) ? 1 : l_array_poe_recovery_cfgs[user_port-1].failure;
break;
case INC_RESTART:
l_array_poe_recovery_cfgs[user_port-1].restart = (l_array_poe_recovery_cfgs[user_port-1].restart++ == POE_RECOVERY_RESTART_MAX) ? 1 : l_array_poe_recovery_cfgs[user_port-1].restart;
break;
case INC_TOTAL:
l_array_poe_recovery_cfgs[user_port-1].total = (l_array_poe_recovery_cfgs[user_port-1].total++ == POE_RECOVERY_TOTAL_MAX) ? 1 : l_array_poe_recovery_cfgs[user_port-1].total;
break;
case CLR_FAILURE_RESTART_TOTAL:
l_array_poe_recovery_cfgs[user_port-1].failure = 0;
l_array_poe_recovery_cfgs[user_port-1].restart = 0;
l_array_poe_recovery_cfgs[user_port-1].total = 0;
default:
rv = ERR_BAD_PARAM;
break;
}
// RECOVERY_TASK_UNLOCK();
return rv;
}
static int _poe_recovery_validate_port_config(const POE_PORTRECOVERYCFG_STRUCT *poe_port_recovery_cfg, int check_ip)
{
printf("_poe_recovery_validate_port_config will goto ping recovery %d\n", 5); // @wxh dbg
#if 0
if (check_ip && !sw_poe_recovery_ip_validate(poe_port_recovery_cfg->ip))
{
return FALSE;
}
#endif
if (poe_port_recovery_cfg->status != POE_RECOVERY_DISABLE_UC && poe_port_recovery_cfg->status != POE_RECOVERY_ENABLE_UC)
{
printf("[%s] ERR_BAD_PARAM: status.\r\n", __FUNCTION__);
return FALSE;
}
if (poe_port_recovery_cfg->startup < POE_RECOVERY_STARTUP_MIN || poe_port_recovery_cfg->startup > POE_RECOVERY_STARTUP_MAX)
{
printf("[%s] ERR_BAD_PARAM: startup.\r\n", __FUNCTION__);
return FALSE;
}
if (poe_port_recovery_cfg->interval < POE_RECOVERY_INTERVAL_MIN || poe_port_recovery_cfg->interval > POE_RECOVERY_INTERVAL_MAX)
{
printf("[%s] ERR_BAD_PARAM: interval.\r\n", __FUNCTION__);
return FALSE;
}
if (poe_port_recovery_cfg->retry < POE_RECOVERY_RETRY_MIN || poe_port_recovery_cfg->retry > POE_RECOVERY_RETRY_MAX)
{
printf("[%s] ERR_BAD_PARAM: retry.\r\n", __FUNCTION__);
return FALSE;
}
if (poe_port_recovery_cfg->reboot < POE_RECOVERY_BREAK_MIN || poe_port_recovery_cfg->reboot > POE_RECOVERY_BREAK_MAX)
{
printf("[%s] ERR_BAD_PARAM: reboot.\r\n", __FUNCTION__);
return FALSE;
}
return TRUE;
}
static int _poe_recovery_get_port_config(int user_port, POE_PORTRECOVERYCFG_STRUCT *poe_port_recovery_cfg)
{
if (user_port < get_poe_first_uport() || user_port > get_poe_last_uport() || NULL == poe_port_recovery_cfg)
{
return ERR_BAD_PARAM;
}
// RECOVERY_TASK_LOCK();
memcpy(poe_port_recovery_cfg, &l_array_poe_recovery_cfgs[user_port-1], sizeof(POE_PORTRECOVERYCFG_STRUCT));
// RECOVERY_TASK_UNLOCK();
return ERR_NO_ERROR;
}
/* set to local variable */
static int _poe_recovery_set_port_config(int user_port, const POE_PORTRECOVERYCFG_STRUCT *poe_port_recovery_cfg)
{
printf("_poe_recovery_set_port_config will goto ping recovery %d\n", 6); // @wxh dbg
if (NULL == poe_port_recovery_cfg || l_array_poe_recovery_cfgs == NULL)
{
return ERR_BAD_PARAM;
}
// RECOVERY_TASK_LOCK();
memset(l_array_poe_recovery_cfgs[user_port-1].ip, 0, 16);
snprintf(l_array_poe_recovery_cfgs[user_port-1].ip, 16, "%s", poe_port_recovery_cfg->ip);
l_array_poe_recovery_cfgs[user_port-1].status = poe_port_recovery_cfg->status;
l_array_poe_recovery_cfgs[user_port-1].startup = poe_port_recovery_cfg->startup;
l_array_poe_recovery_cfgs[user_port-1].interval = poe_port_recovery_cfg->interval;
l_array_poe_recovery_cfgs[user_port-1].retry = poe_port_recovery_cfg->retry;
l_array_poe_recovery_cfgs[user_port-1].reboot = poe_port_recovery_cfg->reboot;
// RECOVERY_TASK_UNLOCK();
return ERR_NO_ERROR;
}
static int _poe_recovery_get_global_status(int *status)
{
// RECOVERY_TASK_LOCK();
*status = l_poe_recovery_global_status;
// RECOVERY_TASK_UNLOCK();
return ERR_NO_ERROR;
}
/* set to local variable */
static int _poe_recovery_set_global_status(int status)
{
// RECOVERY_TASK_LOCK();
l_poe_recovery_global_status = status;
// RECOVERY_TASK_UNLOCK();
return ERR_NO_ERROR;
}
/*!
*\Function:
* _poe_port_status_set
*\Description:
* Port PoE status set api for PoE Auto Recovery
*\Input:
user_port - user port, start from 1
enable - status <POE_ENABLE_UC | POE_DISABLE_UC>
*\Output:
* n/a
*\Return:
Port PoE status set result
*\Note:
*/
static int _poe_port_status_set(unsigned int user_port, int enable)
{
// POE_PORTCFG_STRUCT poe_port_config = {0};
int rv = ERR_NO_ERROR;
int power_dis_flag = 0;
int time_seg_dis_flag = 0;
/* Check params */
if (user_port > get_poe_last_uport() || user_port < get_poe_first_uport())
{
printf("[%s] PoE function is unavailable on user_port %d.\r\n", __FUNCTION__, user_port);
return ERR_BAD_PARAM;
}
if (POE_DISABLE != enable && POE_ENABLE != enable)
{
return ERR_BAD_PARAM;
}
ad_poe_port_flag_get(user_port, POE_MANAGE_POWER_DIS, &power_dis_flag);
ad_poe_port_flag_get(user_port, POE_MANAGE_TIMESEG_DIS, &time_seg_dis_flag);
if (POE_RELEASE == power_dis_flag && POE_RELEASE == time_seg_dis_flag)
{
/* Update adapter config */
rv = ad_poe_set_port_state(user_port, enable);
if (ERR_NO_ERROR != rv)
{
return rv;
}
}
/* Update poe port flag */
return ad_poe_port_flag_set(user_port, POE_MANAGE_RECOVERY_DIS, (POE_DISABLE == enable) ? POE_OCCUPY : POE_RELEASE);
}
// 线程task
static void* poe_recovery_task(void* arg)
{
POE_PORTRECOVERYCFG_STRUCT poe_port_recovery_cfg;
int fail_cnt = 0;
int global_status;
int user_port = *(int*)arg;
int seq = 0;
if (user_port > get_poe_last_uport() || user_port < get_poe_first_uport())
{
return NULL;
}
/* PoE Auto Recovery Task主循环 */
while (1)
{
global_status = POE_RECOVERY_DISABLE_UC;
(void)_poe_recovery_get_global_status(&global_status);
_poe_recovery_get_port_config(user_port, &poe_port_recovery_cfg);
if (POE_RECOVERY_ENABLE_UC != poe_port_recovery_cfg.status || POE_RECOVERY_ENABLE_UC != global_status)
{
printf("[Port %d] PoE Auto Recovery disabled!\r\n", user_port);
sleep(1);
continue;
}
int raw_socket = _create_raw_socket();
if (raw_socket < 0) {
printf("Thread %d: Failed to create socket\n", user_port);
return NULL;
}
printf("Thread %d: raw_socket is %d \n", user_port,raw_socket);
printf("[Port %d] Startup: %d secnonds...\r\n", user_port, poe_port_recovery_cfg.startup);
sleep(poe_port_recovery_cfg.startup);
/* PoE Auto Recovery工作循环,检测到Enable才进入 */
while (1)
{
global_status = POE_RECOVERY_DISABLE_UC;
(void)_poe_recovery_get_global_status(&global_status);
_poe_recovery_get_port_config(user_port, &poe_port_recovery_cfg);
if (POE_RECOVERY_ENABLE_UC != poe_port_recovery_cfg.status || POE_RECOVERY_ENABLE_UC != global_status)
{
printf("[Port %d] PoE Auto Recovery disabled!\r\n", user_port);
break;
}
//ping target ip
if (_ping_ip(raw_socket, poe_port_recovery_cfg.ip, seq, user_port) < 0)
{
printf("[Port %d] Failed to send ping to %s, try again.\r\n", user_port, poe_port_recovery_cfg.ip);
sleep(3);
continue;
}
_poe_recovery_counter_command(user_port, INC_TOTAL);
if (_get_ping_result(raw_socket, poe_port_recovery_cfg.ip, seq, user_port) < 0)
{
printf("Thread %d: Ping failed for %s\r\n", user_port, poe_port_recovery_cfg.ip);
fail_cnt++;
_poe_recovery_counter_command(user_port, INC_FAILURE);
printf("[Port %d] Ping FAIL: total=%d, failure=%d, fail_cnt=%d\r\n",
user_port, poe_port_recovery_cfg.total+1, poe_port_recovery_cfg.failure+1, fail_cnt);
}
else
{
printf("Thread %d: Ping success for %s\n", user_port, poe_port_recovery_cfg.ip);
fail_cnt=0;
_poe_recovery_counter_command(user_port, CLR_FAILURE);
printf("[Port %d] Ping SUCCESS: total=%d, failure=%d, fail_cnt=%d.\r\n",
user_port, poe_port_recovery_cfg.total+1, poe_port_recovery_cfg.failure, fail_cnt);
}
seq++;
if (fail_cnt >= poe_port_recovery_cfg.retry)
{
printf("[Port %d] Ping: fail_cnt reaches the limit(%d), now reboot pd.(Reboot Time: %d seconds)\r\n",
user_port, poe_port_recovery_cfg.retry, poe_port_recovery_cfg.reboot);
fail_cnt = 0;
_poe_recovery_counter_command(user_port, CLR_FAILURE);
_poe_recovery_counter_command(user_port, INC_RESTART);
_poe_port_status_set(user_port, POE_DISABLE);
// ad_poe_set_port_state(user_port, POE_DISABLE);
sleep(poe_port_recovery_cfg.reboot);
_poe_port_status_set(user_port, POE_ENABLE);
// ad_poe_set_port_state(user_port, POE_ENABLE);
break;
}
printf("[Port %d] Ping: wait %d seconds for next ping...\r\n\n", user_port, poe_port_recovery_cfg.interval);
sleep(poe_port_recovery_cfg.interval - POE_RECOVERY_PING_TIMEOUT);
}
close(raw_socket);
}
}
// 创建线程
static int poe_recovery_task_create_thread(int user_port) {
// printf("poe_recovery_task_create_thread will goto ping recovery %d \n", 7); // @wxh dbg
//@wxh 勘误修改 l_thread_count代表创建的线程数 应该小于等于2,这里 >= 应改为 > 符号
// if (l_thread_count >= MAX_THREADS) {
if (l_thread_count > MAX_THREADS) {
printf("Error: Maximum number of l_array_poe_recovery_threads reached (%d)\n", MAX_THREADS);
return -1;
}
printf("poe_recovery_task_create_thread thread ID:%d \n",user_port);
if (user_port < get_poe_first_uport() || user_port > get_poe_last_uport()) {
printf("Error: Invalid thread ID \n");
return -1;
}
if (l_array_poe_recovery_ids[user_port-1] != POE_RECOVERY_THREAD_NOT_USE) {
printf("Error: Thread ID %d is already in use\n", user_port);
return -1;
}
int* arg = malloc(sizeof(int));
if (!arg) {
perror("Memory allocation failed");
return -1;
}
*arg = user_port;
if (pthread_create(&l_array_poe_recovery_threads[user_port-1], NULL, poe_recovery_task, arg) != 0) {
perror("Failed to create thread");
free(arg);
return -1;
}
l_array_poe_recovery_ids[user_port-1] = POE_RECOVERY_THREAD_IN_USE; // 标记线程ID为已使用
_poe_recovery_counter_command(user_port, CLR_FAILURE_RESTART_TOTAL);
l_thread_count++;
//todo
// stats[user_port] = (PingStats){0, 0, 0}; // 初始化统计信息
printf("Thread for user_port %d created successfully\n", user_port);
return ERR_NO_ERROR;
}
// 关闭线程
static int poe_recovery_task_destroy_thread(int user_port) {
// @wxh 勘误修改 这里的 >= 会导致取消线程2时报错,导致线程2无法被取消,应该改为 >
// if (user_port < 0 || user_port >= MAX_THREADS) {
if (user_port <0 || user_port > MAX_THREADS) {
printf("Error: Invalid thread ID\n");
return -1;
}
if (l_array_poe_recovery_ids[user_port-1] == POE_RECOVERY_THREAD_NOT_USE) {
printf("Error: Thread ID %d does not exist\n", user_port);
return -1;
}
if (pthread_cancel(l_array_poe_recovery_threads[user_port-1]) != 0) {
perror("Failed to cancel thread");
return -1;
}
pthread_join(l_array_poe_recovery_threads[user_port-1], NULL);
l_array_poe_recovery_ids[user_port-1] = POE_RECOVERY_THREAD_NOT_USE; // 标记线程ID为未使用
_poe_recovery_counter_command(user_port, CLR_FAILURE_RESTART_TOTAL);
l_thread_count--;
printf("Thread %d canceled successfully\n", user_port);
return ERR_NO_ERROR;
}
/*
// 清理所有线程
static void poe_recovery_task_cleanup_threads() {
int i;
for (i = get_poe_first_uport(); i <= get_poe_last_uport(); i++)
{
if (l_array_poe_recovery_ids[i-1] != POE_RECOVERY_THREAD_NOT_USE)
{
pthread_cancel(l_array_poe_recovery_threads[i-1]);
pthread_join(l_array_poe_recovery_threads[i-1], NULL);
}
}
}
*/
/**************************************************************************************************/
/* PUBLIC_FUNCTIONS */
/**************************************************************************************************/
//set port config to local variable
int poe_recovery_set_port_config( int user_port, const POE_PORTRECOVERYCFG_STRUCT *poe_port_recovery_cfg, int check_ip)
{
int rv = 0;
int global_status;
// POE_PORTCFG_STRUCT poe_port_cfg;
POE_PORTRECOVERYCFG_STRUCT poe_port_recovery_cfg_old;
printf("[%s] enter on port %d.\r\n", __FUNCTION__, user_port);
/* check param legality */
if (user_port < get_poe_first_uport() || user_port > get_poe_last_uport() || NULL == poe_port_recovery_cfg)
{
printf("[%s][port %d] ERR_BAD_PARAM: user_port.\r\n", __FUNCTION__, user_port);
return ERR_BAD_PARAM;
}
/* check poe config */
// sw_poe_get_port_config(user_port, &poe_port_cfg);
_poe_recovery_get_port_config(user_port, &poe_port_recovery_cfg_old);
printf("[%s] done _poe_recovery_get_port_config on port %d.\r\n", __FUNCTION__, user_port);
/*
todo:when port not enable poe,shoule return.
if (poe_port_recovery_cfg_old.status == POE_RECOVERY_DISABLE_UC
&& poe_port_recovery_cfg->status == POE_RECOVERY_ENABLE_UC
&& poe_port_cfg.status == POE_DISABLE)
{
// sprintf(buff, "port %d", user_port);
// swPoeAddLogSinglePara(LOG_POE_RECOVERY_CONFIG_SET_FAIL, (ULONG)buff);
return ERR_POE_RECOVERY_POE_DISABLED;
}
*/
/* validate configuration */
if (!_poe_recovery_validate_port_config(poe_port_recovery_cfg, check_ip))
{
printf("[%s][port %d] ERR_BAD_PARAM: user_port.\r\n", __FUNCTION__, user_port);
return ERR_BAD_PARAM;
}
rv = _poe_recovery_set_port_config(user_port, poe_port_recovery_cfg); //更新参数到了 l_array_poe_recovery_cfgs
if (ERR_NO_ERROR != rv)
{
printf("[%s][port %d] _poe_recovery_set_port_config ERROR.\r\n", __FUNCTION__, user_port);
return rv;
}
/* create/destroy poe recovery task */
/* 全局enable的情况下,端口enable/disable触发task创建/销毁 */
/* 全局disable的情况下,端口enable/disable只改变参数,后续全局enable/disable时再创建/销毁线程 */
rv = _poe_recovery_get_global_status(&global_status);
if (rv != ERR_NO_ERROR) {
return rv;
}
/* 未更改之前的逻辑,对端口的 status 变化有响应,对端口的其他5个参数变化没有相应 */
// if (poe_port_recovery_cfg_old.status != poe_port_recovery_cfg->status && POE_RECOVERY_ENABLE_UC == global_status)
// {
// printf("poe_port_recovery_cfg_old.status = %u\n", poe_port_recovery_cfg_old.status); //@wxh dbg
// printf("poe_port_recovery_cfg->status = %u\n", poe_port_recovery_cfg->status); //@wxh dbg
// printf("POE_RECOVERY_ENABLE_UC = %d\n", POE_RECOVERY_ENABLE_UC); //@wxh dbg
// printf("global_status = %d\n", global_status); //@wxh dbg
// /* enable -> disable */
// if (poe_port_recovery_cfg_old.status == POE_RECOVERY_ENABLE_UC)
// {
// rv = poe_recovery_task_destroy_thread(user_port);
// if (ERR_NO_ERROR != rv)
// {
// return rv;
// }
// }
// /* disable -> enable */
// else
// {
// rv = poe_recovery_task_create_thread(user_port);
// if (ERR_NO_ERROR != rv)
// {
// printf("@@@@@ poe_recovery_task_create_thread failure\n");
// return rv;
// }
// printf("@@@@@ poe_recovery_task_create_thread sucess\n");
// }
// }
if (POE_RECOVERY_ENABLE_UC == global_status)
{
printf("[%s][port %d] POE_RECOVERY_ENABLE_UC == global_status\r\n", __FUNCTION__, user_port);
printf("[%s][port %d] poe_port_recovery_cfg_old.status = %d \r\n", __FUNCTION__, user_port,poe_port_recovery_cfg_old.status);
printf("[%s][port %d] poe_port_recovery_cfg->status = %d \r\n", __FUNCTION__, user_port,poe_port_recovery_cfg->status);
if (poe_port_recovery_cfg_old.status != poe_port_recovery_cfg->status)
{
// printf("poe_port_recovery_cfg_old.status = %u\n", poe_port_recovery_cfg_old.status); //@wxh dbg
// printf("poe_port_recovery_cfg->status = %u\n", poe_port_recovery_cfg->status); //@wxh dbg
// printf("POE_RECOVERY_ENABLE_UC = %d\n", POE_RECOVERY_ENABLE_UC); //@wxh dbg
// printf("global_status = %d\n", global_status); //@wxh dbg
/* enable -> disable */
if (poe_port_recovery_cfg_old.status == POE_RECOVERY_ENABLE_UC)
{
printf("----->---- [%s] /* disable -> enable */\n", __FUNCTION__); //@wxh dbg
rv = poe_recovery_task_destroy_thread(user_port);
if (ERR_NO_ERROR != rv)
{
return rv;
}
}
/* disable -> enable */
else
{
printf("----->---- [%s] /* disable -> enable */\n", __FUNCTION__); //@wxh dbg
rv = poe_recovery_task_create_thread(user_port);
if (ERR_NO_ERROR != rv)
{
printf("----->---- poe_recovery_task_create_thread failure\n");
return rv;
}
printf("----->---- poe_recovery_task_create_thread sucess\n");
}
}
/*
@wxh 新旧的端口 status 都为 POE_RECOVERY_ENABLE_UC 时,改变ip、startup、interval、retry、reboot 5个参数时
需要销毁线程,并且重新创建线程来使这些更新的参数生效。
*/
else
{
/* @wxh 当5个参数中的任意一个参数发生变化时,销毁线程,重新创建线程来使这些更新的参数生效 */
printf("[%s][port %d] goto else\r\n", __FUNCTION__, user_port);
if (POE_RECOVERY_ENABLE_UC == poe_port_recovery_cfg_old.status)
{
if (0 != strcmp(poe_port_recovery_cfg_old.ip, poe_port_recovery_cfg->ip) ||
poe_port_recovery_cfg_old.startup != poe_port_recovery_cfg->startup ||
poe_port_recovery_cfg_old.interval != poe_port_recovery_cfg->interval ||
poe_port_recovery_cfg_old.retry != poe_port_recovery_cfg->retry ||
poe_port_recovery_cfg_old.reboot != poe_port_recovery_cfg->reboot)
{
printf("---->---- 除status的5个参数(ip startup interval retry reboot )发生变化,销毁线程,重新创建线程\n");
printf("---->---->---- old param poe_port_recovery_cfg_old: status:%d ip:%s interval:%d startup:%d retry:%d reboot:%d\n",
poe_port_recovery_cfg_old.status, poe_port_recovery_cfg_old.ip, poe_port_recovery_cfg_old.interval,
poe_port_recovery_cfg_old.startup, poe_port_recovery_cfg_old.retry, poe_port_recovery_cfg_old.reboot);
printf("---->---->---- new param poe_port_recovery_cfg: status:%d ip:%s interval:%d startup:%d retry:%d reboot:%d\n",
poe_port_recovery_cfg->status, poe_port_recovery_cfg->ip, poe_port_recovery_cfg->interval,
poe_port_recovery_cfg->startup, poe_port_recovery_cfg->retry, poe_port_recovery_cfg->reboot);
rv |= poe_recovery_task_destroy_thread(user_port);
if (ERR_NO_ERROR != rv)
{
printf("---->---->---- poe_recovery_task_destroy_thread failure\n");
}
printf("---->---->---- poe_recovery_task_create_thread sucess\n");
rv |= poe_recovery_task_create_thread(user_port);
if (ERR_NO_ERROR != rv)
{
printf("---->---->---- poe_recovery_task_create_thread failure\n");
}
printf("---->---->---- poe_recovery_task_create_thread sucess\n");
}
}
}
}
else
{
printf("---->---- [%s] poe recovery set port but l_poe_recovery_global_status is POE_RECOVERY_DISABLE_UC\n", __FUNCTION__);
printf("---->---- in poe_port_recovery_cfg: status:%d ip:%s interval:%d startup:%d retry:%d reboot:%d\n",
poe_port_recovery_cfg->status, poe_port_recovery_cfg->ip, poe_port_recovery_cfg->interval,
poe_port_recovery_cfg->startup, poe_port_recovery_cfg->retry, poe_port_recovery_cfg->reboot);
}
//@wxh 如果 port recovery status 是enable状态,此时上层api 将其中的ip 、interval、startup 等值改变了如何处理?
printf("[%s][port %d] end.\r\n", __FUNCTION__, user_port);
return ERR_NO_ERROR;
}
int poe_auto_recovery_global_set(int status)
{
int user_port, rv, global_status;
POE_PORTRECOVERYCFG_STRUCT poe_port_recovery_cfg;
if (POE_RECOVERY_DISABLE_UC != status && POE_RECOVERY_ENABLE_UC != status)
{
return ERR_BAD_PARAM;
}
if (0 == get_include_poe_auto_recovery())
{
printf("[%s] not support auto recovery\n", __FUNCTION__);
return ERR_NO_ERROR;
}
rv = _poe_recovery_get_global_status(&global_status);
if (rv != ERR_NO_ERROR)
{
return rv;
}
if (status != global_status)
{
/* update 全局变量 l_poe_recovery_global_status */
_poe_recovery_set_global_status(status);
/* enable -> disable */
if (POE_RECOVERY_DISABLE_UC == status)
{
printf("####**&&** in [%s] /* enable -> disable */\n", __FUNCTION__);
for (user_port = get_poe_first_uport(); user_port <= get_poe_last_uport(); user_port++)
{
rv = poe_recovery_task_destroy_thread(user_port);
if (ERR_NO_ERROR != rv)
{
return rv;
}
}
}
/* disable -> enable */
else
{
printf("####**&&** in [%s] /* disable -> enable */\n", __FUNCTION__);
for (user_port = get_poe_first_uport(); user_port <= get_poe_last_uport(); user_port++)
{
/* Check poe recovery config */
_poe_recovery_get_port_config(user_port, &poe_port_recovery_cfg);
printf("####**&&** in [%s] _poe_recovery_get_port_config, result:\n", __FUNCTION__);
printf("[port %d] status:%d ip:%s interval:%d startup:%d retry:%d reboot:%d\n", poe_port_recovery_cfg.port_no,
poe_port_recovery_cfg.status, poe_port_recovery_cfg.ip, poe_port_recovery_cfg.interval,
poe_port_recovery_cfg.startup, poe_port_recovery_cfg.retry, poe_port_recovery_cfg.reboot);
if (POE_RECOVERY_ENABLE_UC == poe_port_recovery_cfg.status)
{
rv = poe_recovery_task_create_thread(user_port);
if (ERR_NO_ERROR != rv)
{
printf("####**&&** poe_recovery_task_create_thread failure\n");
return rv;
}
printf("####**&&** poe_recovery_task_create_thread sucess\n");
}
else
{
printf("####**&&** poe_port_recovery_cfg.status != POE_RECOVERY_ENABLE_UC\n");
printf("####**&&** poe_port_recovery_cfg.status = %d\n", poe_port_recovery_cfg.status);
}
}
}
}
printf("[%s] Recovery status changed to %d \n", __FUNCTION__, status);
return ERR_NO_ERROR;
}
int poe_auto_recovery_global_get(int* status)
{
if( NULL == status )
{
return ERR_BAD_PARAM;
}
if (0 == get_include_poe_auto_recovery())
{
printf("[%s] not support auto recovery\n", __FUNCTION__);
return ERR_NO_ERROR;
}
_poe_recovery_get_global_status(status);
// printf("[%s] get Recovery status: %d \n", __FUNCTION__, *status);
return ERR_NO_ERROR;
}
//once set one port
int poe_auto_recovery_config_set(const POE_OUT_MSG *in_info)
{
POE_PORTRECOVERYCFG_STRUCT* port_cfg = (POE_PORTRECOVERYCFG_STRUCT*)in_info->data.poe_recovery_port_cfg;
POE_PORTRECOVERYCFG_STRUCT recovery_cfg = {0};
int user_port = port_cfg->port_no;
int rv = 0;
if (0 == get_include_poe_auto_recovery())
{
printf("[%s] not support auto recovery\n", __FUNCTION__);
return ERR_NO_ERROR;
}
if (user_port < get_poe_first_uport() || user_port > get_poe_last_uport())
{
printf("Input port_id:%d is invalid\n", user_port);
return -1;
}
printf("####ppoe_auto_recovery_config_set in [%s] port:%d\n status:%d ip:%s\n interval:%d\n startup:%d\n retry:%d\n reboot:%d\n failure:%d\n restart:%d\n total:%d\n",__FUNCTION__, port_cfg->port_no,
port_cfg->status,port_cfg->ip,port_cfg->interval,port_cfg->startup,port_cfg->retry,port_cfg->reboot,port_cfg->failure,port_cfg->restart,port_cfg->total);
recovery_cfg.status = port_cfg->status; // POE_RECOVERY_STATUS_UC status; /* PoE Recovery使能 */
snprintf(recovery_cfg.ip, 16, "%s", port_cfg->ip); //char ip[IP_STR_LEN]; /* Ping IP Address */
recovery_cfg.startup = port_cfg->startup; // int startup; /* Startip Delay (seconds) */
recovery_cfg.interval = port_cfg->interval; // int interval; /* Interval (seconds) */
recovery_cfg.retry = port_cfg->retry; // int retry; /* Failure Threshold */
recovery_cfg.reboot = port_cfg->reboot; // int reboot; /* Break Time (seconds)*/
recovery_cfg.failure = port_cfg->failure; // int failure; /* Failures */
recovery_cfg.restart = port_cfg->restart; // int restart; /* Restarts */
recovery_cfg.total = port_cfg->total; // int total; /* Total */
rv = poe_recovery_set_port_config(user_port, &recovery_cfg, TRUE);
if (rv != ERR_NO_ERROR)
printf("[%s]Set auto recovery port%d failed\n", __FUNCTION__, user_port);
return ERR_NO_ERROR;
}
//@wxh 已重构优化
//once set one port
int poe_auto_recovery_config_del(const POE_OUT_MSG *in_info)
{
POE_PORTRECOVERYCFG_STRUCT* port_cfg = (POE_PORTRECOVERYCFG_STRUCT*)in_info->data.poe_recovery_port_cfg;
int user_port = port_cfg->port_no;
int rv = 0;
POE_PORTRECOVERYCFG_STRUCT recovery_cfg = {0};
if (0 == get_include_poe_auto_recovery())
{
printf("[%s] not support auto recovery\n", __FUNCTION__);
return ERR_NO_ERROR;
}
if (user_port < get_poe_first_uport() || user_port > get_poe_last_uport())
{
printf("Input port_id:%d is invalid\n", user_port);
return -1;
}
/* 设置为默认参数 */
recovery_cfg.startup = POE_RECOVERY_STARTUP;
recovery_cfg.interval = POE_RECOVERY_INTERVAL;
recovery_cfg.retry = POE_RECOVERY_RETRY;
recovery_cfg.reboot = POE_RECOVERY_REBOOT;
recovery_cfg.status = POE_RECOVERY_DISABLE_UC;
rv = poe_recovery_set_port_config(user_port, &recovery_cfg, FALSE);
if (rv != ERR_NO_ERROR)
printf("[%s]Del auto recovery port%d failed\n", __FUNCTION__, user_port);
return rv;
}
//@wxh 已重构优化
int poe_auto_recovery_status_get(POE_OUT_MSG *out_info)
{
POE_PORTRECOVERYCFG_STRUCT recovery_cfg = {0};
// POE_PORTRECOVERYCFG_STRUCT* cur_out_port_cfg = out_info->data.poe_recovery_port_cfg;
int user_port = 0;
if (0 == get_include_poe_auto_recovery())
{
printf("[%s] not support auto recovery\n", __FUNCTION__);
return ERR_NO_ERROR;
}
for (user_port = get_poe_first_uport(); user_port <= get_poe_last_uport(); user_port++)
{
_poe_recovery_get_port_config(user_port, &recovery_cfg);
out_info->data.poe_recovery_port_cfg[user_port - 1].port_no = user_port; /* 端口号 */
out_info->data.poe_recovery_port_cfg[user_port - 1].status = recovery_cfg.status; /* PoE Recovery使能 */
// strcpy(out_info->data.poe_recovery_port_cfg[user_port - 1].ip, recovery_cfg.ip); // char ip[IP_STR_LEN]; /* Ping IP Address */
// strcpy(out_info->data.poe_recovery_port_cfg[user_port - 1].ip, "192.168.0.253"); // char ip[IP_STR_LEN]; /* Ping IP Address */ 使用strcpy不安全,应该用snprintf
snprintf(out_info->data.poe_recovery_port_cfg[user_port - 1].ip, 16, "%s", recovery_cfg.ip); //char ip[IP_STR_LEN]; /* Ping IP Address */
out_info->data.poe_recovery_port_cfg[user_port - 1].startup = recovery_cfg.startup; /* Startip Delay (seconds) */
out_info->data.poe_recovery_port_cfg[user_port - 1].interval = recovery_cfg.interval; /* Interval (seconds) */
out_info->data.poe_recovery_port_cfg[user_port - 1].retry = recovery_cfg.retry; /* Failure Threshold */
out_info->data.poe_recovery_port_cfg[user_port - 1].reboot = recovery_cfg.reboot; /* Break Time (seconds)*/
out_info->data.poe_recovery_port_cfg[user_port - 1].failure = recovery_cfg.failure; /* Failures */
out_info->data.poe_recovery_port_cfg[user_port - 1].restart = recovery_cfg.restart; /* Restarts */
out_info->data.poe_recovery_port_cfg[user_port - 1].total = recovery_cfg.total; /* Total */
}
return ERR_NO_ERROR;
}
int poe_recovery_init(void)
{
printf("goto poe_recovery_init\n"); //@wxh dbg
// int user_port = 0;
int user_port = 1; //@wxh 根据apiPoeMP3924.c user_port - user_port, start from 1
// POE_PORTRECOVERYCFG_STRUCT recovery_cfg = {0};
// int status = -1;
// int rv = 0;
for (user_port = get_poe_first_uport(); user_port <= get_poe_last_uport(); user_port++)
{
/* init recovery flag */
ad_poe_port_flag_set(user_port, POE_MANAGE_RECOVERY_DIS, POE_RELEASE);
}
if (0 == get_include_poe_auto_recovery())
{
return ERR_NO_ERROR;
}
//todo ?
/* poe auto recoevry need to load ping module first */
// sw_ping_init();
l_array_poe_recovery_threads = (pthread_t *)malloc(sizeof(pthread_t)*get_poe_last_uport());
l_array_poe_recovery_ids = (int *)malloc(sizeof(int)*get_poe_last_uport());
l_array_poe_recovery_cfgs = (POE_PORTRECOVERYCFG_STRUCT *)malloc(sizeof(POE_PORTRECOVERYCFG_STRUCT)*get_poe_last_uport());
memset(l_array_poe_recovery_cfgs, 0, sizeof(POE_PORTRECOVERYCFG_STRUCT) * get_poe_last_uport());
// poe_recovery_id = (pal_thread_t *)POE_ALLOC(sizeof(pal_thread_t)*get_poe_last_uport());
for (user_port = get_poe_first_uport(); user_port <= get_poe_last_uport(); user_port++)
{
/* init thread id */
// printf("l_array_poe_recovery_ids[%d] = POE_RECOVERY_THREAD_NOT_USE; \n",user_port-1);
l_array_poe_recovery_ids[user_port-1] = POE_RECOVERY_THREAD_NOT_USE;
}
printf("Start to load and set userconfig for auto recovery.\n");
printf("in swPoeOut.c sw_poeOut_init load flash data and set auto recovery\n");
return ERR_NO_ERROR;
}
/**************************************************************************************************/
/* GLOBAL_FUNCTIONS */
/**************************************************************************************************/
画出一个流程图,专业的解释我这段代码里面的ping检测功能
最新发布