| /* |
| * |
| * 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 <net/if.h> |
| #include <netinet/in.h> |
| #include <sys/socket.h> |
| #include <sys/ioctl.h> |
| |
| #include "cmm.h" |
| #include "cmmd.h" |
| #include "module_mc6.h" |
| |
| #define MC6_MAX_LISTENERS_IN_QUERY 5 |
| |
| unsigned char Null_Mac[6] = {0,0,0,0,0,0}; |
| |
| extern pthread_mutex_t mc_lock; |
| |
| int cmmMc6Show(struct cli_def * cli, char *command, char *argv[], int argc) |
| { |
| int count = 0, ii, jj; |
| struct list_head *entry; |
| struct mcast_entry *mc; |
| char buf1[INET6_ADDRSTRLEN]; |
| char buf2[INET6_ADDRSTRLEN]; |
| |
| __pthread_mutex_lock(&mc_lock); |
| |
| for( ii = 0; ii < MC_NUM_HASH_ENTRIES; ii++ ) |
| { |
| for (entry = list_first(&mc_table[ii]); entry != &mc_table[ii]; entry = list_next(entry)) |
| { |
| mc = container_of(entry, struct mcast_entry, list); |
| |
| if( mc->family != AF_INET6 ) |
| continue; |
| |
| cmm_print(DEBUG_STDOUT, "%04d: Src addr: %s src_mask_len: %x Dst addr: %s Queue %d \n", |
| count, |
| inet_ntop(AF_INET6, &mc->src_addr, buf1, INET6_ADDRSTRLEN), |
| mc->src_mask_len, |
| inet_ntop(AF_INET6, &mc->dst_addr, buf2, INET6_ADDRSTRLEN), |
| mc->queue); |
| for( jj = 0; jj < mc->num_output; jj++) |
| { |
| cmm_print(DEBUG_STDOUT," PROGRAMMED : %02d TIMER : 0x%x SHAPER : 0x%x Interface %s\n",mc->l_program[jj], |
| mc->listener[jj].timer,mc->listener[jj].shaper_mask, mc->listener[jj].output_device_str); |
| if(mc->listener[jj].q_bit) |
| cmm_print(DEBUG_STDOUT," QUEUE : 0x%x \n",mc->listener[jj].queue ); |
| if(mc->listener[jj].uc_bit) |
| cmm_print(DEBUG_STDOUT,"UC MAC is %02x:%02x:%02x:%02x:%02x:%02x ",mc->listener[jj].uc_mac[0],mc->listener[jj].uc_mac[1],mc->listener[jj].uc_mac[2],mc->listener[jj].uc_mac[3],mc->listener[jj].uc_mac[4],mc->listener[jj].uc_mac[5]); |
| } |
| count++; |
| |
| } |
| } |
| cmm_print(DEBUG_STDOUT, "Total Multicast v6 Entries: %d\n", count); |
| __pthread_mutex_unlock(&mc_lock); |
| |
| return 0; |
| } |
| |
| /************************************************************ |
| * |
| * |
| * |
| ************************************************************/ |
| void cmmMc6ShowPrintHelp() |
| { |
| cmm_print(DEBUG_STDOUT, "show mc6 not yet supported\n"); |
| } |
| |
| |
| /************************************************************ |
| * |
| * |
| * |
| ************************************************************/ |
| int cmmMc6ShowProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle) |
| { |
| |
| //help: |
| cmmMc6ShowPrintHelp(); |
| return -1; |
| } |
| |
| /************************************************************ |
| * |
| * |
| * |
| ************************************************************/ |
| int cmmMc6QueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle) |
| { |
| |
| int rcvBytes = 0; |
| char rcvBuffer[256]; |
| char buf1[INET6_ADDRSTRLEN]; |
| char buf2[INET6_ADDRSTRLEN]; |
| char output_buf[256]; |
| short rc; |
| int count = 0,len =0; |
| cmmd_mc6_entry_t *mc6_entry = (cmmd_mc6_entry_t *) rcvBuffer; |
| cmmd_mc6_listener_t* mc6_listener = (cmmd_mc6_listener_t *)(rcvBuffer + sizeof (cmmd_mc6_entry_t)); |
| |
| mc6_entry->action = CMMD_ACTION_QUERY; |
| rcvBytes = cmmSendToDaemon(daemon_handle,CMMD_CMD_MC6_MULTICAST , |
| mc6_entry, sizeof(cmmd_mc6_entry_t)+ MC6_MAX_LISTENERS_IN_QUERY * sizeof(cmmd_mc6_listener_t) , rcvBuffer); |
| |
| if (rcvBytes < sizeof(cmmd_mc6_entry_t) + sizeof (cmmd_mc6_listener_t) + sizeof(unsigned short)) { |
| rc = (rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer); |
| if (rc == CMMD_ERR_UNKNOWN_ACTION) { |
| cmm_print(DEBUG_STDERR, "ERROR: FPP CMD_MC6_MULTICAST does not support ACTION_QUERY\n"); |
| } else if (rc == CMMD_ERR_MC_ENTRY_NOT_FOUND) { |
| cmm_print(DEBUG_STDERR, "ERROR: FPP Multicast V6 table empty\n"); |
| } else { |
| cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%d\n", rc); |
| } |
| return CLI_OK; |
| } |
| cmm_print(DEBUG_STDOUT, "IPv6 Multicast Entries:\n"); |
| do { |
| int i, listner_count; |
| if(mc6_entry->dst_addr[0] & 0xFF) |
| { |
| cmm_print(DEBUG_STDOUT, "\n%04d: Src addr: %s src_mask_len: %x Dst addr: %s Queue: 0x%x \n\n", |
| count, |
| inet_ntop(AF_INET6, &mc6_entry->src_addr, buf1, INET6_ADDRSTRLEN), |
| mc6_entry->src_mask_len, |
| inet_ntop(AF_INET6, &mc6_entry->dst_addr, buf2, INET6_ADDRSTRLEN), |
| mc6_entry->queue ); |
| count++; |
| } |
| listner_count = mc6_entry->num_output; |
| if (listner_count > MC6_MAX_LISTENERS_IN_QUERY) |
| { |
| cmm_print(DEBUG_STDOUT,"output interfaces are more than %d",MC6_MAX_LISTENERS_IN_QUERY); |
| listner_count = MC6_MAX_LISTENERS_IN_QUERY; |
| } |
| |
| for ( i = 0; i < listner_count; i++) |
| { |
| len += sprintf(output_buf + len, "output interface: "); |
| len += sprintf(output_buf + len, "%s ", mc6_listener[i].output_device_str); |
| cmm_print (DEBUG_STDOUT,output_buf); |
| if(mc6_listener[i].uc_bit) |
| cmm_print(DEBUG_STDOUT,"UC MAC is %02x:%02x:%02x:%02x:%02x:%02x ",mc6_listener[i].uc_mac[0],mc6_listener[i].uc_mac[1],mc6_listener[i].uc_mac[2],mc6_listener[i].uc_mac[3],mc6_listener[i].uc_mac[4],mc6_listener[i].uc_mac[5]); |
| cmm_print(DEBUG_STDOUT," TIMER : 0x%x SHAPER : 0x%x QUEUE : 0x%x\n",mc6_listener[i].timer,mc6_listener[i].shaper_mask, mc6_listener[i].queue); |
| len = 0; |
| } |
| |
| mc6_entry->action = CMMD_ACTION_QUERY_CONT; |
| rcvBytes = cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MULTICAST, mc6_entry, |
| sizeof(cmmd_mc6_entry_t)+ MC6_MAX_LISTENERS_IN_QUERY * sizeof(cmmd_mc6_listener_t), rcvBuffer); |
| } while (rcvBytes >= sizeof(cmmd_mc6_entry_t)+ sizeof(cmmd_mc6_listener_t) + sizeof(unsigned short)); |
| cmm_print(DEBUG_STDOUT, "Total Multicast v6 Entries: %d\n", count); |
| |
| return CLI_OK; |
| |
| } |
| |
| |
| /************************************************************ |
| * |
| * |
| * |
| ************************************************************/ |
| void cmmMc6SetPrintHelp() |
| { |
| #ifdef COMCERTO_2000 |
| cmm_print(DEBUG_STDOUT, "Usage: set mc6 interface {if_name} {add | del | update } \n\tgroup {bit_mask} {IPv6 Src Address} {IPv6 Multicast Dst Address} [mode {bridged | routed}] [queue {0..19}] \n\t[listener [timer {timer_value1}] [shapers {0..0xFF}][mc | uc {Mac addr1} ] [queue {0..19}]] [if {if_name}] \n\t [ listener [timer {timer_value2}] [shapers {0..0xFF}][mc | uc {Mac addr2} ] [queue {0..19}]] [if {if_name}]... \n\t[ listener [timer {timer_valueN}] [shapers {0..0xFF}][mc | uc {Mac addrN} ] [queue {0..19}]] [if {if_name}]"); |
| #else |
| cmm_print(DEBUG_STDOUT, "Usage: set mc6 interface {if_name} {add | del | update } \n\tgroup {bit_mask} {IPv6 Src Address} {IPv6 Multicast Dst Address} [mode {bridged | routed}] [queue {0..31}]\n\t[listener [timer {timer_value1}] [shapers {0..0xFF}][mc | uc {Mac addr1} ] [queue {0..31}]] [if {if_name}] \n\t [ listener [timer {timer_value2}] [shapers {0..0xFF}][mc | uc {Mac addr2} ] [queue {0..31}]] [if {if_name}]... \n\t[ listener [timer {timer_valueN}] [shapers {0..0xFF}][mc | uc {Mac addrN} ] [queue {0..31}]] [if {if_name}] "); |
| #endif |
| cmm_print(DEBUG_STDOUT, "\n\nUsage:set mc6 mode route|bridge\n"); |
| } |
| |
| /************************************************************ |
| * cmmMc6ParseListener |
| * This function parses the mc6 command with multiple listeners |
| * and a single listener alike. |
| * |
| ************************************************************/ |
| int cmmMcParseListener(char ** keywords, int *cpt, cmmd_mc6_listener_t * listener, u_int8_t * mode, u_int16_t action) |
| { |
| |
| unsigned int tmp; |
| char * endptr; |
| |
| listener->timer = 0xFFFFFFFF; |
| listener->q_bit = 0; |
| listener->uc_bit = 0; // Multicast by default when a new entry is added |
| listener->Ifbit = 0; |
| |
| while(keywords[*cpt] && (strncasecmp(keywords[*cpt],"listener",strlen(keywords[*cpt])) != 0)) |
| { |
| if(strcasecmp(keywords[*cpt],"mc") == 0) |
| { |
| listener->uc_bit = 0; |
| } |
| else if(strcasecmp(keywords[*cpt],"uc") == 0) |
| { |
| if(!keywords[++*cpt]) |
| return 1; |
| listener->uc_bit = 1; |
| if (!parse_macaddr(keywords[*cpt], listener->uc_mac)) |
| { |
| cmm_print(DEBUG_STDERR, "ERROR %d Invalid Mac Address \n",CMMD_ERR_MC_INVALID_MAC); |
| return 1; |
| } |
| if((listener->uc_mac[0] & 0x01) || !memcmp(listener->uc_mac,Null_Mac,6)) |
| { |
| cmm_print(DEBUG_STDERR, "ERROR %d Invalid Mac Address \n",CMMD_ERR_MC_INVALID_MAC); |
| return 1; |
| } |
| } |
| |
| else if (strcasecmp(keywords[*cpt], "timer") == 0) |
| { |
| if(!keywords[++*cpt]) |
| return 1; |
| |
| /*Get an integer from the string*/ |
| endptr = NULL; |
| tmp = strtoul(keywords[*cpt], &endptr, 0); |
| listener->timer = tmp; |
| } |
| else if (strcasecmp(keywords[*cpt], "mode") == 0) |
| { |
| if(!keywords[++*cpt]) |
| return 1; |
| |
| if (strcasecmp(keywords[*cpt], "bridged") == 0) |
| *mode = CMMD_MC6_MODE_BRIDGED; |
| else if (strcasecmp(keywords[*cpt], "routed") == 0) |
| *mode = CMMD_MC6_MODE_ROUTED; |
| else |
| return 1; |
| |
| } |
| else if (strcasecmp(keywords[*cpt], "queue") == 0) |
| { |
| |
| if(!keywords[++*cpt]) |
| return 1; |
| |
| /*Get an integer from the string*/ |
| endptr = NULL; |
| tmp = strtoul(keywords[*cpt], &endptr, 0); |
| listener->q_bit = 1; |
| |
| if (tmp < FPP_NUM_QUEUES) |
| listener->queue = tmp; |
| else |
| return 1; |
| } |
| else if (strcasecmp(keywords[*cpt], "shapers") == 0) |
| { |
| if(!keywords[++*cpt]) |
| return 1; |
| |
| /*Get an integer from the string*/ |
| endptr = NULL; |
| tmp = strtoul(keywords[*cpt], &endptr, 0); |
| |
| if (tmp <= 0xFF) |
| listener->shaper_mask = tmp; |
| else |
| return 1; |
| } |
| else if(strcasecmp(keywords[*cpt],"if") == 0 ) |
| { |
| if(action != CMMD_MC_ACTION_UPDATE) |
| return 1; |
| |
| if(!keywords[++*cpt]) |
| return 1; |
| |
| if (strlen(keywords[*cpt]) > 10) { |
| cmm_print(DEBUG_STDERR, "Error : interface name %s limited to 10 characters\n", keywords[*cpt]); |
| return 1; |
| } |
| strcpy(listener->new_output_device_str, keywords[*cpt]); |
| listener->Ifbit = 1; |
| } |
| else |
| return 1; |
| ++*cpt; |
| |
| } |
| return 0; |
| } |
| |
| |
| /************************************************************ |
| * |
| * |
| * |
| ************************************************************/ |
| int cmmMc6SetProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle) |
| { |
| int cpt = tabStart; |
| unsigned int tmp; |
| char * endptr; |
| int rc = 0; |
| char sndBuffer[256]; |
| char rcvBuffer[256]; |
| char interfaceName[11] = {}; |
| cmmd_mc6_entry_t * entryCmd = (cmmd_mc6_entry_t *) sndBuffer; |
| cmmd_mc6_listener_t * listener = (cmmd_mc6_listener_t *) (sndBuffer + sizeof(cmmd_mc6_entry_t)); |
| int listenerCnt = 0; |
| u_int8_t mode = 0; |
| |
| memset(sndBuffer, 0, sizeof(sndBuffer)); |
| listener->timer = 0xFFFFFFFF; |
| listener->q_bit = 0; |
| listener->uc_bit = 0; // Multicast by default when a new entry is added |
| listener->Ifbit = 0; |
| |
| if(!keywords[cpt]) |
| goto help; |
| |
| if(strcasecmp(keywords[cpt], "interface") == 0) |
| { |
| if(!keywords[++cpt]) |
| goto help; |
| |
| if (strlen(keywords[cpt]) > 10) { |
| cmm_print(DEBUG_STDERR, "Error : interface name %s limited to 10 characters\n", keywords[cpt]); |
| goto help; |
| } |
| strcpy(interfaceName, keywords[cpt]); |
| strcpy(listener->output_device_str,interfaceName); |
| } |
| else if(strcasecmp(keywords[cpt], "reset") == 0) |
| { |
| /*Reset, special case*/ |
| if(cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_RESET, NULL, 0, rcvBuffer) == 2) |
| { |
| if ( ((unsigned short *)rcvBuffer)[0] != 0) |
| cmm_print(DEBUG_STDERR, "Error %d received from FPP for CMD_MC6_RESET\n", ((unsigned short *)rcvBuffer)[0]); |
| } |
| return ((unsigned short *)rcvBuffer)[0]; |
| } |
| else if (strcasecmp(keywords[cpt], "mode") == 0) |
| { |
| unsigned short mc6_mode; |
| |
| if (!keywords[++cpt]) |
| goto help; |
| |
| if (strcasecmp(keywords[cpt], "bridge") == 0) |
| mc6_mode = CMMD_MC6_MODE_BRIDGED; |
| else if (strcasecmp(keywords[cpt], "route") == 0) |
| mc6_mode = CMMD_MC6_MODE_ROUTED; |
| else |
| goto help; |
| |
| if(cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MODE, &mc6_mode, sizeof(mc6_mode), rcvBuffer) == 2) |
| { |
| if ( ((unsigned short *)rcvBuffer)[0] != 0) |
| cmm_print(DEBUG_STDERR, "Error %d received from FPP for CMD_MC6_MODE\n", ((unsigned short *)rcvBuffer)[0]); |
| } |
| return ((unsigned short *)rcvBuffer)[0]; |
| |
| } |
| else |
| goto keyword_error; |
| |
| if(!keywords[++cpt]) |
| goto help; |
| |
| if(strcasecmp(keywords[cpt], "add") == 0) |
| { |
| entryCmd->action = CMMD_MC_ACTION_ADD; |
| } |
| else if(strcasecmp(keywords[cpt], "del") == 0) |
| { |
| entryCmd->action = CMMD_MC_ACTION_REMOVE; |
| } |
| else if(strcasecmp(keywords[cpt], "update") == 0) |
| { |
| entryCmd->action = CMMD_MC_ACTION_UPDATE; |
| } |
| else |
| goto keyword_error; |
| |
| if(!keywords[++cpt]) |
| goto help; |
| |
| if (strcasecmp(keywords[cpt], "group") == 0) |
| { |
| if(!keywords[++cpt]) |
| goto help; |
| |
| /*Get an integer from the string for the MASK*/ |
| endptr = NULL; |
| tmp = strtoul(keywords[cpt], &endptr, 0); |
| entryCmd->src_mask_len = tmp; |
| |
| if(!keywords[++cpt]) |
| goto help; |
| |
| /*Get an integer from the string for the IPsrc*/ |
| if(inet_pton(AF_INET6, keywords[cpt], &entryCmd->src_addr) != 1) |
| goto help; |
| |
| if(!keywords[++cpt]) |
| goto help; |
| |
| /*Get an integer from the string for the IPdst*/ |
| if(inet_pton(AF_INET6, keywords[cpt], &entryCmd->dst_addr) != 1) |
| goto help; |
| |
| if (! (entryCmd->dst_addr[0] & 0xFF)) |
| goto help; |
| } |
| |
| ++cpt; |
| |
| while(keywords[cpt]) |
| { |
| strcpy(((cmmd_mc6_listener_t *)listener + listenerCnt)->output_device_str,interfaceName); |
| if (strncasecmp(keywords[cpt], "listener",strlen(keywords[cpt])) == 0) //May be a case of multiple listeners, parse differently |
| { |
| ++cpt; |
| if(!cmmMcParseListener(keywords, &cpt, listener + listenerCnt, &mode, entryCmd->action)) |
| { |
| if(++listenerCnt == MC6_MAX_LISTENERS_IN_QUERY) |
| //Send first batch to FPP and reset listener count |
| { |
| |
| entryCmd->num_output = listenerCnt; |
| if(cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MULTICAST, sndBuffer, sizeof(cmmd_mc6_entry_t) + (listenerCnt * sizeof(cmmd_mc6_listener_t)), rcvBuffer) == 2) |
| { |
| if ( (rc = ((unsigned short *)rcvBuffer)[0]) != 0) |
| { |
| if(rc == CMMD_ERR_NOT_CONFIGURED) |
| cmm_print(DEBUG_STDERR, "%d Interface not yet up in FPP, will be configured when interface comes up\n", rc); |
| else if(rc == CMMD_ERR_MC_MAX_LISTENERS) |
| cmm_print(DEBUG_STDERR, "Error %d MAX listeners for the group exhausted\n", rc); |
| else if(rc == CMMD_ERR_MC_INTERFACE_NOT_ALLOWED) |
| cmm_print(DEBUG_STDERR, "Error %d Interface configured cannot support Unicast MAC\n", rc); |
| else if(rc == CMMD_ERR_MC_ENTRY_OVERLAP) |
| { |
| cmm_print(DEBUG_STDERR, "Error %d Overlapping entry configured\n", rc); |
| entryCmd->action = CMMD_MC_ACTION_REMOVE_LOCAL; |
| cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MULTICAST, sndBuffer, |
| sizeof(cmmd_mc6_entry_t) + (listenerCnt * sizeof(cmmd_mc6_listener_t)), rcvBuffer); |
| } |
| else |
| cmm_print(DEBUG_STDERR, "Error %d received from FPP for CMD_MC6_MULTICAST\n", rc); |
| } |
| } |
| listenerCnt = 0; |
| memset(sndBuffer + sizeof(cmmd_mc6_entry_t), 0 , sizeof(sndBuffer) - sizeof(cmmd_mc6_entry_t)); |
| } |
| } |
| else |
| goto help; |
| } |
| else |
| { |
| if(!cmmMcParseListener(keywords, &cpt, listener, &mode, entryCmd->action)) |
| { |
| listener->q_bit = 0; // Default config listener q_bit is always zero. |
| entryCmd->queue = listener->queue; |
| entryCmd->mode = mode; |
| } |
| else |
| goto help; |
| } |
| |
| } |
| if(!listenerCnt & !entryCmd->num_output) |
| listenerCnt = 1; //fall back to legacy design, single listener is configured. |
| |
| entryCmd->num_output = listenerCnt; |
| |
| if(listenerCnt && (cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MULTICAST, sndBuffer, sizeof(cmmd_mc6_entry_t) + (listenerCnt * sizeof(cmmd_mc6_listener_t)), rcvBuffer) == 2)) |
| { |
| if ( (rc = ((unsigned short *)rcvBuffer)[0]) != 0) |
| { |
| if(rc == CMMD_ERR_NOT_CONFIGURED) |
| cmm_print(DEBUG_STDERR, "%d Interface not yet up in FPP, will be configured when interface comes up\n", rc); |
| else if(rc == CMMD_ERR_MC_MAX_LISTENERS) |
| cmm_print(DEBUG_STDERR, "Error %d MAX listeners for the group exhausted\n", rc); |
| else if(rc == CMMD_ERR_MC_INTERFACE_NOT_ALLOWED) |
| cmm_print(DEBUG_STDERR, "Error %d Interface configured cannot support Unicast MAC\n", rc); |
| else if(rc == CMMD_ERR_MC_ENTRY_OVERLAP) |
| { |
| cmm_print(DEBUG_STDERR, "Error %d Overlapping entry configured\n", rc); |
| entryCmd->action = CMMD_MC_ACTION_REMOVE_LOCAL; |
| cmmSendToDaemon(daemon_handle, CMMD_CMD_MC6_MULTICAST, sndBuffer, |
| sizeof(cmmd_mc6_entry_t) + (listenerCnt * sizeof(cmmd_mc6_listener_t)), rcvBuffer); |
| } |
| else |
| cmm_print(DEBUG_STDERR, "Error %d received from FPP for CMD_MC6_MULTICAST\n", rc); |
| } |
| } |
| return rc; |
| |
| keyword_error: |
| cmm_print(DEBUG_STDERR, "ERROR: Unknown keyword %s\n", keywords[cpt]); |
| |
| help: |
| cmmMc6SetPrintHelp(); |
| return -1; |
| } |
| |
| |
| /************************************************************ |
| * cmmMc6ProcessClientCmd |
| * This function do needed local process before sending |
| * the command to FPP |
| * |
| ************************************************************/ |
| |
| int cmmMc6ProcessClientCmd(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) |
| { |
| int ret = 0; |
| cmmd_mc6_entry_t * entry = (cmmd_mc6_entry_t *) cmd_buf; |
| cmmd_mc6_listener_t * listener; |
| |
| switch(function_code) |
| { |
| case CMMD_CMD_MC6_MULTICAST: |
| // We need to check if we don't have to do something with the interface names |
| |
| //Sanity checks |
| if (cmd_len < sizeof(cmmd_mc6_entry_t)) |
| { |
| res_buf[0] = CMMD_ERR_WRONG_COMMAND_SIZE; |
| break; |
| } |
| |
| if ((entry->action == CMMD_ACTION_QUERY) || |
| (entry->action == CMMD_ACTION_QUERY_CONT)) |
| goto FCI_CMD; |
| |
| if (entry->num_output > MC6_MAX_LISTENERS_IN_QUERY) |
| { |
| res_buf[0] = CMMD_ERR_WRONG_COMMAND_PARAM; |
| break; |
| } |
| |
| if (cmd_len < (sizeof(cmmd_mc6_entry_t) + (entry->num_output * sizeof(cmmd_mc6_listener_t)))) |
| { |
| res_buf[0] = CMMD_ERR_WRONG_COMMAND_SIZE; |
| break; |
| } |
| |
| |
| // Check if the listeners are on virtual interface |
| listener = (cmmd_mc6_listener_t *)(cmd_buf + sizeof(cmmd_mc6_entry_t) ); |
| switch( entry->action ) |
| { |
| case CMMD_MC_ACTION_ADD: |
| case CMMD_MC_ACTION_REMOVE: |
| case CMMD_MC_ACTION_UPDATE: |
| res_buf[0] = CMMD_ERR_OK; |
| ret = mc6_update_entry(entry, listener, entry->action ); |
| if( ret != CMMD_ERR_OK ) |
| { |
| res_buf[0] = ret; |
| goto out; |
| } |
| goto FCI_CMD; |
| break; |
| case CMMD_MC_ACTION_REMOVE_LOCAL: |
| mc_remove_group(entry,AF_INET6); |
| break; |
| |
| } |
| out: |
| |
| break; |
| |
| case CMMD_CMD_MC6_RESET: |
| __pthread_mutex_lock(&itf_table.lock); |
| __pthread_mutex_lock(&ctMutex); |
| __pthread_mutex_lock(&rtMutex); |
| __pthread_mutex_lock(&neighMutex); |
| __pthread_mutex_lock(&flowMutex); |
| __pthread_mutex_lock(&mc_lock); |
| |
| res_buf[0] = fci_write(fci_handle, CMMD_CMD_MC6_RESET, 0, NULL); |
| if ( ret == CMMD_ERR_OK ) |
| mc_reset(AF_INET); |
| |
| __pthread_mutex_unlock(&mc_lock); |
| __pthread_mutex_unlock(&flowMutex); |
| __pthread_mutex_unlock(&neighMutex); |
| __pthread_mutex_unlock(&rtMutex); |
| __pthread_mutex_unlock(&ctMutex); |
| __pthread_mutex_unlock(&itf_table.lock); |
| break; |
| |
| case CMMD_CMD_MC6_MODE: |
| goto FCI_CMD; |
| |
| default: |
| res_buf[0] = CMMD_ERR_UNKNOWN_COMMAND; |
| break; |
| } |
| |
| *res_len = 2; |
| return 0; |
| |
| FCI_CMD: |
| return fci_cmd(fci_handle, function_code, (u_int16_t*)cmd_buf, cmd_len, res_buf, res_len); |
| } |
| |