blob: ffbe710e42128662fb535e0ce4911b30b6d15834 [file] [log] [blame]
/*
*
* Copyright (C) 2007 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cmm.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define UNKNOWN_CMD 0
#define ICC_CMD 1
#define BRIDGE_CMD 2
#ifdef WIFI_ENABLE
struct wifi_ff_entry glbl_wifi_ff_ifs[MAX_WIFI_FF_IFS];
#endif
struct list_head l2flow_table[L2FLOW_HASH_TABLE_SIZE];
pthread_mutex_t brMutex = PTHREAD_MUTEX_INITIALIZER; /*mutex to prevent race condition on the route table*/
#ifdef AUTO_BRIDGE
/* This function allocates and add an entry into flow_table */
static int __cmm_l2flow_del(struct l2flowTable * l2flow_entry)
{
list_del(&l2flow_entry->list);
free(l2flow_entry);
return 0;
}
/* This function allocates and add an entry into flow_table */
static struct l2flowTable * __cmm_l2flow_add(struct l2flow *l2flowtmp)
{
unsigned int key;
struct l2flowTable* l2flow_entry;
cmm_print(DEBUG_INFO, "%s\n", __func__);
key = l2flow_hash(l2flowtmp);
l2flow_entry = malloc(sizeof(*l2flow_entry));
if(!l2flow_entry){
cmm_print(DEBUG_ERROR, "Out of memory\n");
goto out;
}
memset(l2flow_entry, 0, sizeof(*l2flow_entry));
memcpy(&l2flow_entry->l2flow, l2flowtmp, sizeof(*l2flowtmp));
list_add(&l2flow_table[key], &l2flow_entry->list);
cmm_print(DEBUG_INFO, "Entry added, hash = %d \n", key);
out:
return l2flow_entry;
}
static struct l2flowTable * __cmm_l2flow_find(struct l2flow *l2flowtmp)
{
int key;
struct list_head *entry;
struct l2flowTable *table_entry;
key = l2flow_hash(l2flowtmp);
entry = list_first(&l2flow_table[key]);
while (entry != &l2flow_table[key])
{
table_entry = container_of(entry, struct l2flowTable, list);
if(!cmm_l2flow_cmp(&table_entry->l2flow, l2flowtmp))
return table_entry; // Found
entry = list_next(entry);
}
return NULL; // Not found
}
void cmm_l2flow_print(int level, struct l2flow *l2flow_tmp, char nl)
{
cmm_print(level, "Saddr=%02x:%02x:%02x:%02x:%02x:%02x ", l2flow_tmp->saddr[0], l2flow_tmp->saddr[1],
l2flow_tmp->saddr[2], l2flow_tmp->saddr[3], l2flow_tmp->saddr[4], l2flow_tmp->saddr[5]);
cmm_print(level, "Daddr=%02x:%02x:%02x:%02x:%02x:%02x ", l2flow_tmp->daddr[0], l2flow_tmp->daddr[1],
l2flow_tmp->daddr[2], l2flow_tmp->daddr[3], l2flow_tmp->daddr[4], l2flow_tmp->daddr[5]);
cmm_print(level, "Ethertype=%04x ", ntohs(l2flow_tmp->ethertype));
cmm_print(level, "PPPoE session id=%d ", ntohs(l2flow_tmp->session_id));
cmm_print(level, "Proto=%d ", l2flow_tmp->l3.proto);
if(l2flow_tmp->l3.proto)
{
int family = 0;
char saddr_buf[INET6_ADDRSTRLEN], daddr_buf[INET6_ADDRSTRLEN];
if(l2flow_tmp->ethertype == htons(ETH_P_IP))
family = AF_INET;
else if (l2flow_tmp->ethertype == htons(ETH_P_IPV6))
family = AF_INET6;
if(family)
cmm_print(level, " L3 info src=%s dst=%s sport=%d dport=%d ",
inet_ntop(family, l2flow_tmp->l3.saddr.all, saddr_buf, INET6_ADDRSTRLEN),
inet_ntop(family, l2flow_tmp->l3.daddr.all, daddr_buf, INET6_ADDRSTRLEN),
ntohs(l2flow_tmp->l4.sport), ntohs(l2flow_tmp->l4.dport));
}
if(nl)
cmm_print(level, "\n");
}
int __cmm_l2flow_deregister(FCI_CLIENT* fci_handler, struct l2flow *l2flow_tmp)
{
struct l2flowTable *l2flow_entry = NULL;
cmm_print(DEBUG_INFO, "%s\n", __func__);
cmm_l2flow_print(DEBUG_INFO, l2flow_tmp, 1);
l2flow_entry = __cmm_l2flow_find(l2flow_tmp);
if(!l2flow_entry){
cmm_print(DEBUG_INFO, "%s Can't find l2flow entry\n", __func__);
}
else{
if(!cmmFeL2FlowUpdate(fci_handler, REMOVE, l2flow_entry))
__cmm_l2flow_del(l2flow_entry);
cmm_print(DEBUG_INFO, "%s L2 entry successfully deleted\n", __func__);
}
/* In all case it is needed to ack ABM whatever */
cmm_l2flow_abm_notify(L2FLOW_ENTRY_DEL, L2FLOW_ACK, l2flow_tmp);
return 0;
}
int __cmm_l2flow_register(FCI_CLIENT* fci_handler, char action, struct l2flow *l2flow_tmp, int iifi_idx, int oifi_idx, int flags, short mark)
{
struct l2flowTable * entry = NULL;
char allowed = 0;
cmm_print(DEBUG_INFO, "%s\n", __func__);
cmm_l2flow_print(DEBUG_INFO, l2flow_tmp, 0);
cmm_print(DEBUG_INFO, "Input itf idx = %d ", iifi_idx);
cmm_print(DEBUG_INFO, "Output itf idx = %d ", oifi_idx);
cmm_print(DEBUG_INFO, "Mark = %0x4\n", mark);
entry = __cmm_l2flow_find(l2flow_tmp);
if(!entry){
if((entry = __cmm_l2flow_add(l2flow_tmp)) == NULL){
cmm_print(DEBUG_INFO, "%s error l2flow add failed\n", __func__);
goto fail;
}
entry->flags |= FPP_NEEDS_UPDATE;
}
if(__itf_is_programmed(iifi_idx) && __itf_is_programmed(oifi_idx)){
cmm_print(DEBUG_INFO, "L2Flow Entry allowed\n", iifi_idx);
allowed = 1;
}
else{
cmm_print(DEBUG_INFO, "L2Flow Entry not allowed\n", iifi_idx);
entry->flags &= ~FPP_NEEDS_UPDATE;
}
if((entry->idev_ifi != iifi_idx) || (entry->odev_ifi != oifi_idx))
entry->flags |= FPP_NEEDS_UPDATE;
entry->idev_ifi = iifi_idx;
entry->odev_ifi = oifi_idx;
entry->mark = mark;
if(allowed){
if(!cmmFeL2FlowUpdate(fci_handler, ADD|UPDATE, entry))
cmm_l2flow_abm_notify(L2FLOW_ENTRY_UPDATE, L2FLOW_OFFLOADED | L2FLOW_ACK, &entry->l2flow);
else
cmm_l2flow_abm_notify(L2FLOW_ENTRY_UPDATE, L2FLOW_DENIED | L2FLOW_ACK, &entry->l2flow);
}
else{
cmmFeL2FlowUpdate(fci_handler, REMOVE, entry);
cmm_l2flow_abm_notify(L2FLOW_ENTRY_UPDATE, L2FLOW_DENIED, &entry->l2flow);
}
return 0;
fail:
return -1;
}
int __cmm_l2flow_reset(FCI_CLIENT* fci_handler)
{
int i;
struct l2flowTable * table_entry = NULL;
struct list_head *entry;
if (fci_write(fci_handler, FPP_CMD_RX_L2BRIDGE_FLOW_RESET, 0, NULL))
{
cmm_print(DEBUG_ERROR, "Error while trying to reset bridge module\n");
goto out;
}
cmm_print(DEBUG_COMMAND, "Send CMD_RX_L2BRIDGE_FLOW_RESET\n");
for(i= 0 ; i < L2FLOW_HASH_TABLE_SIZE; i++)
while (!list_empty(&l2flow_table[i]))
{
entry = list_first(&l2flow_table[i]);
table_entry = container_of(entry, struct l2flowTable, list);
__cmm_l2flow_del(table_entry);
}
out:
return 0;
}
int cmm_l2flow_abm_notify(char action, int flags, struct l2flow * l2flow)
{
struct rtnl_handle rth;
char buf[256] __attribute__ ((aligned (4)));
struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
struct l2flow_msg *l2m;
cmm_print(DEBUG_INFO, "%s\n", __func__);
if (cmm_nl_open(&rth, 0, NETLINK_L2FLOW) < 0) {
cmm_print(DEBUG_ERROR, "%s::%d: cmm_rtnl_open() failed, %s\n", __func__, __LINE__, strerror(errno));
goto err0;
}
cmm_nlh_init(nlh, sizeof(struct l2flow_msg), L2FLOW_MSG_ENTRY, NLM_F_REQUEST);
l2m = NLMSG_DATA(nlh);
memset(l2m, 0, sizeof(struct l2flow_msg));
l2m->action = action;
l2m->flags = flags;
memcpy(l2m->saddr, l2flow->saddr, ETH_ALEN);
memcpy(l2m->daddr, l2flow->daddr, ETH_ALEN);
l2m->ethertype = l2flow->ethertype;
if(l2flow->vlan_tag)
cmm_addattr16(nlh, sizeof(buf), L2FLOWA_VLAN_TAG, l2flow->vlan_tag);
if(l2flow->session_id)
cmm_addattr16(nlh, sizeof(buf), L2FLOWA_PPP_S_ID, l2flow->session_id);
if(l2flow->l3.proto){
cmm_addattr_l(nlh, sizeof(buf), L2FLOWA_IP_PROTO, &l2flow->l3.proto, sizeof(l2flow->l3.proto));
if(l2flow->ethertype == htons(ETH_P_IP)){
cmm_addattr32(nlh, sizeof(buf), L2FLOWA_IP_SRC, l2flow->l3.saddr.ip);
cmm_addattr32(nlh, sizeof(buf), L2FLOWA_IP_DST, l2flow->l3.daddr.ip);
}
else if(l2flow->ethertype == htons(ETH_P_IPV6)){
cmm_addattr_l(nlh, sizeof(buf), L2FLOWA_IP_SRC, l2flow->l3.saddr.ip6, 16);
cmm_addattr_l(nlh, sizeof(buf), L2FLOWA_IP_DST, l2flow->l3.daddr.ip6, 16);
}
if((l2flow->l3.proto == IPPROTO_UDP)
|| (l2flow->l3.proto == IPPROTO_TCP)){
cmm_addattr16(nlh, sizeof(buf), L2FLOWA_SPORT, l2flow->l4.sport);
cmm_addattr16(nlh, sizeof(buf), L2FLOWA_DPORT, l2flow->l4.dport);
}
}
if (cmm_rtnl_send(&rth, nlh) < 0)
goto err1;
cmm_rtnl_close(&rth);
return 0;
err1:
cmm_rtnl_close(&rth);
err0:
return -1;
}
int cmm_l2flow_netlink_rcv(const struct sockaddr_nl *who, struct nlmsghdr *nlh, void *arg)
{
struct rtattr *tb[L2FLOWA_MAX + 1];
struct cmm_ct *ctx = arg;
switch (nlh->nlmsg_type) {
case L2FLOW_MSG_ENTRY:
case L2FLOW_MSG_RESET:
break;
default:
cmm_print(DEBUG_ERROR, "%s: unsupported ABM netlink message %x\n", __func__, nlh->nlmsg_type);
goto out;
break;
}
if (nlh->nlmsg_type == L2FLOW_MSG_ENTRY)
{
struct l2flow l2flow_tmp;
struct l2flow_msg * l2msg;
int oifi_idx = 0;
int iifi_idx = 0;
short mark = 0;
char action;
memset(&l2flow_tmp, 0, sizeof(l2flow_tmp));
l2msg = NLMSG_DATA(nlh);
memcpy(l2flow_tmp.saddr, l2msg->saddr, ETH_ALEN);
memcpy(l2flow_tmp.daddr, l2msg->daddr, ETH_ALEN);
l2flow_tmp.ethertype = l2msg->ethertype;
action = l2msg->action;
cmm_parse_rtattr(tb, L2FLOWA_MAX, L2FLOWA_RTA(l2msg),L2FLOWA_PAYLOAD(nlh));
if(tb[L2FLOWA_IIF_IDX])
iifi_idx = *(unsigned int *)RTA_DATA((tb[L2FLOWA_IIF_IDX]));
if(tb[L2FLOWA_OIF_IDX])
oifi_idx = *(unsigned int *)RTA_DATA((tb[L2FLOWA_OIF_IDX]));
if(tb[L2FLOWA_VLAN_TAG])
l2flow_tmp.vlan_tag = *(unsigned short *)RTA_DATA((tb[L2FLOWA_VLAN_TAG]));
if(tb[L2FLOWA_PPP_S_ID])
l2flow_tmp.session_id = *(unsigned short *)RTA_DATA((tb[L2FLOWA_PPP_S_ID]));
if(tb[L2FLOWA_MARK])
mark = *(unsigned short *)RTA_DATA((tb[L2FLOWA_MARK]));
if(tb[L2FLOWA_IP_SRC])
memcpy(&l2flow_tmp.l3.saddr.all, RTA_DATA(tb[L2FLOWA_IP_SRC]), RTA_PAYLOAD(tb[L2FLOWA_IP_SRC]));
if(tb[L2FLOWA_IP_DST])
memcpy(&l2flow_tmp.l3.daddr.all, RTA_DATA(tb[L2FLOWA_IP_DST]), RTA_PAYLOAD(tb[L2FLOWA_IP_DST]));
if(tb[L2FLOWA_IP_PROTO])
l2flow_tmp.l3.proto= *(unsigned char *)RTA_DATA(tb[L2FLOWA_IP_PROTO]);
if(tb[L2FLOWA_SPORT])
l2flow_tmp.l4.sport= *(unsigned short *)RTA_DATA(tb[L2FLOWA_SPORT]);
if(tb[L2FLOWA_DPORT])
l2flow_tmp.l4.dport= *(unsigned short *)RTA_DATA(tb[L2FLOWA_DPORT]);
if((action == L2FLOW_ENTRY_NEW) || (action == L2FLOW_ENTRY_UPDATE))
{
__pthread_mutex_lock(&brMutex);
__cmm_l2flow_register(ctx->fci_handle, action, &l2flow_tmp, iifi_idx, oifi_idx, l2msg->flags, mark);
__pthread_mutex_unlock(&brMutex);
}
else if (action == L2FLOW_ENTRY_DEL)
{
__pthread_mutex_lock(&brMutex);
__cmm_l2flow_deregister(ctx->fci_handle, &l2flow_tmp);
__pthread_mutex_unlock(&brMutex);
}
}
else if (nlh->nlmsg_type == L2FLOW_MSG_RESET)
{
__pthread_mutex_lock(&brMutex);
__cmm_l2flow_reset(ctx->fci_handle);
__pthread_mutex_unlock(&brMutex);
}
out:
return RTNL_CB_CONTINUE;
}
#else
int cmm_l2flow_netlink_rcv(const struct sockaddr_nl *who, struct nlmsghdr *nlh, void *arg)
{
return RTNL_CB_CONTINUE;
}
#endif
#ifdef AUTO_BRIDGE
int cmmBridgeInit(struct cmm_ct *ctx)
{
fpp_l2_bridge_control_cmd_t br_cmd;
if (cmm_nl_open(&ctx->rth_abm, L2FLOW_NL_GRP, NETLINK_L2FLOW) < 0)
{
cmm_print(DEBUG_CRIT, "%s: Bridge is started in manual mode\n", __func__);
br_cmd.mode_timeout = FPP_L2_BRIDGE_MODE_MANUAL;
globalConf.auto_bridge = 0;
}
else{
br_cmd.mode_timeout = FPP_L2_BRIDGE_MODE_AUTO;
cmm_print(DEBUG_CRIT, "%s: Bridge is started in auto mode\n", __func__);
globalConf.auto_bridge = 1;
}
/* Set bridge mode in FPP */
cmm_print(DEBUG_COMMAND, "Send FPP_CMD_RX_L2BRIDGE_MODE\n");
if (fci_write(ctx->fci_handle, FPP_CMD_RX_L2BRIDGE_MODE, sizeof(br_cmd), (unsigned short *)&br_cmd)){
cmm_print(DEBUG_ERROR, "Error while trying to set bridge mode\n");
return -1;
}
return 0;
}
#else
int cmmBridgeInit(struct cmm_ct *ctx)
{
globalConf.auto_bridge = 0;
cmm_print(DEBUG_CRIT, "%s: Bridge is started in manual mode\n", __func__);
return 0;
}
#endif
int cmmBridgeControlProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int cpt = tabStart;
fpp_l2_bridge_control_cmd_t cmd;
char rcvBuffer[256];
char *endptr;
unsigned int timeout;
int rc;
if(!keywords[cpt])
goto usage;
if (strcasecmp(keywords[cpt], "timeout") != 0)
goto usage;
if(!keywords[++cpt])
goto usage;
/*Get an integer from the string*/
endptr = NULL;
timeout = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (timeout > UINT16_MAX) || (timeout == 0)){
cmm_print(DEBUG_ERROR, "%s Timeout must be > 0 and < %d s \n",__func__, UINT16_MAX);
goto usage;
}
cmd.mode_timeout = timeout;
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send FPP_CMD_RX_L2BRIDGE_FLOW_TIMEOUT to FPP\n");
rc = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_FLOW_TIMEOUT, (unsigned short *) &cmd, sizeof(fpp_l2_bridge_control_cmd_t), rcvBuffer);
if (rc != 2) /* we expect 2 bytes in response */
{
cmm_print(DEBUG_STDERR, "FPP_CMD_RX_L2BRIDGE_FLOW_TIMEOUT unexpected response length %d\n", rc);
return -1;
}
else if ((((u_int16_t*)rcvBuffer)[0]) != FPP_ERR_OK)
{
cmm_print(DEBUG_STDERR, "Error %d received from FPP\n", ((u_int16_t*)rcvBuffer)[0]);
return -1;
}
return 0;
usage:
cmm_print(DEBUG_STDOUT, "Usage: set bridge timeout {timeout value in seconds}\n");
return -1;
}
/************************************************************
*
*
*
************************************************************/
void cmmRxShowPrintHelp()
{
char buf[128];
print_all_gemac_ports(buf, 128);
// cmm_print(DEBUG_STDOUT, "show rx not yet supported\n");
cmm_print(DEBUG_STDOUT, "Usage: show rx interface {%s} icc\n"
" query rx bridge\n", buf);
}
/************************************************************
*
*
*
************************************************************/
int cmmRxQueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int cpt = tabStart;
unsigned int cmdToSend = 0; /* bits field*/
int rcvBytes = 0;
char rcvBuffer[256];
char null_mac[6] = {0,0,0,0,0,0};
//goto help
if(!keywords[cpt])
goto help;
if(strcasecmp(keywords[cpt], "bridge") == 0)
{
cmdToSend |= CMD_BIT(FPP_CMD_RX_L2BRIDGE_QUERY_STATUS);
}
else
goto keyword_error;
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_L2BRIDGE_QUERY_STATUS))
{
int count = 0;
char input_interface[IFNAMSIZ];
char output_interface[IFNAMSIZ];
char pkt_priority[16];
char vlan_priority[16];
char queue_modifier[16];
fpp_l2_bridge_query_status_response_t *pStatusResponse = (fpp_l2_bridge_query_status_response_t *)rcvBuffer;
fpp_l2_bridge_query_entry_response_t *pEntryResponse = (fpp_l2_bridge_query_entry_response_t *)rcvBuffer;
while( 1 )
{
// Send CMD_RX_L2BRIDGE_QUERY_STATUS command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_QUERY_STATUS, NULL, 0, rcvBuffer);
if ( rcvBytes != sizeof(fpp_l2_bridge_query_status_response_t) )
{
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%04x\n",
(rcvBytes < sizeof(unsigned short) ) ?
0 : *((unsigned short *) rcvBuffer)
);
goto exit;
}
if (pStatusResponse->eof)
break;
cmm_print(DEBUG_STDOUT, "Interface %s Status: %s\n",
pStatusResponse->ifname, pStatusResponse->status ? "ON":"OFF");
}
#if 0
// Send CMD_RX_L2BRIDGE_QUERY_STATUS command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_QUERY_STATUS, NULL, 0, rcvBuffer);
if (rcvBytes != sizeof(fpp_l2_bridge_query_status_response_t) + sizeof(unsigned short))
{
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%04x\n",
(rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer)
);
goto exit;
}
#ifdef WIFI_ENABLE
cmm_print(DEBUG_STDOUT, "Interface %s (WAN) Status: %s\nInterface %s (LAN) Status: %s\nInterface %s (WIFI) Status: %s\nInterface %s (WIFI) Status: %s\n",
WAN_INTERFACE_NAME,
( pStatusResponse->status & (1 << WAN_PORT_ID))? "ON" : "OFF",
LAN_INTERFACE_NAME,
( pStatusResponse->status & (1 << LAN_PORT_ID))? "ON" : "OFF",
WIFI_INTERFACE_NAME0,
( pStatusResponse->status & (1 << WIFI_PORT0)) ? "ON" : "OFF",
WIFI_INTERFACE_NAME1,
( pStatusResponse->status & (1 << WIFI_PORT1)) ? "ON" : "OFF");
#else
cmm_print(DEBUG_STDOUT, "Interface %s (WAN) Status: %s\nInterface %s (LAN) Status: %s\n",
WAN_INTERFACE_NAME,
( pStatusResponse->status & (1 << WAN_PORT_ID))? "ON" : "OFF",
LAN_INTERFACE_NAME,
( pStatusResponse->status & (1 << LAN_PORT_ID))? "ON" : "OFF");
#endif
#endif
while (1)
{
char sessionid_buf[32];
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_QUERY_ENTRY, NULL, 0, rcvBuffer);
if (rcvBytes != sizeof(fpp_l2_bridge_query_entry_response_t))
{
cmm_print(DEBUG_STDERR, "ERROR: CMD_RX_L2BRIDGE_QUERY_ENTRY Unexpected result returned from FPP rc:%04x - received %d - expected %d\n",
(rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer),
rcvBytes,
sizeof(fpp_l2_bridge_query_entry_response_t)
);
goto exit;
}
if (pEntryResponse->eof)
break;
if (pEntryResponse->input_interface >= GEM_PORTS)
strcpy(input_interface, pEntryResponse->input_name);
else
get_port_name(pEntryResponse->input_interface, input_interface, IFNAMSIZ);
if (pEntryResponse->input_vlan != 0xFFFF)
sprintf(input_interface + strlen(input_interface), ".%d", pEntryResponse->input_vlan);
if (pEntryResponse->output_interface >= GEM_PORTS)
strcpy(output_interface, pEntryResponse->output_name);
else
get_port_name(pEntryResponse->output_interface, output_interface, IFNAMSIZ);
if (pEntryResponse->output_vlan != 0xFFFF)
sprintf(output_interface + strlen(output_interface), ".%d", pEntryResponse->output_vlan);
if (pEntryResponse->pkt_priority == 0x8000)
strcpy(pkt_priority, "vlan");
else
sprintf(pkt_priority, "%d", pEntryResponse->pkt_priority);
if (pEntryResponse->vlan_priority == 0x8000)
strcpy(vlan_priority, "copy");
else
sprintf(vlan_priority, "%d", pEntryResponse->vlan_priority);
if (pEntryResponse->session_id != 0)
sprintf(sessionid_buf, "SessionId=%d ", pEntryResponse->session_id);
else
sessionid_buf[0] = '\0';
if(pEntryResponse->queue_modifier == FPP_BRIDGE_QMOD_DSCP)
strcpy(queue_modifier, "dscp");
else
strcpy(queue_modifier, "none");
if ((!memcmp(pEntryResponse->srcaddr, null_mac, 6)) && (pEntryResponse->ethertype == 0))
cmm_print(DEBUG_STDOUT, "Input=%-6s "
"DA=%02X:%02X:%02X:%02X:%02X:%02X "
"SA= * "
"Type= * "
"Queue=%-s "
"Qmod=%-s "
"VLANPrio=%-s "
"%s"
"Output=%s\n",
input_interface,
pEntryResponse->destaddr[0], pEntryResponse->destaddr[1], pEntryResponse->destaddr[2],
pEntryResponse->destaddr[3], pEntryResponse->destaddr[4], pEntryResponse->destaddr[5],
pkt_priority, queue_modifier, vlan_priority, sessionid_buf, output_interface);
else if (!memcmp(pEntryResponse->srcaddr, null_mac, 6))
cmm_print(DEBUG_STDOUT, "Input=%-6s "
"DA=%02X:%02X:%02X:%02X:%02X:%02X "
"SA= * "
"Type=%04X "
"Queue=%-s "
"Qmod=%-s "
"VLANPrio=%-s "
"%s"
"Output=%s\n",
input_interface,
pEntryResponse->destaddr[0], pEntryResponse->destaddr[1], pEntryResponse->destaddr[2],
pEntryResponse->destaddr[3], pEntryResponse->destaddr[4], pEntryResponse->destaddr[5],
pEntryResponse->ethertype, pkt_priority, queue_modifier, vlan_priority, sessionid_buf, output_interface);
else if (pEntryResponse->ethertype == 0)
cmm_print(DEBUG_STDOUT, "Input=%-6s "
"DA=%02X:%02X:%02X:%02X:%02X:%02X "
"SA=%02X:%02X:%02X:%02X:%02X:%02X "
"Type= * "
"Queue=%-s "
"Qmod=%-s "
"VLANPrio=%-s "
"%s"
"Output=%s\n",
input_interface,
pEntryResponse->destaddr[0], pEntryResponse->destaddr[1], pEntryResponse->destaddr[2],
pEntryResponse->destaddr[3], pEntryResponse->destaddr[4], pEntryResponse->destaddr[5],
pEntryResponse->srcaddr[0], pEntryResponse->srcaddr[1], pEntryResponse->srcaddr[2],
pEntryResponse->srcaddr[3], pEntryResponse->srcaddr[4], pEntryResponse->srcaddr[5],
pkt_priority, queue_modifier, vlan_priority, sessionid_buf, output_interface);
else
cmm_print(DEBUG_STDOUT, "Input=%-6s "
"DA=%02X:%02X:%02X:%02X:%02X:%02X "
"SA=%02X:%02X:%02X:%02X:%02X:%02X "
"Type=%04X "
"Queue=%-s "
"Qmod=%-s "
"VLANPrio=%-s "
"%s"
"Output=%s\n",
input_interface,
pEntryResponse->destaddr[0], pEntryResponse->destaddr[1], pEntryResponse->destaddr[2],
pEntryResponse->destaddr[3], pEntryResponse->destaddr[4], pEntryResponse->destaddr[5],
pEntryResponse->srcaddr[0], pEntryResponse->srcaddr[1], pEntryResponse->srcaddr[2],
pEntryResponse->srcaddr[3], pEntryResponse->srcaddr[4], pEntryResponse->srcaddr[5],
pEntryResponse->ethertype, pkt_priority, queue_modifier, vlan_priority, sessionid_buf, output_interface);
count++;
}
cmm_print(DEBUG_STDOUT, "\n%d Bridge Table Entries found\n", count);
}
return 0;
keyword_error:
cmm_print(DEBUG_STDERR, "ERROR: Unknown keyword %s\n", keywords[cpt]);
help:
cmmRxShowPrintHelp();
exit:
return -1;
}
/************************************************************
*
*
*
************************************************************/
int cmmRxShowProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int cpt = tabStart;
unsigned int cmdToSend = 0; /* bits field*/
int rcvBytes = 0;
char rcvBuffer[256];
fpp_rx_icc_disable_cmd_t showCmd; // same structure used for show
fpp_rx_icc_show_return_cmd_t *iccStatus;
//goto help
if(!keywords[cpt])
goto help;
if(strcasecmp(keywords[cpt], "interface") == 0)
{
if(!keywords[++cpt])
goto help;
if ((showCmd.interface = get_port_id(keywords[cpt])) < 0)
goto keyword_error;
if(!keywords[++cpt])
goto help;
if(strcasecmp(keywords[cpt], "icc") == 0)
cmdToSend |= CMD_BIT(FPP_CMD_RX_CNG_SHOW);
else
goto keyword_error;
}
else
goto keyword_error;
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_CNG_SHOW))
{
// Send CMD_RX_CNG_SHOW command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_CNG_SHOW, & showCmd, sizeof(showCmd), rcvBuffer);
if ( rcvBytes < (sizeof(fpp_rx_icc_show_return_cmd_t) - sizeof(unsigned short)) )
{
cmm_print(DEBUG_STDERR, "ERROR: Unexpected returned result from FPP rc:%04x\n",
(rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer)
);
goto exit;
}
else
{
iccStatus = (fpp_rx_icc_show_return_cmd_t *)(rcvBuffer);
cmm_print(DEBUG_STDOUT, "State: %s\n" "Acc: %d\n" "onThr: %d\n" "offThr: %d\n",
(iccStatus->state & 1 )? "Enabled":"Disabled\n", iccStatus->acc_value, iccStatus->on_thr, iccStatus->off_thr);
if (iccStatus->state & 0xfe)
cmm_print(DEBUG_STDOUT, "Flags: 0x%02x\n", iccStatus->state & 0xfe);
}
}
return 0;
keyword_error:
cmm_print(DEBUG_STDERR, "ERROR: Unknown keyword %s\n", keywords[cpt]);
help:
cmmRxShowPrintHelp();
exit:
return -1;
}
/************************************************************
*
*
*
************************************************************/
void cmmRxSetPrintHelp(int cmd_type)
{
char buf[128];
print_all_gemac_ports(buf, 128);
if (cmd_type == UNKNOWN_CMD || cmd_type == ICC_CMD)
{
cmm_print(DEBUG_STDOUT,
"Usage: set rx interface {%s} [icc {on|off}]\n"
" [acc {acc_value}]\n"
" [on_thr {on_thr value}]\n"
" [off_thr {off_thr value}]\n"
" [flag {flag value}]\n"
" [val1 {val1 value}]\n"
" [val2 {val2 value}]\n", buf);
}
if (cmd_type == UNKNOWN_CMD)
{
cmm_print(DEBUG_STDOUT, "\n");
}
if (cmd_type == UNKNOWN_CMD || cmd_type == BRIDGE_CMD)
{
#ifdef WIFI_ENABLE
//FIXME : Now interface names are hardcoded to ath0/ath1. Need to
// find solution to get interface names from config file.
cmm_print(DEBUG_STDOUT,
"Usage: set rx interface {%s|<wi-fi interface>} [bridge {on|off|add|remove}]\n"
" add / remove options:\n"
" [da {dest_addr value}]\n"
" [sa {src_addr value}]\n"
" [type {ethertype value}]\n"
" add options:\n"
" [queue {output queue base value 0-31|vlan}]\n"
" [vlanprio {priority value|copy}]\n"
" [sessionid {session id value}]\n"
" [output {interface}]\n"
" [qmod {output queue modifier dscp|none}]\n", buf);
#else
cmm_print(DEBUG_STDOUT,
"Usage: set rx interface {%s} [bridge {on|off|add|remove}]\n"
" add / remove options:\n"
" [da {dest_addr value}]\n"
" [sa {src_addr value}]\n"
" [type {ethertype value}]\n"
" add options:\n"
" [queue {output queue base value 0-31|vlan}]\n"
" [vlanprio {priority value|copy}]\n"
" [sessionid {session id value}]\n"
" [output {interface}]\n"
" [qmod {output queue modifier dscp|none}]\n", buf);
#endif
}
}
/************************************************************
*
*
*
************************************************************/
static int parse_interface(char *pstring, unsigned short *pinterface_number );
static int parse_interface_vlan(char *pstring, unsigned short *pinterface_number, unsigned short *pvlan_id);
int cmmRxSetProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int cmd_type = UNKNOWN_CMD;
int cpt = tabStart;
unsigned int cmdToSend = 0; /* bits field*/
char * endptr;
unsigned int tmp;
int rcvBytes = 0;
char *pinterface;
unsigned short interface;
fpp_rx_icc_enable_cmd_t enableCmd;
fpp_rx_icc_disable_cmd_t disableCmd;
fpp_l2_bridge_enable_cmd_t bridgeEnableCmd;
fpp_l2_bridge_add_entry_cmd_t bridgeAddCmd;
fpp_l2_bridge_remove_entry_cmd_t bridgeRemoveCmd;
char rcvBuffer[256];
if(!keywords[cpt])
goto help;
if(strcasecmp(keywords[cpt], "interface") == 0)
{
if(!keywords[++cpt])
goto help;
pinterface = keywords[cpt];
}
else
goto keyword_error;
if(!keywords[++cpt])
goto help;
if(strcasecmp(keywords[cpt], "icc") == 0)
{
cmd_type = ICC_CMD;
if(!keywords[++cpt])
goto help;
if(strcasecmp(keywords[cpt], "on") == 0)
{
cmdToSend |= CMD_BIT(FPP_CMD_RX_CNG_ENABLE);
memset(&enableCmd, 0, sizeof(enableCmd));
if (parse_icc_interface(pinterface, &interface, 2) < 0)
goto help;
enableCmd.interface = interface;
cpt++;
while (keywords[cpt] != NULL)
{
if(strcasecmp(keywords[cpt], "acc") == 0)
{
if(!keywords[++cpt])
goto help;
/*Get an integer from the string*/
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > USHRT_MAX))
{
cmm_print(DEBUG_CRIT, "icc ERROR: acc must be a number between 1 and %d\n", USHRT_MAX);
goto help;
}
enableCmd.acc_value = tmp;
}
else if(strcasecmp(keywords[cpt], "on_thr") == 0)
{
if(!keywords[++cpt])
goto help;
/*Get an integer from the string*/
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > USHRT_MAX))
{
cmm_print(DEBUG_CRIT, "icc ERROR: on_thr must be a number between 1 and %d\n", USHRT_MAX);
goto help;
}
enableCmd.on_thr = tmp;
}
else if(strcasecmp(keywords[cpt], "off_thr") == 0)
{
if(!keywords[++cpt])
goto help;
/*Get an integer from the string*/
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > USHRT_MAX))
{
cmm_print(DEBUG_CRIT, "icc ERROR: off_thr must be a number between 1 and %d\n", USHRT_MAX);
goto help;
}
enableCmd.off_thr = tmp;
}
else if (strncasecmp(keywords[cpt],"flag",1) == 0) {
if(!keywords[++cpt])
goto help;
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
enableCmd.flag = tmp;
}
else if (strcasecmp(keywords[cpt],"val1") == 0) {
if(!keywords[++cpt])
goto help;
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
enableCmd.val1 = tmp;
}
else if (strcasecmp(keywords[cpt],"val2") == 0) {
if(!keywords[++cpt])
goto help;
endptr = NULL;
tmp = strtoul(keywords[cpt], &endptr, 0);
enableCmd.val1 = tmp;
}
else
goto help;
cpt ++;
}
}
else if(strcasecmp(keywords[cpt], "off") == 0)
{
cmdToSend |= CMD_BIT(FPP_CMD_RX_CNG_DISABLE);
memset(&disableCmd, 0, sizeof(disableCmd));
if (parse_icc_interface(pinterface, &interface, 2) < 0)
goto help;
disableCmd.interface = interface;
}
else
goto keyword_error;
}
else if(strcasecmp(keywords[cpt], "bridge") == 0)
{
cmd_type = BRIDGE_CMD;
if(!keywords[++cpt])
goto help;
if(strcasecmp(keywords[cpt], "on") == 0)
{
if (keywords[++cpt])
goto help;
cmdToSend |= CMD_BIT(FPP_CMD_RX_L2BRIDGE_ENABLE);
memset(&bridgeEnableCmd, 0, sizeof(bridgeEnableCmd));
bridgeEnableCmd.enable_flag = 1;
bridgeEnableCmd.interface = 0xffff;
strcpy (&bridgeEnableCmd.input_name[0], pinterface);
}
else if(strcasecmp(keywords[cpt], "off") == 0)
{
if (keywords[++cpt])
goto help;
cmdToSend |= CMD_BIT(FPP_CMD_RX_L2BRIDGE_ENABLE);
memset(&bridgeEnableCmd, 0, sizeof(bridgeEnableCmd));
bridgeEnableCmd.enable_flag = 0;
bridgeEnableCmd.interface = 0xffff;
strcpy (&bridgeEnableCmd.input_name[0], pinterface);
}
else if(strcasecmp(keywords[cpt], "add") == 0)
{
cmdToSend |= CMD_BIT(FPP_CMD_RX_L2BRIDGE_ADD);
memset(&bridgeAddCmd, 0, sizeof(bridgeAddCmd));
strcpy(bridgeAddCmd.input_name, pinterface);
bridgeAddCmd.input_interface = 0xffff;
bridgeAddCmd.input_vlan = 0xffff;
bridgeAddCmd.output_interface = 0xffff;
bridgeAddCmd.output_vlan = 0xFFFF;
while (keywords[++cpt] != NULL)
{
if(strcasecmp(keywords[cpt], "da") == 0)
{
if(!keywords[++cpt])
goto help;
if (!parse_macaddr(keywords[cpt], bridgeAddCmd.destaddr))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad MAC address: %s\n", keywords[cpt]);
goto help;
}
}
else if(strcasecmp(keywords[cpt], "sa") == 0)
{
if(!keywords[++cpt])
goto help;
if (!parse_macaddr(keywords[cpt], bridgeAddCmd.srcaddr))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad MAC address: %s\n", keywords[cpt]);
goto help;
}
}
else if(strcasecmp(keywords[cpt], "type") == 0)
{
if(!keywords[++cpt])
goto help;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 0xFFFF))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad ETHERTYPE value: %s\n", keywords[cpt]);
goto help;
}
bridgeAddCmd.ethertype = (unsigned short)tmp;
}
else if(strcasecmp(keywords[cpt], "prio") == 0)
{
if(!keywords[++cpt])
goto help;
if (strcasecmp(keywords[cpt], "vlan") == 0)
bridgeAddCmd.pkt_priority = 0x8000;
else
{
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 7))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad PRIORITY value: %s\n", keywords[cpt]);
goto help;
}
bridgeAddCmd.pkt_priority = (unsigned short)tmp;
}
}
else if(strcasecmp(keywords[cpt], "queue") == 0)
{
if(!keywords[++cpt])
goto help;
if (strcasecmp(keywords[cpt], "vlan") == 0)
bridgeAddCmd.pkt_priority = 0x8000;
else
{
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp >= FPP_NUM_QUEUES))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad QUEUE value: %s\n", keywords[cpt]);
goto help;
}
bridgeAddCmd.pkt_priority = (unsigned short)tmp;
}
}
else if(strcasecmp(keywords[cpt], "vlanprio") == 0)
{
if(!keywords[++cpt])
goto help;
if (strcasecmp(keywords[cpt], "copy") == 0)
bridgeAddCmd.vlan_priority = 0x8000;
else
{
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 7))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad VLAN PRIORITY value: %s\n", keywords[cpt]);
goto help;
}
bridgeAddCmd.vlan_priority = (unsigned short)tmp;
}
}
else if(strcasecmp(keywords[cpt], "sessionid") == 0)
{
if(!keywords[++cpt])
goto help;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 0xFFFF))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad SESSION ID value: %s\n", keywords[cpt]);
goto help;
}
bridgeAddCmd.session_id = (unsigned short)tmp;
}
else if(strcasecmp(keywords[cpt], "output") == 0)
{
if(!keywords[++cpt])
goto help;
bridgeAddCmd.output_interface = 0xFFFF;
bridgeAddCmd.input_interface = 0xFFFF;
bridgeAddCmd.output_vlan = 0xFFFF;
strcpy(bridgeAddCmd.output_name, keywords[cpt]);
strcpy(bridgeAddCmd.input_name, pinterface);
}
else if(strcasecmp(keywords[cpt], "qmod") == 0)
{
if(!keywords[++cpt])
goto help;
if (strcasecmp(keywords[cpt], "dscp") == 0)
bridgeAddCmd.queue_modifier = FPP_BRIDGE_QMOD_DSCP;
else if(strcasecmp(keywords[cpt], "none") == 0)
bridgeAddCmd.queue_modifier = FPP_BRIDGE_QMOD_NONE;
else {
bridgeAddCmd.queue_modifier = FPP_BRIDGE_QMOD_NONE;
cmm_print(DEBUG_CRIT, "bridge ERROR: bad QUEUE MODIFIER value: %s\n", keywords[cpt]);
goto help;
}
}
else
goto help;
}
}
else if(strcasecmp(keywords[cpt], "remove") == 0)
{
cmdToSend |= CMD_BIT(FPP_CMD_RX_L2BRIDGE_REMOVE);
memset(&bridgeRemoveCmd, 0, sizeof(bridgeRemoveCmd));
strcpy(bridgeRemoveCmd.input_name, pinterface);
bridgeRemoveCmd.input_interface = 0xffff;
bridgeRemoveCmd.input_vlan = 0xffff;
while (keywords[++cpt] != NULL)
{
if(strcasecmp(keywords[cpt], "da") == 0)
{
if(!keywords[++cpt])
goto help;
if (!parse_macaddr(keywords[cpt], bridgeRemoveCmd.destaddr))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad MAC address: %s\n", keywords[cpt]);
goto help;
}
}
else if(strcasecmp(keywords[cpt], "sa") == 0)
{
if(!keywords[++cpt])
goto help;
if (!parse_macaddr(keywords[cpt], bridgeRemoveCmd.srcaddr))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad MAC address: %s\n", keywords[cpt]);
goto help;
}
}
else if(strcasecmp(keywords[cpt], "type") == 0)
{
if(!keywords[++cpt])
goto help;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 0xFFFF))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad ETHERTYPE value: %s\n", keywords[cpt]);
goto help;
}
bridgeRemoveCmd.ethertype = (unsigned short)tmp;
}
else if(strcasecmp(keywords[cpt], "sessionid") == 0)
{
if(!keywords[++cpt])
goto help;
tmp = strtoul(keywords[cpt], &endptr, 0);
if ((keywords[cpt] == endptr) || (tmp > 0xFFFF))
{
cmm_print(DEBUG_CRIT, "bridge ERROR: bad SESSION ID value: %s\n", keywords[cpt]);
goto help;
}
bridgeRemoveCmd.session_id = (unsigned short)tmp;
}
else
goto help;
}
}
else
goto keyword_error;
}
else
goto keyword_error;
/*
* Parsing have been performed
* Now send the right commands
*/
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_L2BRIDGE_ENABLE))
{
// Send CMD_RX_L2BRIDGE_ENABLE command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_ENABLE, & bridgeEnableCmd, sizeof(bridgeEnableCmd), rcvBuffer);
}
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_L2BRIDGE_ADD))
{
// Send CMD_RX_L2BRIDGE_ADD command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_ADD, & bridgeAddCmd, sizeof(bridgeAddCmd), rcvBuffer);
}
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_L2BRIDGE_REMOVE))
{
// Send CMD_RX_L2BRIDGE_REMOVE command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2BRIDGE_REMOVE, & bridgeRemoveCmd, sizeof(bridgeRemoveCmd), rcvBuffer);
}
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_CNG_DISABLE))
{
// Send CMD_RX_CNG_DISABLE command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_CNG_DISABLE, & disableCmd, sizeof(disableCmd), rcvBuffer);
}
if(TEST_CMD_BIT(cmdToSend, FPP_CMD_RX_CNG_ENABLE))
{
// Send CMD_RX_CNG_ENABLE command
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_CNG_ENABLE, & enableCmd, sizeof(enableCmd), rcvBuffer);
}
if ((rcvBytes != 2) || *((unsigned short *) rcvBuffer)) {
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%04x\n",
(rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer)
);
return -1;
}
return 0;
keyword_error:
cmm_print(DEBUG_CRIT, "ERROR: Unknown keyword %s\n", keywords[cpt]);
help:
cmmRxSetPrintHelp(cmd_type);
return -1;
}
/*********************************************************************************
*
*
*
********************************************************************************/
int cmmL2BridgeProcessClientCmd(FCI_CLIENT* fci_handle, int fc, u_int8_t *cmd_buf, u_int16_t cmd_len, u_int16_t *res_buf, u_int16_t *res_len)
{
fpp_l2_bridge_enable_cmd_t *bridgeEnableCmd;
fpp_l2_bridge_add_entry_cmd_t *bridgeAddCmd;
fpp_l2_bridge_remove_entry_cmd_t *bridgeRemoveCmd;
unsigned short vlan_id, interface;
cmm_print(DEBUG_INFO, "%s\n", __func__);
res_buf[0] = CMMD_ERR_WRONG_COMMAND_SIZE;
switch(fc)
{
case FPP_CMD_RX_L2BRIDGE_ENABLE:
cmm_print(DEBUG_INFO, "2 %s\n", __func__);
bridgeEnableCmd = (fpp_l2_bridge_enable_cmd_t *)cmd_buf;
*res_len = 2;
if( cmd_len < sizeof(fpp_l2_bridge_enable_cmd_t) )
{
cmm_print(DEBUG_ERROR, "%s: Bridge enable command size too small(%d, %d)\n",
__func__, cmd_len, sizeof(fpp_l2_bridge_enable_cmd_t));
return 0;
}
if( parse_interface(bridgeEnableCmd->input_name, &interface) < 0 )
{
cmm_print(DEBUG_ERROR, "%s: Bridge enable command with unknown interface: %s\n",
__func__, bridgeEnableCmd->input_name);
res_buf[0] = CMMD_ERR_NOT_CONFIGURED;
return 0;
}
bridgeEnableCmd->interface = interface;
goto FCI_CMD;
case FPP_CMD_RX_L2BRIDGE_ADD:
bridgeAddCmd = (fpp_l2_bridge_add_entry_cmd_t *)cmd_buf;
*res_len = 2;
if( cmd_len < sizeof(fpp_l2_bridge_add_entry_cmd_t) )
{
cmm_print(DEBUG_ERROR, "%s: Bridge add command size too small(%d, %d)\n",
__func__, cmd_len, sizeof(fpp_l2_bridge_add_entry_cmd_t));
return 0;
}
if( parse_interface_vlan(bridgeAddCmd->input_name, &interface, &vlan_id) < 0 )
{
cmm_print(DEBUG_ERROR, "%s: Bridge add command with unknown interface: %s\n",
__func__, bridgeAddCmd->input_name);
res_buf[0] = CMMD_ERR_NOT_CONFIGURED;
return 0;
}
bridgeAddCmd->input_interface = interface;
bridgeAddCmd->input_vlan = vlan_id;
/* FIXME : output interface should be provided by the user */
// bridgeAddCmd->output_interface = interface == GEMAC0_PORT ? GEMAC1_PORT : GEMAC0_PORT;
// bridgeAddCmd->output_vlan = 0xFFFF;
// if (!strlen(bridgeAddCmd->output_name))
// goto FCI_CMD;
if( parse_interface_vlan(bridgeAddCmd->output_name, &interface, &vlan_id) == 0 )
{
bridgeAddCmd->output_interface = interface;
bridgeAddCmd->output_vlan = vlan_id;
}
else
{
bridgeAddCmd->output_interface = 0xFFFF;
bridgeAddCmd->input_interface = 0xFFFF;
bridgeAddCmd->output_vlan = 0xFFFF;
}
goto FCI_CMD;
case FPP_CMD_RX_L2BRIDGE_REMOVE:
bridgeRemoveCmd = (fpp_l2_bridge_remove_entry_cmd_t *)cmd_buf;
*res_len = 2;
if( cmd_len < sizeof(fpp_l2_bridge_remove_entry_cmd_t) )
{
cmm_print(DEBUG_ERROR, "%s: Bridge remove command size too small(%d, %d)\n",
__func__, cmd_len, sizeof(fpp_l2_bridge_remove_entry_cmd_t));
return 0;
}
if( parse_interface_vlan(bridgeRemoveCmd->input_name, &interface, &vlan_id) < 0 )
{
cmm_print(DEBUG_ERROR, "%s: Bridge remove command with unknown interface: %s\n",
__func__, bridgeRemoveCmd->input_name);
res_buf[0] = CMMD_ERR_NOT_CONFIGURED;
return 0;
}
bridgeRemoveCmd->input_interface = interface;
bridgeRemoveCmd->input_vlan = vlan_id;
goto FCI_CMD;
case FPP_CMD_RX_L2BRIDGE_QUERY_STATUS:
case FPP_CMD_RX_L2BRIDGE_QUERY_ENTRY:
goto FCI_CMD;
}
FCI_CMD:
return fci_cmd(fci_handle, fc, (u_int16_t*)cmd_buf, cmd_len, res_buf, res_len);
}
int parse_icc_interface(char *pstring, unsigned short *pinterface_number, int num_interfaces)
{
u_int32_t interface;
if ((short)(*pinterface_number = get_port_id(pstring)) < 0)
{
if (parse_value(pstring, &interface, num_interfaces - 1) == 0)
{
*pinterface_number = interface;
}
else
{
return -1;
}
}
return 0;
}
static int parse_interface(char *pstring, unsigned short *pinterface_number)
{
if ((short)(*pinterface_number = get_port_id(pstring)) < 0)
{
#ifdef WIFI_ENABLE
int i, ret;
__pthread_mutex_lock(&itf_table.lock);
ret = __itf_is_programmed(if_nametoindex(pstring));
__pthread_mutex_unlock(&itf_table.lock);
if( ret <= 0 )
return -1;
for (i = 0; i < MAX_WIFI_FF_IFS; i++)
{
if( !strcmp(pstring, glbl_wifi_ff_ifs[i].ifname) && glbl_wifi_ff_ifs[i].used )
{
*pinterface_number = WIFI_PORT0 + i;
break;
}
}
if( i >= MAX_WIFI_FF_IFS )
#endif
return -1;
}
return 0;
}
static int parse_interface_vlan(char *pstring, unsigned short *pinterface_number, unsigned short *pvlan_id)
{
char interface[16];
char *pperiod;
char *peos;
unsigned long vlan_id;
strncpy(interface, pstring, sizeof(interface) - 1);
pperiod = strchr(interface, '.');
if (pperiod)
*pperiod++ = '\0';
if ((short)(*pinterface_number = get_port_id(pstring)) < 0)
{
#ifdef WIFI_ENABLE
int i, ret;
__pthread_mutex_lock(&itf_table.lock);
ret = __itf_is_programmed(if_nametoindex(interface));
__pthread_mutex_unlock(&itf_table.lock);
if( ret <= 0 )
return -1;
for (i = 0; i < MAX_WIFI_FF_IFS; i++)
{
if( !strcmp(interface, glbl_wifi_ff_ifs[i].ifname) && glbl_wifi_ff_ifs[i].used )
{
*pinterface_number = WIFI_PORT0 + 1;
break;
}
}
if( i >= MAX_WIFI_FF_IFS )
#endif
return -1;
}
if (pperiod)
{
vlan_id = strtoul(pperiod, &peos, 10);
if (peos == pperiod || *peos != '\0' || vlan_id > 4094)
{
cmm_print(DEBUG_CRIT, "ERROR: Invalid VLAN specification: %s\n", pstring);
return -1;
}
*pvlan_id = (unsigned short)vlan_id;
}
else
*pvlan_id = 0xFFFF;
return 0;
}
int parse_macaddr(char *pstring, unsigned char *pmacaddr)
{
int i, n;
unsigned long nextbyte;
char *endp;
for (i = 0; i < 6; i++)
{
nextbyte = strtoul(pstring, &endp, 16);
n = endp - pstring;
if (n < 1 || n > 2)
return 0;
if ((i < 5 && *endp != ':') || (i == 5 && *endp != '\0'))
return 0;
*pmacaddr++ = (unsigned char)nextbyte;
pstring = endp + 1;
}
return 1;
}