int dump_interface(const char *name) { unsigned addr, flags; unsigned char hwbuf[ETH_ALEN]; int prefixLength; if(ifc_get_info(name, &addr, &prefixLength, &flags)) { return 0; } printf("%-8s %s ", name, flags & 1 ? "UP " : "DOWN"); printf("%40s", ipaddr(addr)); printf("/%-4d", prefixLength); printf("0x%08x ", flags); if (!ifc_get_hwaddr(name, hwbuf)) { int i; for(i=0; i < (ETH_ALEN-1); i++) printf("%02x:", hwbuf[i]); printf("%02x\n", hwbuf[i]); } else { printf("\n"); } return 0; }
int CommandListener::InterfaceCmd::runCommand(SocketClient *cli, int argc, char **argv) { if (argc < 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } if (!strcmp(argv[1], "list")) { DIR *d; struct dirent *de; if (!(d = opendir("/sys/class/net"))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true); return 0; } while((de = readdir(d))) { if (de->d_name[0] == '.') continue; cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false); } closedir(d); cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false); return 0; } else if (!strcmp(argv[1], "readrxcounter")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface readrxcounter <interface>", false); return 0; } unsigned long rx = 0, tx = 0; if (readInterfaceCounters(argv[2], &rx, &tx)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); return 0; } char *msg; asprintf(&msg, "%lu", rx); cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false); free(msg); return 0; } else if (!strcmp(argv[1], "readtxcounter")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface readtxcounter <interface>", false); return 0; } unsigned long rx = 0, tx = 0; if (readInterfaceCounters(argv[2], &rx, &tx)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); return 0; } char *msg = NULL; asprintf(&msg, "%lu", tx); cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false); free(msg); return 0; } else if (!strcmp(argv[1], "getthrottle")) { if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface getthrottle <interface> <rx|tx>", false); return 0; } int val = 0; int rc = 0; int voldRc = ResponseCode::InterfaceRxThrottleResult; if (!strcmp(argv[3], "rx")) { rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val); } else { rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val); voldRc = ResponseCode::InterfaceTxThrottleResult; } if (rc) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true); } else { char *msg = NULL; asprintf(&msg, "%u", val); cli->sendMsg(voldRc, msg, false); free(msg); return 0; } return 0; } else if (!strcmp(argv[1], "setthrottle")) { if (argc != 5) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false); return 0; } if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true); } else { cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false); } return 0; } else { /* * These commands take a minimum of 3 arguments */ if (argc < 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } if (!strcmp(argv[1], "getcfg")) { struct in_addr addr, mask; unsigned char hwaddr[6]; unsigned flags = 0; ifc_init(); memset(hwaddr, 0, sizeof(hwaddr)); if (ifc_get_info(argv[2], &addr.s_addr, &mask.s_addr, &flags)) { cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); return 0; } if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) { LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno)); } char *addr_s = strdup(inet_ntoa(addr)); char *mask_s = strdup(inet_ntoa(mask)); const char *updown, *brdcst, *loopbk, *ppp, *running, *multi; updown = (flags & IFF_UP) ? "up" : "down"; brdcst = (flags & IFF_BROADCAST) ? " broadcast" : ""; loopbk = (flags & IFF_LOOPBACK) ? " loopback" : ""; ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : ""; running = (flags & IFF_RUNNING) ? " running" : ""; multi = (flags & IFF_MULTICAST) ? " multicast" : ""; char *flag_s; asprintf(&flag_s, "[%s%s%s%s%s%s]", updown, brdcst, loopbk, ppp, running, multi); char *msg = NULL; asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s %s", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], addr_s, mask_s, flag_s); cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false); free(addr_s); free(mask_s); free(flag_s); free(msg); return 0; } else if (!strcmp(argv[1], "setcfg")) { // arglist: iface addr mask [flags] if (argc < 5) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } LOGD("Setting iface cfg"); struct in_addr addr, mask; unsigned flags = 0; if (!inet_aton(argv[3], &addr)) { cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false); return 0; } if (!inet_aton(argv[4], &mask)) { cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false); return 0; } ifc_init(); if (ifc_set_addr(argv[2], addr.s_addr)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true); return 0; } if (ifc_set_mask(argv[2], mask.s_addr)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true); return 0; } /* Process flags */ /* read from "[XX" arg to "YY]" arg */ bool bStarted = false; for (int i = 5; i < argc; i++) { char *flag = argv[i]; if (!bStarted) { if (*flag == '[') { flag++; bStarted = true; } else { continue; } } int len = strlen(flag); if (flag[len-1] == ']') { i = argc; // stop after this loop flag[len-1] = 0; } if (!strcmp(flag, "up")) { LOGD("Trying to bring up %s", argv[2]); if (ifc_up(argv[2])) { LOGE("Error upping interface"); cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true); return 0; } } else if (!strcmp(flag, "down")) { LOGD("Trying to bring down %s", argv[2]); if (ifc_down(argv[2])) { LOGE("Error downing interface"); cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true); return 0; } } else if (!strcmp(flag, "broadcast")) { LOGD("broadcast flag ignored"); } else if (!strcmp(flag, "multicast")) { LOGD("multicast flag ignored"); } else { cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false); return 0; } } cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false); return 0; } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); return 0; } } return 0; }
int CommandListener::InterfaceCmd::runCommand(SocketClient *cli, int argc, char **argv) { if (argc < 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } if (!strcmp(argv[1], "list")) { DIR *d; struct dirent *de; if (!(d = opendir("/sys/class/net"))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true); return 0; } while((de = readdir(d))) { if (de->d_name[0] == '.') continue; cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false); } closedir(d); cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false); return 0; } else if (!strcmp(argv[1], "readrxcounter")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface readrxcounter <interface>", false); return 0; } unsigned long rx = 0, tx = 0; if (readInterfaceCounters(argv[2], &rx, &tx)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); return 0; } char *msg; asprintf(&msg, "%lu", rx); cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false); free(msg); return 0; } else if (!strcmp(argv[1], "readtxcounter")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface readtxcounter <interface>", false); return 0; } unsigned long rx = 0, tx = 0; if (readInterfaceCounters(argv[2], &rx, &tx)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); return 0; } char *msg = NULL; asprintf(&msg, "%lu", tx); cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false); free(msg); return 0; } else if (!strcmp(argv[1], "getthrottle")) { if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface getthrottle <interface> <rx|tx>", false); return 0; } int val = 0; int rc = 0; int voldRc = ResponseCode::InterfaceRxThrottleResult; if (!strcmp(argv[3], "rx")) { rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val); } else { rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val); voldRc = ResponseCode::InterfaceTxThrottleResult; } if (rc) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true); } else { char *msg = NULL; asprintf(&msg, "%u", val); cli->sendMsg(voldRc, msg, false); free(msg); return 0; } return 0; } else if (!strcmp(argv[1], "setthrottle")) { if (argc != 5) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false); return 0; } if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true); } else { cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false); } return 0; } else if (!strcmp(argv[1], "driver")) { int rc; char *rbuf; if (argc < 4) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface driver <interface> <cmd> <args>", false); return 0; } rc = sInterfaceCtrl->interfaceCommand(argc, argv, &rbuf); if (rc) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to execute command", true); } else { cli->sendMsg(ResponseCode::CommandOkay, rbuf, false); } return 0; } else { /* * These commands take a minimum of 3 arguments */ if (argc < 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } // 0 1 2 3 4 5 6 7 // interface route add/remove iface default/secondary dest prefix gateway if (!strcmp(argv[1], "route")) { int prefix_length = 0; if (argc < 8) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } if (sscanf(argv[6], "%d", &prefix_length) != 1) { cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route prefix", false); return 0; } if (!strcmp(argv[2], "add")) { if (!strcmp(argv[4], "default")) { if (ifc_add_route(argv[3], argv[5], prefix_length, argv[7])) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to add route to default table", true); } else { cli->sendMsg(ResponseCode::CommandOkay, "Route added to default table", false); } } else if (!strcmp(argv[4], "secondary")) { return sSecondaryTableCtrl->addRoute(cli, argv[3], argv[5], prefix_length, argv[7]); } else { cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route type, expecting 'default' or 'secondary'", false); return 0; } } else if (!strcmp(argv[2], "remove")) { if (!strcmp(argv[4], "default")) { if (ifc_remove_route(argv[3], argv[5], prefix_length, argv[7])) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove route from default table", true); } else { cli->sendMsg(ResponseCode::CommandOkay, "Route removed from default table", false); } } else if (!strcmp(argv[4], "secondary")) { return sSecondaryTableCtrl->removeRoute(cli, argv[3], argv[5], prefix_length, argv[7]); } else { cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route type, expecting 'default' or 'secondary'", false); return 0; } } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); } return 0; } if (!strcmp(argv[1], "getcfg")) { struct in_addr addr; int prefixLength; unsigned char hwaddr[6]; unsigned flags = 0; ifc_init(); memset(hwaddr, 0, sizeof(hwaddr)); if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) { cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); ifc_close(); return 0; } if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) { ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno)); } char *addr_s = strdup(inet_ntoa(addr)); const char *updown, *brdcst, *loopbk, *ppp, *running, *multi; updown = (flags & IFF_UP) ? "up" : "down"; brdcst = (flags & IFF_BROADCAST) ? " broadcast" : ""; loopbk = (flags & IFF_LOOPBACK) ? " loopback" : ""; ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : ""; running = (flags & IFF_RUNNING) ? " running" : ""; multi = (flags & IFF_MULTICAST) ? " multicast" : ""; char *flag_s; asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi); char *msg = NULL; asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], addr_s, prefixLength, flag_s); cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false); free(addr_s); free(flag_s); free(msg); ifc_close(); return 0; } else if (!strcmp(argv[1], "setcfg")) { // arglist: iface [addr prefixLength] flags if (argc < 4) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); return 0; } ALOGD("Setting iface cfg"); struct in_addr addr; unsigned flags = 0; int index = 5; ifc_init(); if (!inet_aton(argv[3], &addr)) { // Handle flags only case index = 3; } else { if (ifc_set_addr(argv[2], addr.s_addr)) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true); ifc_close(); return 0; } // Set prefix length on a non zero address if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) { cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true); ifc_close(); return 0; } } /* Process flags */ for (int i = index; i < argc; i++) { char *flag = argv[i]; if (!strcmp(flag, "up")) { ALOGD("Trying to bring up %s", argv[2]); if (ifc_up(argv[2])) { ALOGE("Error upping interface"); cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true); ifc_close(); return 0; } } else if (!strcmp(flag, "down")) { ALOGD("Trying to bring down %s", argv[2]); if (ifc_down(argv[2])) { ALOGE("Error downing interface"); cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true); ifc_close(); return 0; } } else if (!strcmp(flag, "broadcast")) { // currently ignored } else if (!strcmp(flag, "multicast")) { // currently ignored } else if (!strcmp(flag, "running")) { // currently ignored } else if (!strcmp(flag, "loopback")) { // currently ignored } else if (!strcmp(flag, "point-to-point")) { // currently ignored } else { cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false); ifc_close(); return 0; } } cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false); ifc_close(); return 0; } else if (!strcmp(argv[1], "clearaddrs")) { // arglist: iface ALOGD("Clearing all IP addresses on %s", argv[2]); ifc_clear_addresses(argv[2]); cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false); return 0; } else if (!strcmp(argv[1], "ipv6privacyextensions")) { if (argc != 4) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface ipv6privacyextensions <interface> <enable|disable>", false); return 0; } char *tmp; asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/use_tempaddr", argv[2]); if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "2" : "0", 1) < 0) { free(tmp); cli->sendMsg(ResponseCode::OperationFailed, "Failed to set ipv6 privacy extensions", true); return 0; } free(tmp); cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false); return 0; } else if (!strcmp(argv[1], "ipv6")) { if (argc != 4) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: interface ipv6 <interface> <enable|disable>", false); return 0; } char *tmp; asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", argv[2]); if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "0" : "1", 1) < 0) { free(tmp); cli->sendMsg(ResponseCode::OperationFailed, "Failed to change IPv6 state", true); return 0; } free(tmp); cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false); return 0; } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); return 0; } } return 0; }
int dhcp_init_ifc(const char *ifname) { dhcp_msg discover_msg; dhcp_msg request_msg; dhcp_msg reply; dhcp_msg *msg; dhcp_info info; int s, r, size; int valid_reply; uint32_t xid; unsigned char hwaddr[6]; struct pollfd pfd; unsigned int state; unsigned int timeout; int if_index; xid = (uint32_t) get_msecs(); if (ifc_get_hwaddr(ifname, hwaddr)) { return fatal("cannot obtain interface address"); } if (ifc_get_ifindex(ifname, &if_index)) { return fatal("cannot obtain interface index"); } s = open_raw_socket(ifname, hwaddr, if_index); timeout = TIMEOUT_INITIAL; state = STATE_SELECTING; info.type = 0; goto transmit; for (;;) { pfd.fd = s; pfd.events = POLLIN; pfd.revents = 0; r = poll(&pfd, 1, timeout); if (r == 0) { #if VERBOSE printerr("TIMEOUT\n"); #endif if (timeout >= TIMEOUT_MAX) { printerr("timed out\n"); if ( info.type == DHCPOFFER ) { printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname); return dhcp_configure(ifname, &info); } errno = ETIME; close(s); return -1; } timeout = timeout * 2; transmit: size = 0; msg = NULL; switch(state) { case STATE_SELECTING: msg = &discover_msg; size = init_dhcp_discover_msg(msg, hwaddr, xid); break; case STATE_REQUESTING: msg = &request_msg; size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr); break; default: r = 0; } if (size != 0) { r = send_message(s, if_index, msg, size); if (r < 0) { printerr("error sending dhcp msg: %s\n", strerror(errno)); } } continue; } if (r < 0) { if ((errno == EAGAIN) || (errno == EINTR)) { continue; } return fatal("poll failed"); } errno = 0; r = receive_packet(s, &reply); if (r < 0) { if (errno != 0) { LOGD("receive_packet failed (%d): %s", r, strerror(errno)); if (errno == ENETDOWN || errno == ENXIO) { return -1; } } continue; } #if VERBOSE > 1 dump_dhcp_msg(&reply, r); #endif decode_dhcp_msg(&reply, r, &info); if (state == STATE_SELECTING) { valid_reply = is_valid_reply(&discover_msg, &reply, r); } else { valid_reply = is_valid_reply(&request_msg, &reply, r); } if (!valid_reply) { printerr("invalid reply\n"); continue; } if (verbose) dump_dhcp_info(&info); switch(state) { case STATE_SELECTING: if (info.type == DHCPOFFER) { state = STATE_REQUESTING; timeout = TIMEOUT_INITIAL; xid++; goto transmit; } break; case STATE_REQUESTING: if (info.type == DHCPACK) { printerr("configuring %s\n", ifname); close(s); return dhcp_configure(ifname, &info); } else if (info.type == DHCPNAK) { printerr("configuration request denied\n"); close(s); return -1; } else { printerr("ignoring %s message in state %d\n", dhcp_type_to_name(info.type), state); } break; } } close(s); return 0; }
struct ifaddrs *get_interface(const char *name, sa_family_t family) { unsigned addr, flags; int masklen; struct ifaddrs *ifa; struct sockaddr_in *saddr = NULL; struct sockaddr_in *smask = NULL; struct sockaddr_ll *hwaddr = NULL; unsigned char hwbuf[ETH_ALEN]; if (ifc_get_info(name, &addr, &masklen, &flags)) return NULL; if ((family == AF_INET) && (addr == 0)) return NULL; ifa = malloc(sizeof(struct ifaddrs)); if (!ifa) return NULL; memset(ifa, 0, sizeof(struct ifaddrs)); ifa->ifa_name = malloc(strlen(name)+1); if (!ifa->ifa_name) { free(ifa); return NULL; } strcpy(ifa->ifa_name, name); ifa->ifa_flags = flags; if (family == AF_INET) { saddr = malloc(sizeof(struct sockaddr_in)); if (saddr) { saddr->sin_addr.s_addr = addr; saddr->sin_family = family; } ifa->ifa_addr = (struct sockaddr *)saddr; if (masklen != 0) { smask = malloc(sizeof(struct sockaddr_in)); if (smask) { smask->sin_addr.s_addr = prefixLengthToIpv4Netmask(masklen); smask->sin_family = family; } } ifa->ifa_netmask = (struct sockaddr *)smask; } else if (family == AF_PACKET) { if (!ifc_get_hwaddr(name, hwbuf)) { hwaddr = malloc(sizeof(struct sockaddr_ll)); if (hwaddr) { memset(hwaddr, 0, sizeof(struct sockaddr_ll)); hwaddr->sll_family = family; /* hwaddr->sll_protocol = ETHERTYPE_IP; */ hwaddr->sll_hatype = ARPHRD_ETHER; hwaddr->sll_halen = ETH_ALEN; memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN); } } ifa->ifa_addr = (struct sockaddr *)hwaddr; ifa->ifa_netmask = (struct sockaddr *)smask; } return ifa; }