/*------------------------------------------------------------------------------------------*\ * Copyright (C) 2006,2007,...,2012 AVM GmbH * * * * All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * * * * Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * * * * Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in * * the documentation and/or other materials provided with the distribution. * * * * * Neither the name of AVM nor the names of its contributors may be used * * to endorse or promote products derived from this software without * * specific prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include /*--- #include ---*/ #include "linux_avm_cpmac.h" char *usage[] = { "Usage: ", /*--- " cpmacconfig info", ---*/ " cpmacconfig mode [optional VIDs]", " modes: normal, ata, split, splitata, allports", " cpmacconfig mode special (,[,...] [optional VIDs]", " ports start at 0", " cpmacconfig addporttowan []", " cpmacconfig power <5 * (on|off|save)>", " cpmacconfig setreg ", " cpmacconfig getreg ", " cpmacconfig setphy ", " cpmacconfig getphy ", " cpmacconfig regdump", " cpmacconfig set_igmp_fwd ", " cpmacconfig support", " cpmacconfig test ", " cpmacconfig peek [length [size]]", " cpmacconfig poke [size]", " cpmacconfig mirror ", " enable_* should be 0 or 1", 0 }; char *modes[] = { "illegal", "normal", "ata", "split", "split_ata", "all_ports", "special" }; const unsigned char max_mode = 7; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void show_usage() { unsigned int i = 0; printf("\ncpmacconfig built on %s at %s\n\n", __DATE__, __TIME__); while(usage[i] != 0) { puts(usage[i++]); } printf("SIOCDEVPRIVATE (0x89F0) = %#x, AVM_CPMAC_IOCTL_GENERIC (SIOCDEVPRIVATE + 15) = %#x\n", SIOCDEVPRIVATE, AVM_CPMAC_IOCTL_GENERIC); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int main(int argc, char** argv) { unsigned int i, value; int fd = 0; struct avm_cpmac_ioctl_struct config; struct ifreq ifr; char *cmd = NULL; if(argc < 3) { show_usage(); exit(1); } if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr,"cpmac_ioctl: socket(2) failed\n"); return -1; } memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name) - 1); ifr.ifr_data = (void *) &config; cmd = argv[2]; if(strcasecmp(cmd, "info") == 0) { printf("Information about cpmac: \n"); /*--- config.type = AVM_CPMAC_IOCTL_CONFIG_GET_INFO; ---*/ /*--- if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) ---*/ /*--- goto ioctl_failed; ---*/ /*--- printf(" Ports: %u internal, %u external\n", config.u.info.internal_ports, ---*/ /*--- config.u.info.external_ports); ---*/ config.type = AVM_CPMAC_IOCTL_CONFIG_GET_PHY_POWER; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; printf(" PHY power: %u0ms on, %u0ms off, status = %s %s %s %s %s\n", config.u.phy_power_setup.time_on, config.u.phy_power_setup.time_off, (config.u.phy_power_setup.mode[0] == ADM_PHY_POWER_ON) ? "on" : ((config.u.phy_power_setup.mode[0] == ADM_PHY_POWER_OFF) ? "off" : "save"), (config.u.phy_power_setup.mode[1] == ADM_PHY_POWER_ON) ? "on" : ((config.u.phy_power_setup.mode[1] == ADM_PHY_POWER_OFF) ? "off" : "save"), (config.u.phy_power_setup.mode[2] == ADM_PHY_POWER_ON) ? "on" : ((config.u.phy_power_setup.mode[2] == ADM_PHY_POWER_OFF) ? "off" : "save"), (config.u.phy_power_setup.mode[3] == ADM_PHY_POWER_ON) ? "on" : ((config.u.phy_power_setup.mode[3] == ADM_PHY_POWER_OFF) ? "off" : "save"), (config.u.phy_power_setup.mode[4] == ADM_PHY_POWER_ON) ? "on" : ((config.u.phy_power_setup.mode[4] == ADM_PHY_POWER_OFF) ? "off" : "save")); config.type = AVM_CPMAC_IOCTL_CONFIG_GET_SWITCH_MODE; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; if(max_mode <= config.u.switch_mode.cpmac_mode) { printf(" Switch mode: unknown (%u)", config.u.switch_mode.cpmac_mode); } else { printf(" Switch mode: %s (%u) ", modes[config.u.switch_mode.cpmac_mode], config.u.switch_mode.cpmac_mode); } if(config.u.switch_mode.wan_vlan_number > 0) { printf("with VLANs "); for(i = 0; i < config.u.switch_mode.wan_vlan_number; i++) { printf("%u ", config.u.switch_mode.wan_vlan_id[i]); } } printf("\n"); config.type = AVM_CPMAC_IOCTL_CONFIG_GET_SWITCH_MODE_CURRENT; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; if(config.u.switch_config.wanport != 0xff) { printf(" WAN port %u\n", config.u.switch_config.wanport); } for(i = 0; i < config.u.switch_config.number_of_devices; i++) { printf(" \"%s\": %#2x\n", config.u.switch_config.device[i].name, config.u.switch_config.device[i].target_mask); } } else if(strcasecmp(cmd, "mode") == 0) { char *mode = argv[3]; /* Configure switch mode settings */ printf("Configure cpmac mode %s\n", mode); /* FIXME */ if((argc < 4) || (argc > 12)) goto usage_error; if(strcmp(mode, "normal") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_NORMAL; } else if (strcmp(mode, "ata") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_ATA; } else if (strcmp(mode, "split") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_SPLIT; } else if (strcmp(mode, "splitata") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_SPLIT_ATA; } else if (strcmp(mode, "allports") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_ALL_PORTS; } else if (strcmp(mode, "special") == 0) { config.u.switch_mode.cpmac_mode = CPMAC_MODE_SPECIAL; } if(config.u.switch_mode.cpmac_mode == CPMAC_MODE_SPECIAL) { char *ptr = NULL; config.type = AVM_CPMAC_IOCTL_CONFIG_SET_SWITCH_MODE_SPECIAL; config.u.switch_config.number_of_devices = 0; config.u.switch_config.wanport = 0xff; for(i = 4; (i < (unsigned int) argc) && (config.u.switch_config.number_of_devices < AVM_CPMAC_MAX_DEVS); i++) { unsigned char device = config.u.switch_config.number_of_devices; ptr = strchr(argv[i], ','); if(ptr == NULL) break; strncpy(config.u.switch_config.device[device].name, argv[i], AVM_CPMAC_MAX_DEVICE_NAME_LENGTH - 1); config.u.switch_config.device[device].target_mask = 0; while(*(++ptr) != 0) { char port = atoi(ptr); if((port < 0) || (port >= AVM_CPMAC_MAX_PORTS)) { printf("Illegal port (%i) given\n", port); goto usage_error; } config.u.switch_config.device[device].target_mask |= 1 << port; ptr = strchr(ptr, ','); if(ptr == NULL) break; } config.u.switch_config.number_of_devices++; } if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; config.u.switch_mode.cpmac_mode = CPMAC_MODE_SPECIAL; } else { i = 4; } config.u.switch_mode.wan_vlan_number = 0; for( /* keep i */ ; (i < (unsigned int) argc) && (config.u.switch_mode.wan_vlan_number < 4); i++) { if(!isdigit(*argv[i])) { fprintf(stderr, "\"%s\" is no number", argv[i]); goto usage_error; } config.u.switch_mode.wan_vlan_id[config.u.switch_mode.wan_vlan_number++] = (unsigned short) atoi(argv[i]); } config.type = AVM_CPMAC_IOCTL_CONFIG_SET_SWITCH_MODE; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "addporttowan") == 0) { /* Add port to WAN */ if((argc < 4) || (argc > 5)) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_ADD_PORT_TO_WAN; config.u.config_port_vlan.vid = 0; /* Default */ sscanf(argv[3], "%x", &value); config.u.config_port_vlan.port = (unsigned char) value; if(argc > 4) { sscanf(argv[4], "%x", &value); config.u.config_port_vlan.vid = (unsigned short) value; } if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "power") == 0) { /* Configure power settings */ if(argc != 9) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_SET_PHY_POWER; for(i = 3; i <= 4; i++) { if(!isdigit(*argv[i])) { fprintf(stderr, "\"%s\" is no number", argv[i]); goto usage_error; } } config.u.phy_power_setup.time_on = atoi(argv[3]) / 10; config.u.phy_power_setup.time_off = atoi(argv[4]) / 10; for(i = 0; i < 5; i++) { if(strcasecmp(argv[i + 5], "on") == 0) { config.u.phy_power_setup.mode[i] = ADM_PHY_POWER_ON; } else if(strcasecmp(argv[i + 5], "off") == 0) { config.u.phy_power_setup.mode[i] = ADM_PHY_POWER_OFF; } else if(strcasecmp(argv[i + 5], "save") == 0) { config.u.phy_power_setup.mode[i] = ADM_PHY_POWER_SAVE; } else { goto usage_error; } } if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "setreg") == 0) { /* Set the given switch register */ if(argc != 5) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_SET_SWITCH_REGISTER; sscanf(argv[3], "%x", &config.u.switch_register.reg); sscanf(argv[4], "%x", &config.u.switch_register.value); printf("Setting register %#x to %#x\n", config.u.switch_register.reg, config.u.switch_register.value); if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "getreg") == 0) { /* Get the contents of the given switch register */ if(argc != 4) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_GET_SWITCH_REGISTER; sscanf(argv[3], "%x", &config.u.switch_register.reg); if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; printf("Register %#x = %#x\n", config.u.switch_register.reg, config.u.switch_register.value); } else if(strcasecmp(cmd, "setphy") == 0) { /* Set the given PHY register */ if(argc != 6) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_SET_PHY_REGISTER; sscanf(argv[3], "%x", &value); config.u.phy_register.phy = (unsigned char) value; sscanf(argv[4], "%x", &value); config.u.phy_register.reg = (unsigned short) value; sscanf(argv[5], "%x", &value); config.u.phy_register.value = (unsigned short) value; printf("Setting phy %#x register %#x to %#x\n", config.u.phy_register.phy, config.u.phy_register.reg, config.u.phy_register.value); if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "getphy") == 0) { /* Get the contents of the given PHY register */ if(argc != 5) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_GET_PHY_REGISTER; sscanf(argv[3], "%x", &value); config.u.phy_register.phy = (unsigned short) value; sscanf(argv[4], "%x", &value); config.u.phy_register.reg = (unsigned short) value; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; printf("PHY %#x register %#x = %#x\n", config.u.phy_register.phy, config.u.phy_register.reg, config.u.phy_register.value); } else if(strcasecmp(cmd, "regdump") == 0) { /* Initiate complete switch register dump */ if(argc != 3) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_GET_SWITCH_REGISTER_DUMP; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "set_igmp_fwd") == 0) { /* Execute set_igmp_fwd function in driver */ if(argc != 4) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_SET_IGMP_FWD; sscanf(argv[3], "%x", &config.u.igmp_fwd_portmap); if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "support") == 0) { /* Print support data of the driver */ if(argc != 3) goto usage_error; config.type = AVM_CPMAC_IOCTL_SUPPORT_DATA; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "test") == 0) { /* Execute test function in driver */ if(argc != 4) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_TESTCMD; sscanf(argv[3], "%x", &config.u.value); if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "peek") == 0) { /* Print memory location(s) */ if((argc < 4) || (argc > 6)) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_PEEK; sscanf(argv[3], "%x", &value); config.u.peek.ptr = (void *) value; config.u.peek.size = 4; config.u.peek.value = 1; if(argc > 4) { sscanf(argv[4], "%x", &config.u.peek.value); if(argc > 5) { sscanf(argv[5], "%x", &config.u.peek.size); } } if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "poke") == 0) { /* Poke memory location */ if((argc < 5) || (argc > 6)) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_POKE; sscanf(argv[3], "%x", &value); config.u.peek.ptr = (void *) value; sscanf(argv[4], "%x", &config.u.peek.value); config.u.peek.size = 4; if(argc > 5) { sscanf(argv[5], "%x", &config.u.peek.size); } if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else if(strcasecmp(cmd, "mirror") == 0) { /* Configure port mirror */ if(argc != 7) goto usage_error; config.type = AVM_CPMAC_IOCTL_CONFIG_MIRROR_PORT; sscanf(argv[3], "%x", &value); config.u.mirror_port.mirror_from_port = (unsigned char) value; sscanf(argv[4], "%x", &value); config.u.mirror_port.mirror_to_port = (unsigned char) value; sscanf(argv[5], "%x", &value); config.u.mirror_port.enable_ingress = (unsigned char) value; sscanf(argv[6], "%x", &value); config.u.mirror_port.enable_egress = (unsigned char) value; if(ioctl(fd, AVM_CPMAC_IOCTL_GENERIC, (caddr_t) &ifr) < 0) goto ioctl_failed; } else { goto usage_error; } close(fd); return 0; ioctl_failed: fprintf(stderr, "cpmac_ioctl failed\n"); goto error_exit; usage_error: printf("argc = %u\n", argc); show_usage(); error_exit: if(fd >= 0) close(fd); return -1; } /* main */