blob: 3b101f000115781d3207dd90fcf2054bd0536145 [file] [log] [blame]
#include "cmm.h"
#include "itf.h"
#include "ffbridge.h"
#include "cmmd.h"
#include "fpp.h"
#include <sys/ioctl.h>
/* Structure representing a pppoe entry (internally to cmm) */
struct PPPoERelayEntry {
struct PPPoERelayEntry *next;
int count;
fpp_pppoe_relay_cmd_t *pppoe;
};
struct PPPoERelayEntry *relay_table = NULL;
pthread_mutex_t RelayMutex = PTHREAD_MUTEX_INITIALIZER;
/************************************************************
*
*
*
*************************************************************/
#if 1
static int cmmGetIfMac(unsigned char *ifname, unsigned char *mac){
struct ifreq ifr;
int fd;
memcpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
fd = socket(AF_INET, SOCK_DGRAM,0);
if ( fd < 0 )
{
cmm_print(DEBUG_ERROR, "%s::%d:Socket Creation Failed \n",__func__, __LINE__);
return -1;
}
if ( ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 )
{
cmm_print(DEBUG_ERROR, "%s::%d:Ioctl Call Failed \n",__func__, __LINE__);
close(fd);
return -1;
}
memcpy(mac,ifr.ifr_hwaddr.sa_data,IFHWADDRLEN);
close(fd);
return 0;
}
static int cmmRelayAdd(FCI_CLIENT * fci_handler, struct fpp_relay_info *sh, u_int16_t *res_buf, u_int16_t *res_len)
{
struct PPPoERelayEntry *temp, *new_relay_entry = NULL;
fpp_pppoe_relay_cmd_t *cmd;
int ret = 0;
int in_ifindex = -1, out_ifindex = -1, phys_in_ifindex = -1, phys_out_ifindex = -1;
char in_ifname[IFNAMSIZ], out_ifname[IFNAMSIZ];
res_buf[0] = CMMD_ERR_NOT_CONFIGURED;
*res_len = 2;
__pthread_mutex_lock(&RelayMutex);
__pthread_mutex_lock(&itf_table.lock);
/*Check if we have not already been sent to Forward Engine */
temp = relay_table;
while (temp != NULL) {
if (!memcmp(temp->pppoe->peermac1, sh->peermac1, 6)
&& temp->pppoe->sesID == sh->sesID
&& !memcmp(temp->pppoe->peermac2, sh->peermac2, 6)
&& temp->pppoe->relaysesID == sh->relaysesID) {
cmm_print(DEBUG_INFO, "Relay Match found\n");
break;
}
temp = temp->next;
}
if (temp) {
temp->count++;
goto end;
}
/* Check the interface names whether they are valid and get the physical interface
* names for bridge interfaces */
memset(in_ifname , 0, IFNAMSIZ);
memset(out_ifname , 0, IFNAMSIZ);
in_ifindex = if_nametoindex(sh->ipifname);
if (!in_ifindex)
{
cmm_print(DEBUG_ERROR, "%s::%d:if_nametoindex Failed %s\n",__func__, __LINE__, sh->ipifname);
goto end;
}
if ( __itf_is_bridge(in_ifindex))
{
cmm_print(DEBUG_INFO, "%s::%d:IP interface name is Bridge interface : %d\n",__func__, __LINE__, in_ifindex);
phys_in_ifindex = cmmBrGetPhysItf(in_ifindex, sh->peermac1);
if (phys_in_ifindex < 0)
{
cmm_print(DEBUG_ERROR, "%s::%d:Error in finding the Physical interface %d\n",__func__, __LINE__, phys_in_ifindex);
goto end;
}
cmm_print(DEBUG_INFO, "%s::%d:Physical interface is : %d\n",__func__, __LINE__, phys_in_ifindex);
if (! __itf_is_programmed(phys_in_ifindex))
{
cmm_print(DEBUG_ERROR, "%s::%d:Interface is not programmed to FPP %d\n",__func__, __LINE__, phys_in_ifindex);
goto end;
}
if_indextoname(phys_in_ifindex, in_ifname);
}
else
{
if (! __itf_is_programmed(in_ifindex))
{
cmm_print(DEBUG_ERROR, "%s::%d:Interface is not programmed to FPP %d\n",__func__, __LINE__, in_ifindex);
goto end;
}
memcpy(in_ifname,sh->ipifname, 6);
}
out_ifindex = if_nametoindex(sh->opifname);
if (!out_ifindex)
{
cmm_print(DEBUG_ERROR, "%s::%d:if_nametoindex Failed %s\n",__func__, __LINE__, sh->opifname);
goto end;
}
if ( __itf_is_bridge(out_ifindex))
{
phys_out_ifindex = cmmBrGetPhysItf(out_ifindex, sh->peermac2);
if (phys_out_ifindex < 0)
{
cmm_print(DEBUG_ERROR, "%s::%d:Error in finding the Physical interface %d\n",__func__, __LINE__, phys_out_ifindex);
goto end;
}
cmm_print(DEBUG_INFO, "%s::%d:Physical interface is : %d\n",__func__, __LINE__, phys_out_ifindex);
if (! __itf_is_programmed(phys_out_ifindex))
{
cmm_print(DEBUG_ERROR, "%s::%d:Interface is not programmed to FPP %d\n",__func__, __LINE__, phys_out_ifindex);
goto end;
}
if_indextoname(phys_out_ifindex, out_ifname);
}
else
{
if (! __itf_is_programmed(out_ifindex))
{
cmm_print(DEBUG_ERROR, "%s::%d:Interface is not programmed to FPP %d\n",__func__, __LINE__, out_ifindex);
goto end;
}
memcpy(out_ifname,sh->opifname, 6);
}
/*No existing entry found, try to create a new one */
cmd = (fpp_pppoe_relay_cmd_t *) malloc(sizeof(fpp_pppoe_relay_cmd_t));
if (cmd == NULL)
{
cmm_print(DEBUG_ERROR, "%s::%d:Error while allocating memory for PPPoERelayCommand \n",__func__, __LINE__);
ret = -1;
goto end;
}
new_relay_entry = (struct PPPoERelayEntry *) malloc(sizeof(struct PPPoERelayEntry));
if (new_relay_entry == NULL)
{
cmm_print(DEBUG_ERROR, "%s::%d:Error while allocating memory for PPPoERelayEntry \n",__func__, __LINE__);
ret = -1;
free(cmd);
goto end;
}
/* Getting the input/output interface MAC address from the kernel and copy to cmd structure*/
if ( cmmGetIfMac((unsigned char *)sh->ipifname,(unsigned char *)cmd->ipif_mac) < 0 )
{
cmm_print(DEBUG_ERROR, "%s::%d:Error while getting the input interface mac \n",__func__, __LINE__);
goto end;
}
if ( cmmGetIfMac((unsigned char *)sh->opifname,(unsigned char *)cmd->opif_mac) < 0 )
{
cmm_print(DEBUG_ERROR, "%s::%d:Error while getting the output interface mac \n",__func__, __LINE__);
goto end;
}
cmm_print(DEBUG_INFO, "Send CMD_PPPOE_RELAY_ENTRY ACTION_REGISTER\n");
cmd->action = FPP_ACTION_REGISTER;
cmd->sesID = sh->sesID;
memcpy(cmd->peermac1, sh->peermac1, 6);
memcpy(cmd->ipifname, in_ifname, IFNAMSIZ);
cmd->relaysesID = sh->relaysesID;
memcpy(cmd->peermac2, sh->peermac2, 6);
memcpy(cmd->opifname, out_ifname, IFNAMSIZ);
#if 1
cmm_print(DEBUG_INFO,
"Sending command %02x:%02x:%02x:%02x:%02x:%02x(%s %d) to %02x:%02x:%02x:%02x:%02x:%02x(%s %d)\n",
cmd->peermac1[0], cmd->peermac1[1], cmd->peermac1[2],
cmd->peermac1[3], cmd->peermac1[4], cmd->peermac1[5],
cmd->ipifname, cmd->sesID, cmd->peermac2[0],
cmd->peermac2[1], cmd->peermac2[2], cmd->peermac2[3],
cmd->peermac2[4], cmd->peermac2[5], cmd->opifname,
cmd->relaysesID);
#endif
ret = fci_cmd(fci_handler, FPP_CMD_PPPOE_RELAY_ENTRY, (unsigned short *) cmd, sizeof(*cmd), res_buf, res_len);
if (ret != 0 || res_buf[0] != FPP_ERR_OK)
{
if (ret != 0)
cmm_print(DEBUG_ERROR, "Error '%s' when sending CMD_PPPOE_RELAY_ENTRY, ACTION_REGISTER\n", strerror(errno));
else
cmm_print(DEBUG_ERROR, "Error %d when sending CMD_PPPOE_RELAY_ENTRY, ACTION_REGISTER\n", res_buf[0]);
free(cmd);
free(new_relay_entry);
goto end;
}
cmm_print(DEBUG_INFO, "Send CMD_PPPOE_RELAY_ENTRY SUCCESS\n");
new_relay_entry->count = 1;
new_relay_entry->pppoe = cmd;
new_relay_entry->next = relay_table;
relay_table = new_relay_entry;
end:
__pthread_mutex_unlock(&itf_table.lock);
__pthread_mutex_unlock(&RelayMutex);
return ret;
}
#endif
static int cmmRelayRemove(FCI_CLIENT * fci_handler,fpp_relay_info_t *sh, u_int16_t *res_buf, u_int16_t *res_len);
int cmmRelayProcessClientCmd(FCI_CLIENT * fci_handle, int function_code,
u_int8_t *cmd_buf, u_int16_t cmd_len, u_int16_t *res_buf, u_int16_t *res_len)
{
cmmd_relay_info_t *sh;
int rc = 0;
sh = (cmmd_relay_info_t *) cmd_buf;
switch (function_code) {
case CMMD_CMD_PPPOE_RELAY_ADD:
#if 0
cmm_print(DEBUG_INFO,
"Received CMD_PPPOE_RELAY_ENTRY command from RP-PPPoE...\n");
cmm_print(DEBUG_INFO, "size:%d\n", buffer_size);
cmm_print(DEBUG_INFO,
"Received the peers %02x:%02x:%02x:%02x:%02x:%02x(%s %d) to %02x:%02x:%02x:%02x:%02x:%02x(%s %d)\n",
sh->peermac1[0], sh->peermac1[1], sh->peermac1[2],
sh->peermac1[3], sh->peermac1[4], sh->peermac1[5],
sh->ipifname, sh->sesID, sh->peermac2[0],
sh->peermac2[1], sh->peermac2[2], sh->peermac2[3],
sh->peermac2[4], sh->peermac2[5], sh->opifname,
sh->relaysesID);
#endif
rc = cmmRelayAdd(fci_handle, sh, res_buf, res_len);
break;
case CMMD_CMD_PPPOE_RELAY_REMOVE:
rc = cmmRelayRemove(fci_handle, sh, res_buf, res_len);
break;
default:
res_buf[0] = CMMD_ERR_UNKNOWN_COMMAND;
*res_len = 2;
break;
}
return rc;
}
/*****************************************************************
* * cmmPPPoELocalShow
* *
* *
* ******************************************************************/
int cmmRelayLocalShow(struct cli_def *cli, char *command, char *argv[],
int argc)
{
struct PPPoERelayEntry *temp;
__pthread_mutex_lock(&RelayMutex);
for (temp = relay_table; temp != NULL; temp = temp->next) {
if (temp->pppoe) {
cli_print(cli, "%02x.%02x.%02x.%02x.%02x.%02x[%s %d]<==::==>%02x.%02x.%02x.%02x.%02x.%02x[%s %d]",
temp->pppoe->peermac1[0],temp->pppoe->peermac1[1],
temp->pppoe->peermac1[2],temp->pppoe->peermac1[3],
temp->pppoe->peermac1[4],temp->pppoe->peermac1[5],
temp->pppoe->ipifname,temp->pppoe->sesID,
temp->pppoe->peermac2[0],temp->pppoe->peermac2[1],
temp->pppoe->peermac2[2],temp->pppoe->peermac2[3],
temp->pppoe->peermac2[4],temp->pppoe->peermac2[5],
temp->pppoe->opifname,temp->pppoe->relaysesID);
} else
cli_print(cli, "Internal Error");
}
__pthread_mutex_unlock(&RelayMutex);
return CLI_OK;
}
/*****************************************************************
* * cmmRelayRemove
* *
* *
* ******************************************************************/
static int cmmRelayRemove(FCI_CLIENT * fci_handler,fpp_relay_info_t *sh, u_int16_t *res_buf, u_int16_t *res_len)
{
struct PPPoERelayEntry *temp = NULL, *prevEntry = NULL;
fpp_pppoe_relay_cmd_t *cmd;
int ret = 0;
res_buf[0] = CMMD_ERR_NOT_CONFIGURED;
*res_len = 2;
__pthread_mutex_lock(&RelayMutex);
temp = relay_table;
if (temp == NULL) {
cmm_print(DEBUG_ERROR, "relay_table is NULL\n");
goto end;
}
// Do a test on the first of the list
while ((temp != NULL)) {
if (!memcmp(temp->pppoe->peermac1, sh->peermac1, 6)
&& temp->pppoe->sesID == sh->sesID
&&!memcmp(temp->pppoe->peermac2, sh->peermac2, 6)
&& temp->pppoe->relaysesID == sh->relaysesID) {
cmm_print(DEBUG_ERROR, "An entry has been found to remove\n");
break;
} else {
prevEntry = temp;
temp = temp->next;
}
}
// The entry have not been found, should not happen
if (temp == NULL) {
cmm_print(DEBUG_ERROR,
"An entry have been removed already on localtable or the delete command for same entry\n");
goto end;
}
cmd = temp->pppoe;
cmd->action = FPP_ACTION_DEREGISTER;
#if 1
cmm_print(DEBUG_INFO,
"Removing Entry %02x:%02x:%02x:%02x:%02x:%02x(%s %d) to %02x:%02x:%02x:%02x:%02x:%02x(%s %d)\n",
cmd->peermac1[0], cmd->peermac1[1], cmd->peermac1[2],
cmd->peermac1[3], cmd->peermac1[4], cmd->peermac1[5],
cmd->ipifname, cmd->sesID, cmd->peermac2[0],
cmd->peermac2[1], cmd->peermac2[2], cmd->peermac2[3],
cmd->peermac2[4], cmd->peermac2[5], cmd->opifname,
cmd->relaysesID);
#endif
ret = fci_cmd(fci_handler, FPP_CMD_PPPOE_RELAY_ENTRY, (unsigned short *) cmd, sizeof(fpp_pppoe_relay_cmd_t), res_buf, res_len);
if (ret != 0 || (res_buf[0] != FPP_ERR_OK && res_buf[0] != FPP_ERR_PPPOE_ENTRY_NOT_FOUND))
{
if (ret != 0)
cmm_print(DEBUG_ERROR, "Error '%s' while sending CMD_PPPOE_RELAY_ENTRY, ACTION_DEREGISTER\n", strerror(errno));
else
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_PPPOE_RELAY_ENTRY, ACTION_DEREGISTER\n", res_buf[0]);
goto end;
}
if (prevEntry == NULL)
relay_table = temp->next;
else
prevEntry->next = temp->next;
free(temp->pppoe);
free(temp);
end:
__pthread_mutex_unlock(&RelayMutex);
return ret;
}
static int relay_print_usage()
{
cmm_print(DEBUG_ERROR,
"Usage: relay <add|del> <MAC1> <MAC2> <IN iface> <OUT iface> <session ID> <relay session ID>\n"
"\n"
"\n"
" Ex: relay add 00:00:00:00:00:01 00:00:00:00:00:02 eth2 eth1 1 1\n"
" relay del 00:00:00:00:00:01 00:00:00:00:00:02 eth2 eth1 1 1\n"
);
return -1;
}
static int relay_parse_cmd(int argc, char ** keywords, daemon_handle_t daemon_handle)
{
cmmd_relay_info_t cmd;
char res_buf[CMM_BUF_SIZE];
int fc;
int rc;
unsigned long tmp;
if (argc < 7)
return relay_print_usage();
if (strcmp(*keywords, "add") == 0)
fc = CMMD_CMD_PPPOE_RELAY_ADD;
else if (strcmp(*keywords, "del") == 0)
fc = CMMD_CMD_PPPOE_RELAY_REMOVE;
else
return relay_print_usage();
keywords++;
if (!parse_macaddr(*keywords, cmd.peermac1))
return relay_print_usage();
keywords++;
if (!parse_macaddr(*keywords, cmd.peermac2))
return relay_print_usage();
keywords++;
strncpy(cmd.ipifname, *keywords, sizeof(cmd.ipifname));
keywords++;
strncpy(cmd.opifname, *keywords, sizeof(cmd.opifname));
keywords++;
tmp = strtoul(*keywords, NULL, 0);
if(tmp > UINT_MAX)
return relay_print_usage();
cmd.sesID = tmp;
keywords++;
tmp = strtoul(*keywords, NULL, 0);
if(tmp > UINT_MAX)
return relay_print_usage();
cmd.relaysesID = tmp;
rc = cmmSendToDaemon(daemon_handle, fc, &cmd, sizeof(cmd), res_buf);
if (rc != 2) /* we expect 2 bytes in response */
{
cmm_print(DEBUG_STDERR, "unexpected response length %d\n", rc);
return -1;
}
else if ((((u_int16_t*)res_buf)[0]) != CMMD_ERR_OK)
{
cmm_print(DEBUG_STDERR, "Error %d received from CMM Deamon\n", ((u_int16_t*)res_buf)[0]);
return -1;
}
return 0;
}
int cmmRelayParseCmd(int argc, char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
if (tabStart < argc)
return relay_parse_cmd(argc - tabStart, &keywords[tabStart], daemon_handle);
else
return relay_print_usage();
}