| /* |
| * |
| * 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 <linux/if_vlan.h> |
| #include <linux/sockios.h> |
| #include <string.h> |
| #include <sys/socket.h> |
| #include <sys/types.h> |
| #include <sys/ioctl.h> |
| #include <ctype.h> |
| |
| #include "libcmm.h" |
| #include "fpp.h" |
| #include "cmm.h" |
| #include "itf.h" |
| #include "module_icc.h" |
| |
| |
| static void print_error(u_int32_t rc) |
| { |
| switch (rc) |
| { |
| case FPP_ERR_ICC_TOO_MANY_ENTRIES: |
| cmm_print(DEBUG_ERROR,"Error: Too many entries\n"); |
| break; |
| case FPP_ERR_ICC_ENTRY_ALREADY_EXISTS: |
| cmm_print(DEBUG_ERROR,"Error: Entry already exists\n"); |
| break; |
| case FPP_ERR_ICC_ENTRY_NOT_FOUND: |
| cmm_print(DEBUG_ERROR,"Error: Entry not found\n"); |
| break; |
| case FPP_ERR_ICC_THRESHOLD_OUT_OF_RANGE: |
| cmm_print(DEBUG_ERROR,"Error: Threshold value out of range\n"); |
| break; |
| default: |
| cmm_print(DEBUG_ERROR,"Error from CMM, error = `%d'\n", rc); |
| break; |
| } |
| } |
| |
| int IccReset(daemon_handle_t daemon_handle, int argc, char *argv[]) |
| { |
| |
| cmm_command_t cmd; |
| cmm_response_t res; |
| fpp_icc_reset_cmd_t reset_cmd; |
| |
| if (argc != 0) |
| goto usage; |
| |
| memset(&cmd, 0, sizeof(cmd)); |
| memset(&res, 0, sizeof(res)); |
| memset(&reset_cmd, 0, sizeof(reset_cmd)); |
| |
| cmd.func = FPP_CMD_ICC_RESET; |
| cmd.length = sizeof(reset_cmd); |
| memcpy(&cmd.buf, &reset_cmd, sizeof(reset_cmd)); |
| if (cmm_send(daemon_handle, &cmd, 0) != 0) { |
| cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (cmm_recv(daemon_handle, &res, 0) < 0) { |
| cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (res.rc != FPP_ERR_OK) { |
| print_error(res.rc); |
| return -1; |
| } |
| |
| return CLI_OK; |
| usage: |
| cmm_print(DEBUG_ERROR, "Usage: icc reset\n"); |
| return -1; |
| } |
| |
| int IccThreshold(daemon_handle_t daemon_handle, int argc, char *argv[]) |
| { |
| cmm_command_t cmd; |
| cmm_response_t res; |
| fpp_icc_threshold_cmd_t thresh_cmd; |
| u_int32_t val1, val2; |
| |
| if (argc != 2) |
| goto usage; |
| |
| memset(&cmd, 0, sizeof(cmd)); |
| memset(&res, 0, sizeof(res)); |
| memset(&thresh_cmd, 0, sizeof(thresh_cmd)); |
| |
| if (parse_value(argv[0], &val1, 1024) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid bmu1 threshold: %s\n", argv[0]); |
| goto usage; |
| } |
| if (parse_value(argv[1], &val2, 1024) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid bmu2 threshold: %s\n", argv[1]); |
| goto usage; |
| } |
| |
| thresh_cmd.bmu1_threshold = val1; |
| thresh_cmd.bmu2_threshold = val2; |
| |
| cmd.func = FPP_CMD_ICC_THRESHOLD; |
| cmd.length = sizeof(fpp_icc_threshold_cmd_t); |
| memcpy(&cmd.buf, &thresh_cmd, sizeof(thresh_cmd)); |
| |
| if (cmm_send(daemon_handle, &cmd, 0) != 0) { |
| cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (cmm_recv(daemon_handle, &res, 0) < 0) { |
| cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (res.rc != FPP_ERR_OK) { |
| print_error(res.rc); |
| return -1; |
| } |
| |
| return CLI_OK; |
| usage: |
| cmm_print(DEBUG_ERROR, "Usage: icc threshold <bmu1-thresh> <bmu2-thresh>\n"); |
| return CLI_OK; |
| |
| } |
| |
| static int icc_add_delete(daemon_handle_t daemon_handle, int argc, char *argv[], u_int32_t action) |
| { |
| int i; |
| cmm_command_t cmd; |
| cmm_response_t res; |
| fpp_icc_add_delete_cmd_t ad_cmd; |
| unsigned short interface; |
| u_int32_t val1, val2; |
| int arg = 2; |
| |
| if (argc < 3) |
| goto usage; |
| |
| memset(&cmd, 0, sizeof(cmd)); |
| memset(&res, 0, sizeof(res)); |
| memset(&ad_cmd, 0, sizeof(ad_cmd)); |
| ad_cmd.action = action; |
| |
| if (parse_icc_interface(argv[0], &interface, ICC_NUM_INTERFACES) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid interface: %s\n", argv[0]); |
| goto usage; |
| } |
| ad_cmd.interface = interface; |
| |
| if (strcasecmp(argv[1], "ethertype") == 0) |
| { |
| if (argc != 3) |
| goto usage; |
| ad_cmd.table_type = ICC_TABLETYPE_ETHERTYPE; |
| if (parse_value(argv[2], &val1, 0xffff) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid ethertype: %s\n", argv[2]); |
| goto usage; |
| } |
| ad_cmd.ethertype.type = val1; |
| } |
| else if (strcasecmp(argv[1], "protocol") == 0) |
| { |
| ad_cmd.table_type = ICC_TABLETYPE_PROTOCOL; |
| while (argv[arg]) |
| { |
| if (parse_range(argv[arg], &val1, &val2, 255) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid protocol: %s\n", argv[arg]); |
| goto usage; |
| } |
| for (i = val1; i <= val2; i++) |
| setbit_in_array(ad_cmd.protocol.ipproto, i, 1); |
| arg++; |
| } |
| } |
| else if (strcasecmp(argv[1], "dscp") == 0) |
| { |
| ad_cmd.table_type = ICC_TABLETYPE_DSCP; |
| while (argv[arg]) |
| { |
| if (parse_range(argv[arg], &val1, &val2, 63) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid dscp value: %s\n", argv[arg]); |
| goto usage; |
| } |
| for (i = val1; i <= val2; i++) |
| setbit_in_array(ad_cmd.dscp.dscp_value, i, 1); |
| arg++; |
| } |
| } |
| else if (strcasecmp(argv[1], "saddr") == 0 || strcasecmp(argv[1], "daddr") == 0) |
| { |
| if (argc > 4) |
| goto usage; |
| ad_cmd.table_type = strcasecmp(argv[1], "saddr") == 0 ? ICC_TABLETYPE_SADDR : ICC_TABLETYPE_DADDR; |
| if (inet_pton(AF_INET, argv[2], &ad_cmd.ipaddr.v4_addr) != 1) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid IP address: %s\n", argv[2]); |
| goto usage; |
| } |
| if (argc == 4) |
| { |
| if (parse_value(argv[3], &val1, 32) < 0 || val1 == 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid mask length: %s\n", argv[3]); |
| goto usage; |
| } |
| ad_cmd.ipaddr.v4_masklen = val1; |
| } |
| else |
| { |
| ad_cmd.ipaddr.v4_masklen = 32; |
| } |
| } |
| else if (strcasecmp(argv[1], "saddr6") == 0 || strcasecmp(argv[1], "daddr6") == 0) |
| { |
| if (argc > 4) |
| goto usage; |
| ad_cmd.table_type = strcasecmp(argv[1], "saddr6") == 0 ? ICC_TABLETYPE_SADDR6 : ICC_TABLETYPE_DADDR6; |
| if (inet_pton(AF_INET6, argv[2], ad_cmd.ipv6addr.v6_addr) != 1) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid IPv6 address: %s\n", argv[2]); |
| goto usage; |
| } |
| if (argc == 4) |
| { |
| if (parse_value(argv[3], &val1, 128) < 0 || val1 == 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid mask length: %s\n", argv[3]); |
| goto usage; |
| } |
| ad_cmd.ipv6addr.v6_masklen = val1; |
| } |
| else |
| { |
| ad_cmd.ipv6addr.v6_masklen = 128; |
| } |
| } |
| else if (strcasecmp(argv[1], "port") == 0) |
| { |
| if (argc != 4) |
| goto usage; |
| ad_cmd.table_type = ICC_TABLETYPE_PORT; |
| if (parse_range(argv[2], &val1, &val2, 0xffff) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid source port: %s\n", argv[2]); |
| goto usage; |
| } |
| ad_cmd.port.sport_from = val1; |
| ad_cmd.port.sport_to = val2; |
| if (parse_range(argv[3], &val1, &val2, 0xffff) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid destination port: %s\n", argv[3]); |
| goto usage; |
| } |
| ad_cmd.port.dport_from = val1; |
| ad_cmd.port.dport_to = val2; |
| } |
| else if (strcasecmp(argv[1], "sport") == 0) |
| { |
| if (argc != 3) |
| goto usage; |
| ad_cmd.table_type = ICC_TABLETYPE_PORT; |
| if (parse_range(argv[2], &val1, &val2, 0xffff) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid source port: %s\n", argv[2]); |
| goto usage; |
| } |
| ad_cmd.port.sport_from = val1; |
| ad_cmd.port.sport_to = val2; |
| ad_cmd.port.dport_from = 0; |
| ad_cmd.port.dport_to = 65535; |
| } |
| else if (strcasecmp(argv[1], "dport") == 0) |
| { |
| if (argc != 3) |
| goto usage; |
| ad_cmd.table_type = ICC_TABLETYPE_PORT; |
| if (parse_range(argv[2], &val1, &val2, 0xffff) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid destination port: %s\n", argv[2]); |
| goto usage; |
| } |
| ad_cmd.port.dport_from = val1; |
| ad_cmd.port.dport_to = val2; |
| ad_cmd.port.sport_from = 0; |
| ad_cmd.port.sport_to = 65535; |
| } |
| else if (strcasecmp(argv[1], "vlan") == 0) |
| { |
| ad_cmd.table_type = ICC_TABLETYPE_VLAN; |
| if (argc > 4) |
| goto usage; |
| if (parse_range(argv[2], &val1, &val2, 8191) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid vlan ID: %s\n", argv[2]); |
| goto usage; |
| } |
| ad_cmd.vlan.vlan_from = val1; |
| ad_cmd.vlan.vlan_to = val2; |
| if (argc == 4) |
| { |
| if (parse_range(argv[3], &val1, &val2, 7) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid vlan priority: %s\n", argv[3]); |
| goto usage; |
| } |
| } |
| else |
| { |
| val1 = 0; |
| val2 = 7; |
| } |
| ad_cmd.vlan.prio_from = val1; |
| ad_cmd.vlan.prio_to = val2; |
| } |
| else |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Unknown keyword %s\n", argv[1]); |
| goto usage; |
| } |
| |
| cmd.func = FPP_CMD_ICC_ADD_DELETE; |
| cmd.length = sizeof(fpp_icc_add_delete_cmd_t); |
| memcpy(&cmd.buf, &ad_cmd, sizeof(ad_cmd)); |
| |
| if (cmm_send(daemon_handle, &cmd, 0) != 0) { |
| cmm_print(DEBUG_ERROR,"Error sending message to CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (cmm_recv(daemon_handle, &res, 0) < 0) { |
| cmm_print(DEBUG_ERROR,"Error receiving message from CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| |
| if (res.rc != FPP_ERR_OK) { |
| print_error(res.rc); |
| return -1; |
| } |
| |
| return CLI_OK; |
| |
| usage: |
| cmm_print(DEBUG_ERROR, "Usage: icc [add | delete] <interface>\n" |
| "\t[\n" |
| "\t\t[ethertype <type>] |\n" |
| "\t\t[protocol <proto-1> <proto-2> ...] |\n" |
| "\t\t[dscp <value-1> <value-2> ...] |\n" |
| "\t\t[saddr <addr> [<masklen>]] |\n" |
| "\t\t[daddr <addr> [<masklen>]] |\n" |
| "\t\t[saddr6 <addr> [<masklen>]] |\n" |
| "\t\t[daddr6 <addr> [<masklen>]] |\n" |
| "\t\t[port <srcport> <dstport>] |\n" |
| "\t\t[sport <srcport>] |\n" |
| "\t\t[dport <dstport>] |\n" |
| "\t\t[vlan <id> [<priority>]] |\n" |
| "\t]\n"); |
| return CLI_OK; |
| } |
| |
| int IccAdd(daemon_handle_t daemon_handle, int argc, char *argv[]) |
| { |
| return icc_add_delete(daemon_handle, argc, argv, ICC_ACTION_ADD); |
| } |
| |
| int IccDelete(daemon_handle_t daemon_handle, int argc, char *argv[]) |
| { |
| return icc_add_delete(daemon_handle, argc, argv, ICC_ACTION_DELETE); |
| } |
| |
| int IccQuery(daemon_handle_t daemon_handle, int argc, char *argv[]) |
| { |
| int i, j; |
| cmm_command_t cmd; |
| cmm_response_t res; |
| fpp_icc_query_cmd_t query_cmd; |
| fpp_icc_query_reply_t *prsp = (fpp_icc_query_reply_t *)&res.buf[0]; |
| u_int16_t interface; |
| u_int16_t interface_from, interface_to; |
| u_int16_t action; |
| char buf[1024]; |
| |
| if (argc > 1) |
| goto usage; |
| |
| memset(&cmd, 0, sizeof(cmd)); |
| memset(&res, 0, sizeof(res)); |
| memset(&query_cmd, 0, sizeof(query_cmd)); |
| |
| if (argc == 1) |
| { |
| if (parse_icc_interface(argv[0], &interface_from, ICC_NUM_INTERFACES) < 0) |
| { |
| cmm_print(DEBUG_ERROR, "ERROR: Invalid interface: %s\n", argv[0]); |
| goto usage; |
| } |
| interface_to = interface_from; |
| } |
| else |
| { |
| interface_from = 0; |
| interface_to = ICC_NUM_INTERFACES - 1; |
| } |
| |
| for (interface = interface_from; interface <= interface_to; interface++) |
| { |
| cmm_print(DEBUG_STDOUT, "ICC interface %d --\n", interface); |
| cmd.func = FPP_CMD_ICC_QUERY; |
| cmd.length = sizeof(fpp_icc_query_cmd_t); |
| action = ICC_ACTION_QUERY; |
| while (1) |
| { |
| query_cmd.action = action; |
| query_cmd.interface = interface; |
| memcpy(&cmd.buf, &query_cmd, sizeof(query_cmd)); |
| if (cmm_send(daemon_handle, &cmd, 0) != 0) { |
| cmm_print(DEBUG_ERROR, "Error sending message to CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| if (cmm_recv(daemon_handle, &res, 0) < 0) { |
| cmm_print(DEBUG_ERROR, "Error receiving message from CMM, error = `%s'\n", strerror(errno)); |
| return -1; |
| } |
| if (prsp->query_result != 0 || prsp->interface != interface) |
| break; |
| switch (prsp->table_type) |
| { |
| case ICC_TABLETYPE_ETHERTYPE: |
| { |
| cmm_print(DEBUG_STDOUT, "Ethertype: 0x%04x\n", prsp->ethertype.type); |
| break; |
| } |
| case ICC_TABLETYPE_PROTOCOL: |
| { |
| buf[0] = '\0'; |
| for (i = 0; i < 256; i++) |
| { |
| if (!testbit_in_array(prsp->protocol.ipproto, i)) |
| continue; |
| j = i + 1; |
| if (j == 256 || !testbit_in_array(prsp->protocol.ipproto, j)) |
| { |
| sprintf(buf + strlen(buf), "%d ", i); |
| } |
| else |
| { |
| while (j < 255 && testbit_in_array(prsp->protocol.ipproto, j + 1)) |
| j++; |
| sprintf(buf + strlen(buf), "%d-%d ", i, j); |
| } |
| i = j; |
| } |
| cmm_print(DEBUG_STDOUT, "Protocols: %s\n", buf); |
| break; |
| } |
| case ICC_TABLETYPE_DSCP: |
| { |
| buf[0] = '\0'; |
| for (i = 0; i < 64; i++) |
| { |
| if (!testbit_in_array(prsp->dscp.dscp_value, i)) |
| continue; |
| j = i + 1; |
| if (j == 64 || !testbit_in_array(prsp->dscp.dscp_value, j)) |
| { |
| sprintf(buf + strlen(buf), "%d ", i); |
| } |
| else |
| { |
| while (j < 63 && testbit_in_array(prsp->dscp.dscp_value, j + 1)) |
| j++; |
| sprintf(buf + strlen(buf), "%d-%d ", i, j); |
| } |
| i = j; |
| } |
| cmm_print(DEBUG_STDOUT, "DSCP values: %s\n", buf); |
| break; |
| } |
| case ICC_TABLETYPE_SADDR: |
| { |
| cmm_print(DEBUG_STDOUT, "IPv4 Source Address: %s/%d\n", |
| inet_ntop(AF_INET, &prsp->ipaddr.v4_addr, buf, sizeof(buf)), |
| prsp->ipaddr.v4_masklen); |
| break; |
| } |
| case ICC_TABLETYPE_DADDR: |
| { |
| cmm_print(DEBUG_STDOUT, "IPv4 Destination Address: %s/%d\n", |
| inet_ntop(AF_INET, &prsp->ipaddr.v4_addr, buf, sizeof(buf)), |
| prsp->ipaddr.v4_masklen); |
| break; |
| } |
| case ICC_TABLETYPE_SADDR6: |
| { |
| cmm_print(DEBUG_STDOUT, "IPv6 Source Address: %s/%d\n", |
| inet_ntop(AF_INET6, prsp->ipv6addr.v6_addr, buf, sizeof(buf)), |
| prsp->ipv6addr.v6_masklen); |
| break; |
| } |
| case ICC_TABLETYPE_DADDR6: |
| { |
| cmm_print(DEBUG_STDOUT, "IPv6 Destination Address: %s/%d\n", |
| inet_ntop(AF_INET6, prsp->ipv6addr.v6_addr, buf, sizeof(buf)), |
| prsp->ipv6addr.v6_masklen); |
| break; |
| } |
| case ICC_TABLETYPE_PORT: |
| { |
| cmm_print(DEBUG_STDOUT, "Ports: Source %d-%d / Destination %d-%d\n", |
| prsp->port.sport_from, prsp->port.sport_to, |
| prsp->port.dport_from, prsp->port.dport_to); |
| break; |
| } |
| case ICC_TABLETYPE_VLAN: |
| { |
| cmm_print(DEBUG_STDOUT, "VLAN: ID %d-%d / Priority %d-%d\n", |
| prsp->vlan.vlan_from, prsp->vlan.vlan_to, |
| prsp->vlan.prio_from, prsp->vlan.prio_to); |
| break; |
| } |
| } |
| action = ICC_ACTION_QUERY_CONT; |
| } |
| cmm_print(DEBUG_STDOUT, "-------------\n\n"); |
| } |
| |
| return CLI_OK; |
| |
| usage: |
| cmm_print(DEBUG_ERROR, "Usage: icc query [<interface>]\n"); |
| return CLI_OK; |
| } |