blob: 83d58e20e54f5559c2e5bf6ed8a0ffe0b95f2e48 [file] [log] [blame]
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2019 RDK Management
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h> /* ioctl() */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>
#include <linux/if.h> /* struct ifreq */
#include <stdbool.h>
#include "ccsp_hal_ethsw.h"
/**********************************************************************
DEFINITIONS
**********************************************************************/
#define CcspHalEthSwTrace(msg) printf("%s - ", __FUNCTION__); printf msg;
#define MAX_BUF_SIZE 1024
#define MACADDRESS_SIZE 6
#define LM_ARP_ENTRY_FORMAT "%63s %63s %63s %63s %17s %63s"
#define ETH_WAN_INTERFACE "erouter0"
#define ETH_WAN_IFNAME "eth2"
#if defined(FEATURE_RDKB_WAN_MANAGER)
static pthread_t ethsw_tid;
static int hal_init_done = 0;
appCallBack ethWanCallbacks;
#define ETH_INITIALIZE "/tmp/ethagent_initialized"
void *ethsw_thread_main(void *context __attribute__((unused)));
#endif
#define ETHSWITCHTOOL "ethtool"
#define MIITOOL "mii_mgr_cl45"
#define WANLINKUP "0x796D"
#define MAX_LAN_PORT 6
/**********************************************************************
MAIN ROUTINES
**********************************************************************/
CCSP_HAL_ETHSW_ADMIN_STATUS admin_status;
int is_interface_exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
int is_interface_link(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
char buf[32] = {0};
fgets(buf,sizeof(buf),file);
fclose(file);
if(strtol(buf, NULL, 10))
return 1;
}
return 0;
}
/* CcspHalEthSwInit : */
/**
* @description Do what needed to intialize the Eth hal.
* @param None
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwInit
(
void
)
{
#if defined(FEATURE_RDKB_WAN_MANAGER)
int rc;
if (hal_init_done) {
return RETURN_OK;
}
// Create thread to handle async events and callbacks.
rc = pthread_create(&ethsw_tid, NULL, ethsw_thread_main, NULL);
if (rc != 0) {
return RETURN_ERR;
}
hal_init_done = 1;
#endif
return RETURN_OK;
}
/* CcspHalEthSwGetPortStatus : */
/**
* @description Retrieve the current port status -- link speed, duplex mode, etc.
* @param PortId -- Port ID as defined in CCSP_HAL_ETHSW_PORT
* @param pLinkRate -- Receives the current link rate, as in CCSP_HAL_ETHSW_LINK_RATE
* @param pDuplexMode -- Receives the current duplex mode, as in CCSP_HAL_ETHSW_DUPLEX_MODE
* @param pStatus -- Receives the current link status, as in CCSP_HAL_ETHSW_LINK_STATUS
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwGetPortStatus
(
CCSP_HAL_ETHSW_PORT PortId,
PCCSP_HAL_ETHSW_LINK_RATE pLinkRate,
PCCSP_HAL_ETHSW_DUPLEX_MODE pDuplexMode,
PCCSP_HAL_ETHSW_LINK_STATUS pStatus
)
{
char path[32] = {0};
FILE *fp = NULL;
char cmd[64] = {0};
char filepath[32] = {0};
char buf[32] = {0};
char duplex[6] = {0};
int link = 0;
int speed = 0;
char ifName[16] = {0};
if(PortId == NULL || pLinkRate == NULL || pDuplexMode == NULL || pStatus == NULL)
return RETURN_ERR;
if(PortId < 1 || PortId > MAX_LAN_PORT)
return RETURN_ERR;
#ifdef THREE_GMACS_SUPPORT
if(PortId == 5){
sprintf(ifName,"%s", "eth3");
}else
#endif
{
sprintf(ifName, "lan%d", (PortId-1));
}
sprintf(path, "/sys/class/net/%s/carrier", ifName);
link = is_interface_link(path);
if(link){
*pStatus = CCSP_HAL_ETHSW_LINK_Up;
}else{
*pStatus = CCSP_HAL_ETHSW_LINK_Down;
*pLinkRate = CCSP_HAL_ETHSW_LINK_NULL;
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Auto;
return RETURN_OK;
}
sprintf(cmd, "%s %s | grep -i speed > /tmp/%s_speed", ETHSWITCHTOOL, ifName, ifName);
system(cmd);
sprintf(filepath, "/tmp/%s_speed", ifName);
fp = fopen(filepath, "r");
if(fp != NULL)
{
fgets(buf,sizeof(buf),fp);
if(strstr(buf,"Unknown") == NULL){
sscanf(buf," Speed: %dMb/s", &speed);
}
fclose(fp);
}else{
*pLinkRate = CCSP_HAL_ETHSW_LINK_NULL;
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Auto;
return RETURN_OK;
}
if(speed)
{
memset(buf,0,sizeof(buf));
memset(cmd,0,sizeof(cmd));
memset(filepath,0,sizeof(filepath));
sprintf(cmd, "%s %s | grep -i duplex > /tmp/%s_duplex", ETHSWITCHTOOL, ifName, ifName);
system(cmd);
sprintf(filepath, "/tmp/%s_duplex", ifName);
fp = fopen(filepath, "r");
if(fp != NULL)
{
fgets(buf,sizeof(buf),fp);
if(strstr(buf,"Unknown") == NULL){
sscanf(buf," Duplex: %s", duplex);
}
fclose(fp);
if(!strcmp(duplex,"Full"))
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Full;
else
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Half;
}
}
switch (speed)
{
case 0:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_Auto;
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Auto;
break;
}
case 10:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_10Mbps;
break;
}
case 100:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_100Mbps;
break;
}
case 1000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_1Gbps;
break;
}
case 2500:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_2_5Gbps;
break;
}
case 5000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_5Gbps;
break;
}
case 10000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_10Gbps;
break;
}
default:
{
CcspHalEthSwTrace(("Unsupported link rate %d port id %d\n",speed, PortId));
return RETURN_ERR;
}
}
return RETURN_OK;
}
/* CcspHalEthSwGetPortCfg : */
/**
* @description Retrieve the current port config -- link speed, duplex mode, etc.
* @param PortId -- Port ID as defined in CCSP_HAL_ETHSW_PORT
* @param pLinkRate -- Receives the current link rate, as in CCSP_HAL_ETHSW_LINK_RATE
* @param pDuplexMode -- Receives the current duplex mode, as in CCSP_HAL_ETHSW_DUPLEX_MODE
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwGetPortCfg
(
CCSP_HAL_ETHSW_PORT PortId,
PCCSP_HAL_ETHSW_LINK_RATE pLinkRate,
PCCSP_HAL_ETHSW_DUPLEX_MODE pDuplexMode
)
{
FILE *fp = NULL;
char cmd[64] = {0};
char filepath[32] = {0};
char buf[32] = {0};
char duplex[6] = {0};
int speed = 0;
char ifName[16] = {0};
if(PortId == NULL || pLinkRate == NULL || pDuplexMode == NULL)
return RETURN_ERR;
if(PortId < 1 || PortId > MAX_LAN_PORT)
return RETURN_ERR;
#ifdef THREE_GMACS_SUPPORT
if(PortId == 5){
sprintf(ifName,"%s", "eth3");
}else
#endif
{
sprintf(ifName, "lan%d", (PortId-1));
}
sprintf(cmd, "%s %s | grep -i speed > /tmp/%s_speed", ETHSWITCHTOOL, ifName, ifName);
system(cmd);
sprintf(filepath, "/tmp/%s_speed", ifName);
fp = fopen(filepath, "r");
if(fp != NULL)
{
fgets(buf,sizeof(buf),fp);
if(strstr(buf,"Unknown") == NULL){
sscanf(buf," Speed: %dMb/s", &speed);
}
fclose(fp);
}else{
*pLinkRate = CCSP_HAL_ETHSW_LINK_NULL;
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Auto;
return RETURN_OK;
}
if(speed)
{
memset(buf,0,sizeof(buf));
memset(cmd,0,sizeof(cmd));
memset(filepath,0,sizeof(filepath));
sprintf(cmd, "%s %s | grep -i duplex > /tmp/%s_duplex", ETHSWITCHTOOL, ifName, ifName);
system(cmd);
sprintf(filepath, "/tmp/%s_duplex", ifName);
fp = fopen(filepath, "r");
if(fp != NULL)
{
fgets(buf,sizeof(buf),fp);
if(strstr(buf,"Unknown") == NULL){
sscanf(buf," Duplex: %s", duplex);
}
fclose(fp);
if(!strcmp(duplex,"Full"))
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Full;
else
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Half;
}
}
switch (speed)
{
case 0:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_Auto;
*pDuplexMode = CCSP_HAL_ETHSW_DUPLEX_Auto;
break;
}
case 10:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_10Mbps;
break;
}
case 100:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_100Mbps;
break;
}
case 1000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_1Gbps;
break;
}
case 2500:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_2_5Gbps;
break;
}
case 5000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_5Gbps;
break;
}
case 10000:
{
*pLinkRate = CCSP_HAL_ETHSW_LINK_10Gbps;
break;
}
default:
{
CcspHalEthSwTrace(("Unsupported link rate %d port id %d\n",speed, PortId));
return RETURN_ERR;
}
}
return RETURN_OK;
}
/* CcspHalEthSwSetPortCfg : */
/**
* @description Set the port configuration -- link speed, duplex mode
* @param PortId -- Port ID as defined in CCSP_HAL_ETHSW_PORT
* @param LinkRate -- Set the link rate, as in CCSP_HAL_ETHSW_LINK_RATE
* @param DuplexMode -- Set the duplex mode, as in CCSP_HAL_ETHSW_DUPLEX_MODE
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwSetPortCfg
(
CCSP_HAL_ETHSW_PORT PortId,
CCSP_HAL_ETHSW_LINK_RATE LinkRate,
CCSP_HAL_ETHSW_DUPLEX_MODE DuplexMode
)
{
CcspHalEthSwTrace(("set port %d LinkRate to %d, DuplexMode to %d", PortId, LinkRate, DuplexMode));
if(PortId < 1 || PortId > MAX_LAN_PORT)
return RETURN_ERR;
char cmd[128] = {0};
char setduplex[6] = {0};
char ifName[16] = {0};
if(DuplexMode == 2 || DuplexMode == 0)
strcpy(setduplex,"full");
else if (DuplexMode == 1)
strcpy(setduplex,"half");
else
return RETURN_ERR;
#ifdef THREE_GMACS_SUPPORT
if(PortId == 5){
sprintf(ifName,"%s", "eth3");
}else
#endif
{
sprintf(ifName, "lan%d", (PortId-1));
}
switch (LinkRate)
{
case CCSP_HAL_ETHSW_LINK_10Mbps:
{
sprintf(cmd,"%s -s %s speed %d duplex %s", ETHSWITCHTOOL, ifName, 10, setduplex);
system(cmd);
break;
}
case CCSP_HAL_ETHSW_LINK_100Mbps:
{
sprintf(cmd,"%s -s %s speed %d duplex %s", ETHSWITCHTOOL, ifName, 100, setduplex);
system(cmd);
break;
}
case CCSP_HAL_ETHSW_LINK_1Gbps:
{
sprintf(cmd,"%s -s %s speed %d duplex full", ETHSWITCHTOOL, ifName, 1000);
system(cmd);
break;
}
case CCSP_HAL_ETHSW_LINK_2_5Gbps:
case CCSP_HAL_ETHSW_LINK_5Gbps:
case CCSP_HAL_ETHSW_LINK_10Gbps:
case CCSP_HAL_ETHSW_LINK_Auto:
{
sprintf(cmd,"%s -s %s autoneg on", ETHSWITCHTOOL, ifName);
system(cmd);
break;
}
default:
{
CcspHalEthSwTrace(("Unsupported link rate %d port id %d\n",LinkRate, PortId));
return RETURN_ERR;
}
}
return RETURN_OK;
}
/* CcspHalEthSwGetPortAdminStatus : */
/**
* @description Retrieve the current port admin status.
* @param PortId -- Port ID as defined in CCSP_HAL_ETHSW_PORT
* @param pAdminStatus -- Receives the current admin status
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwGetPortAdminStatus
(
CCSP_HAL_ETHSW_PORT PortId,
PCCSP_HAL_ETHSW_ADMIN_STATUS pAdminStatus
)
{
if(PortId == NULL || pAdminStatus == NULL)
return RETURN_ERR;
CcspHalEthSwTrace(("port id %d", PortId));
if(PortId < 1 || PortId > MAX_LAN_PORT)
return RETURN_ERR;
int sockfd;
struct ifreq ifr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("====> open socket fail \n");
return RETURN_ERR;
}
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", "eth1");
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
{
printf("====> ioctl open socket fail \n");
close(sockfd);
return RETURN_ERR;
}
close(sockfd);
if(ifr.ifr_flags & IFF_UP)
*pAdminStatus = CCSP_HAL_ETHSW_AdminUp;
else
*pAdminStatus = CCSP_HAL_ETHSW_AdminDown;
if(admin_status)
*pAdminStatus = CCSP_HAL_ETHSW_AdminDown;
return RETURN_OK;
}
/* CcspHalEthSwSetPortAdminStatus : */
/**
* @description Set the ethernet port admin status
* @param AdminStatus -- set the admin status, as defined in CCSP_HAL_ETHSW_ADMIN_STATUS
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwSetPortAdminStatus
(
CCSP_HAL_ETHSW_PORT PortId,
CCSP_HAL_ETHSW_ADMIN_STATUS AdminStatus
)
{
CcspHalEthSwTrace(("set port %d AdminStatus to %d", PortId, AdminStatus));
if(AdminStatus < CCSP_HAL_ETHSW_AdminUp || AdminStatus > CCSP_HAL_ETHSW_AdminTest)
return RETURN_ERR;
if(PortId < 1 || PortId > MAX_LAN_PORT)
return RETURN_ERR;
char cmd1[32] = {0};
char cmd2[32] = {0};
char interface[8] = {0};
char path[32] = {0};
strcpy(path,"/sys/class/net/eth1");
int eth_if=is_interface_exists(path);
if(eth_if == 0 )
return RETURN_ERR;
strcpy(interface,"eth1");
sprintf(cmd1,"ip link set %s up",interface);
sprintf(cmd2,"ip link set %s down",interface);
switch (PortId)
{
case CCSP_HAL_ETHSW_EthPort1:
case CCSP_HAL_ETHSW_EthPort2:
case CCSP_HAL_ETHSW_EthPort3:
case CCSP_HAL_ETHSW_EthPort4:
{
{
if(AdminStatus==0)
{
system(cmd1);
admin_status=0;
}
else
{
//system(cmd2);
admin_status=1;
}
}
break;
}
default:
CcspHalEthSwTrace(("Unsupported port id %d", PortId));
return RETURN_ERR;
}
return RETURN_OK;
}
/* CcspHalEthSwSetAgingSpeed : */
/**
* @description Set the ethernet port configuration -- admin up/down, link speed, duplex mode
* @param PortId -- Port ID as defined in CCSP_HAL_ETHSW_PORT
* @param AgingSpeed -- integer value of aging speed
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwSetAgingSpeed
(
CCSP_HAL_ETHSW_PORT PortId,
INT AgingSpeed
)
{
CcspHalEthSwTrace(("set port %d aging speed to %d", PortId, AgingSpeed));
if(AgingSpeed < 0 || AgingSpeed > 300)
return RETURN_ERR;
if(PortId < 1)
return RETURN_ERR;
return RETURN_OK;
}
/* CcspHalEthSwLocatePortByMacAddress : */
/**
* @description Retrieve the port number that the specificed MAC address is associated with (seen)
* @param pMacAddr -- Specifies the MAC address -- 6 bytes
* @param pPortId -- Receives the found port number that the MAC address is seen on
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
* @execution Synchronous.
* @sideeffect None.
*
* @note This function must not suspend and must not invoke any blocking system
* calls. It should probably just send a message to a driver event handler task.
*
*/
INT
CcspHalEthSwLocatePortByMacAddress
(
unsigned char * pMacAddr,
INT * pPortId
)
{
if (pMacAddr == NULL)
return RETURN_ERR;
CcspHalEthSwTrace
((
"%s -- search for MAC address %02x:%02x:%02x:%02x:%02x:%02x",
__FUNCTION__,
pMacAddr[0], pMacAddr[1], pMacAddr[2],
pMacAddr[3], pMacAddr[4], pMacAddr[5]
));
char cmd[128] = {0};
char buf[128] = {0};
char foundmac[18] = {0};
int port = 0;
FILE *fp = NULL;
sprintf(foundmac,"%02x:%02x:%02x:%02x:%02x:%02x",pMacAddr[0], pMacAddr[1], pMacAddr[2], pMacAddr[3], pMacAddr[4], pMacAddr[5]);
snprintf(cmd,128, "bridge fdb show | grep %s | awk '$0 ~ /master/{print $3} '", foundmac);
fp = popen(cmd, "r");
if(fp != NULL)
{
if(fgets(buf,sizeof(buf),fp) != NULL)
{
pclose(fp);
if (strncmp(buf, "lan",3))
{
#ifdef THREE_GMACS_SUPPORT
if (!strncmp(buf, "eth3",4))
{
*pPortId = 5;
return RETURN_OK;
}
#endif
return RETURN_ERR;
}else{
sscanf(buf,"lan%d",&port);
*pPortId = port+1;
return RETURN_OK;
}
}
pclose(fp);
}
return RETURN_ERR;
}
//For Getting Current Interface Name from corresponding hostapd configuration
void GetInterfaceName(char *interface_name, char *conf_file)
{
FILE *fp = NULL;
char path[MAX_BUF_SIZE] = {0},output_string[MAX_BUF_SIZE] = {0},fname[MAX_BUF_SIZE] = {0};
int count = 0;
char *interface = NULL;
fp = fopen(conf_file, "r");
if(fp == NULL)
{
printf("conf_file %s not exists \n", conf_file);
return;
}
fclose(fp);
sprintf(fname,"%s%s%s","cat ",conf_file," | grep interface=");
fp = popen(fname,"r");
if(fp == NULL)
{
printf("Failed to run command in Function %s\n",__FUNCTION__);
strcpy(interface_name, "");
return;
}
if(fgets(path, sizeof(path)-1, fp) != NULL)
{
interface = strchr(path,'=');
if(interface != NULL)
strncpy(output_string, interface+1, sizeof(output_string));
}
for(count = 0;output_string[count]!='\n';count++)
interface_name[count] = output_string[count];
interface_name[count]='\0';
fprintf(stderr,"Interface name %s \n", interface_name);
pclose(fp);
}
/* CcspHalExtSw_getAssociatedDevice : */
/**
* @description Collected the active wired clients information
* @param output_array_size -- Size of the active wired connected clients
* @param output_struct -- Structure of wired clients informations
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
*/
INT CcspHalExtSw_getAssociatedDevice(ULONG *output_array_size, eth_device_t **output_struct)
{
CHAR buf[MAX_BUF_SIZE] = {0},str[MAX_BUF_SIZE] = {0},interface_name[50] = {0},macAddr[50] = {0};
FILE *fp = NULL,*fp1 = NULL;
INT count = 0,str_count = 0;
ULONG maccount = 0,eth_count = 0;
INT arr[MACADDRESS_SIZE] = {0};
UCHAR mac[MACADDRESS_SIZE] = {0};
CHAR ipAddr[50],stub[50],phyAddr[50],ifName[32],status[32];
int ret;
if(output_struct == NULL)
{
printf("\nNot enough memory\n");
return RETURN_ERR;
}
system("echo -n > /tmp/ethernetmac.txt");
system("cat /nvram/dnsmasq.leases | cut -d ' ' -f2 > /tmp/connected_mac.txt"); //storing the all associated device information in tmp folder
//storing the private wifi associated device iformation in tmp folder
GetInterfaceName(interface_name,"/nvram/hostapd0.conf");
sprintf(buf,"iw dev %s station dump | grep Station | cut -d ' ' -f2 > /tmp/Associated_Devices.txt",interface_name);
system(buf);
GetInterfaceName(interface_name,"/nvram/hostapd1.conf");
sprintf(buf,"iw dev %s station dump | grep Station | cut -d ' ' -f2 >> /tmp/Associated_Devices.txt",interface_name);
system(buf);
system("diff /tmp/Associated_Devices.txt /tmp/connected_mac.txt | grep \"^+\" | cut -c2- | sed -n '1!p' > /tmp/ethernet_connected_clients.txt"); //separating the ethernet associated device information from connected_mac test file
fp=popen("cat /tmp/ethernet_connected_clients.txt | wc -l","r"); // For getting the ethernet connected mac count
if(fp == NULL)
return RETURN_ERR;
else
{
fgets(buf,MAX_BUF_SIZE,fp);
maccount = strtol(buf, NULL, 10);
fprintf(stderr,"ethernet umac is %d \n",maccount);
}
pclose(fp);
eth_device_t *temp=NULL;
temp = (eth_device_t*)calloc(1, sizeof(eth_device_t)*maccount);
if(temp == NULL)
{
fprintf(stderr,"Not enough memory \n");
return RETURN_ERR;
}
fp=fopen("/tmp/ethernet_connected_clients.txt","r"); // reading the ethernet associated device information
if(fp == NULL)
{
*output_struct = NULL;
*output_array_size = 0;
free(temp);
return RETURN_ERR;
}
else
{
for(count = 0;count < maccount ; count++)
{
fgets(str,MAX_BUF_SIZE,fp);
for(str_count = 0;str[str_count]!='\n';str_count++)
macAddr[str_count] = str[str_count];
macAddr[str_count] = '\0';
system("ip nei show | grep brlan0 > /tmp/arp_cache");
fp1=fopen("/tmp/arp_cache","r");
if(fp1 == NULL){
fclose(fp);
free(temp);
return RETURN_ERR;
}
while(fgets(buf,sizeof(buf),fp1) != NULL)
{
if ( strstr(buf, "FAILED") != 0 )
continue;
/*
Sample:
10.0.0.208 dev brlan0 lladdr d4:be:d9:99:7f:47 STALE
10.0.0.107 dev brlan0 lladdr 64:a2:f9:d2:f5:67 REACHABLE
*/
ret = sscanf(buf, LM_ARP_ENTRY_FORMAT,
ipAddr,
stub,
ifName,
stub,
phyAddr,
status);
if(ret != 6)
continue;
if(strcmp(phyAddr,macAddr) == 0)
{
memset(buf,0,sizeof(buf));
if(strcmp(status,"REACHABLE") == 0)
{
sprintf(buf,"echo %s >> /tmp/ethernetmac.txt",macAddr);
system(buf);
eth_count++;
break;
}
else if((strcmp(status,"STALE") == 0) || (strcmp(status,"DELAY")))
{
sprintf(buf,"ping -q -c 1 -W 1 \"%s\" > /dev/null 2>&1",ipAddr);
fprintf(stderr,"buf is %s and MACADRRESS %s\n",buf,macAddr);
if (WEXITSTATUS(system(buf)) == 0)
{
fprintf(stderr,"Inside STALE SUCCESS \n");
memset(buf,0,sizeof(buf));
sprintf(buf,"echo %s >> /tmp/ethernetmac.txt",macAddr);
system(buf);
eth_count++;
break;
}
}
else
{
fprintf(stderr,"Running in different state \n");
break;
}
}
else
fprintf(stderr,"MAcAddress is not valid \n");
}
fclose(fp1);
}
}
fclose(fp);
fp=fopen("/tmp/ethernetmac.txt","r");
if(fp == NULL)
{
*output_struct = NULL;
*output_array_size = 0;
free(temp);
return RETURN_OK;
}
else
{
memset(buf,0,sizeof(buf));
for(count = 0;count < eth_count ; count++)
{
fgets(buf,sizeof(buf),fp);
if(MACADDRESS_SIZE == sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",&arr[0],&arr[1],&arr[2],&arr[3],&arr[4],&arr[5]) )
{
for( int ethclientindex = 0; ethclientindex < 6; ++ethclientindex )
{
mac[ethclientindex] = (unsigned char) arr[ethclientindex];
}
memcpy(temp[count].eth_devMacAddress,mac,(sizeof(unsigned char))*6);
fprintf(stderr,"MAC %d = %X:%X:%X:%X:%X:%X \n", count, temp[count].eth_devMacAddress[0],temp[count].eth_devMacAddress[1], temp[count].eth_devMacAddress[2], temp[count].eth_devMacAddress[3], temp[count].eth_devMacAddress[4], temp[count].eth_devMacAddress[5]);
}
temp[count].eth_port= 0;
CcspHalEthSwLocatePortByMacAddress(temp[count].eth_devMacAddress, &temp[count].eth_port);
temp[count].eth_vlanid=-1;
FILE *fp2 = NULL;
char cmd[64] = {0};
char filepath[32] = {0};
char buffer[32] = {0};
#ifdef THREE_GMACS_SUPPORT
if (temp[count].eth_port == 5){
sprintf(filepath, "/sys/class/net/eth3/speed");
}else
#endif
{
sprintf(filepath, "/sys/class/net/lan%d/speed",(temp[count].eth_port-1));
}
fp2 = fopen(filepath, "r");
if(fp2 != NULL)
{
fgets(buffer,sizeof(buffer),fp2);
temp[count].eth_devTxRate = strtol(buffer, NULL, 10);
temp[count].eth_Active=1;
fclose(fp2);
}else{
temp[count].eth_devTxRate= -1;
temp[count].eth_Active=0;
}
temp[count].eth_devRxRate = temp[count].eth_devTxRate;
}
}
fclose(fp);
*output_struct = temp;
*output_array_size = eth_count;
fprintf(stderr,"Connected Active ethernet clients count is %ld \n",*output_array_size);
return RETURN_OK;
}
/* CcspHalExtSw_getEthWanEnable */
/**
* @description Return the Ethwan Enbale status
* @param enable -- Having status of WANMode ( Ethernet,DOCSIS)
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
*/
INT CcspHalExtSw_getEthWanEnable(BOOLEAN *enable)
{
int sockfd;
struct ifreq ifr;
if (enable == NULL)
return RETURN_ERR;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("====> open socket fail \n");
return RETURN_ERR;
}
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ETH_WAN_INTERFACE);
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
{
printf("====> ioctl open socket fail \n");
close(sockfd);
return RETURN_ERR;
}
close(sockfd);
*enable = ifr.ifr_flags & IFF_UP;
return RETURN_OK;
}
/* CcspHalExtSw_getEthWanPort: */
/**
* @description Return the ethwan port
* @param port -- having ethwan port
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
*/
INT CcspHalExtSw_getEthWanPort(UINT *Port)
{
if(Port == NULL)
return RETURN_ERR;
*Port = 6;
return RETURN_OK;
}
/* CcspHalExtSw_setEthWanEnable : */
/**
* @description setting the ethwan enable status
* @enable -- Switch from ethernet mode to docsis mode or vice-versa
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
*/
INT CcspHalExtSw_setEthWanEnable(BOOLEAN enable)
{
char cmd[32] = {0};
sprintf(cmd,"ifconfig %s %s",ETH_WAN_INTERFACE, enable ? "up":"down");
system(cmd);
return RETURN_OK;
}
/* CcspHalExtSw_setEthWanPort : */
/**
* @description Need to set the ethwan port
* @param port -- Setting the ethwan port
*
* @return The status of the operation.
* @retval RETURN_OK if successful.
* @retval RETURN_ERR if any error is detected
*
*/
INT CcspHalExtSw_setEthWanPort(UINT Port)
{
if(Port != 6)
return RETURN_ERR;
return RETURN_OK;
}
INT GWP_GetEthWanLinkStatus()
{
int link = 0;
char path[32] = {0};
sprintf(path, "/sys/class/net/erouter0/carrier");
link = is_interface_link(path);
if(link){
return 1;
}else{
return 0;
}
}
#if defined(FEATURE_RDKB_WAN_MANAGER)
void *ethsw_thread_main(void *context __attribute__((unused)))
{
int previousLinkDetected = 0;
int currentLinkDeteced = 0;
int timeout = 0;
int file = 0;
while(timeout != 180)
{
if (file == access(ETH_INITIALIZE, R_OK))
{
CcspHalEthSwTrace(("Eth agent initialized \n"));
break;
}
else
{
timeout = timeout+1;
sleep(1);
}
}
while(1)
{
currentLinkDeteced = GWP_GetEthWanLinkStatus();
if (currentLinkDeteced != previousLinkDetected)
{
if (currentLinkDeteced)
{
CcspHalEthSwTrace(("send_link_event: Got Link UP Event\n"));
ethWanCallbacks.pGWP_act_EthWanLinkUP();
}
else
{
CcspHalEthSwTrace(("send_link_event: Got Link DOWN Event\n"));
ethWanCallbacks.pGWP_act_EthWanLinkDown();
}
previousLinkDetected = currentLinkDeteced;
}
sleep(5);
}
return NULL;
}
#endif
void GWP_RegisterEthWan_Callback(appCallBack *obj) {
#if defined(FEATURE_RDKB_WAN_MANAGER)
int rc;
if (obj == NULL) {
rc = RETURN_ERR;
} else {
ethWanCallbacks.pGWP_act_EthWanLinkUP = obj->pGWP_act_EthWanLinkUP;
ethWanCallbacks.pGWP_act_EthWanLinkDown = obj->pGWP_act_EthWanLinkDown;
rc = RETURN_OK;
}
#endif
}
INT GWP_GetEthWanInterfaceName
(
unsigned char * Interface,
ULONG maxSize
)
{
//Maxsize param should be minimum 4charecters(eth0) including NULL charecter
if( ( Interface == NULL ) || ( maxSize < ( strlen( ETH_WAN_IFNAME ) + 1 ) ) )
{
printf("ERROR: Invalid argument. \n");
return RETURN_ERR;
}
snprintf(Interface, maxSize, "%s", ETH_WAN_IFNAME);
return RETURN_OK;
}