/***************************************************************************** * * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * * The IgH EtherCAT Master is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * vim: expandtab * ****************************************************************************/ #include #include #include #include #include using namespace std; #include "CommandIp.h" #include "MasterDevice.h" /****************************************************************************/ CommandIp::CommandIp(): Command("ip", "Set EoE IP parameters.") { } /****************************************************************************/ string CommandIp::helpString(const string &binaryBaseName) const { stringstream str; str << binaryBaseName << " " << getName() << " [OPTIONS] " << endl << endl << getBriefDescription() << endl << endl << "This command requires a single slave to be selected." << endl << endl << "IP parameters can be appended as argument pairs:" << endl << endl << " ip_address [/prefix] IP address (optionally with" << endl << " decimal subnet prefix)" << endl << " mac_address Link-layer address (may contain" << endl << " colons or hyphens)" << endl << " default_gateway Default gateway" << endl << " dns_address DNS server address" << endl << " hostname Host name (max. 32 byte)" << endl << endl << "IPv4 adresses can be given either in dot notation or as" << endl << "hostnames, which will be automatically resolved." << endl << endl << "Command-specific options:" << endl << " --alias -a " << endl << " --position -p Slave selection. See the help of" << endl << " the 'slaves' command." << endl << endl << numericInfo(); return str.str(); } /****************************************************************************/ void CommandIp::execute(const StringVector &args) { if (args.size() <= 0) { return; } if (args.size() % 2) { stringstream err; err << "'" << getName() << "' needs an even number of arguments!"; throwInvalidUsageException(err); } ec_ioctl_eoe_ip_t io = {}; for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) { string arg = args[argIdx]; string val = args[argIdx + 1]; std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower); if (arg == "link" or arg == "mac_address") { parseMac(io.mac_address, val); io.mac_address_included = 1; } else if (arg == "addr" or arg == "ip_address") { parseIpv4Prefix(&io, val); io.ip_address_included = 1; } else if (arg == "default" or arg == "default_gateway") { resolveIpv4(&io.gateway, val); io.gateway_included = 1; } else if (arg == "dns" or arg == "dns_adress") { resolveIpv4(&io.dns, val); io.dns_included = 1; } else if (arg == "name" or arg == "hostname") { if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) { stringstream err; err << "Name too long!"; throwInvalidUsageException(err); } unsigned int i; for (i = 0; i < val.size(); i++) { io.name[i] = val[i]; } io.name[i] = 0; io.name_included = 1; } else { stringstream err; err << "Unknown argument '" << args[argIdx] << "'!"; throwInvalidUsageException(err); } } MasterDevice m(getSingleMasterIndex()); m.open(MasterDevice::ReadWrite); SlaveList slaves = selectedSlaves(m); if (slaves.size() != 1) { throwSingleSlaveRequired(slaves.size()); } io.slave_position = slaves.front().position; // execute actual request try { m.setIpParam(&io); } catch (MasterDeviceException &e) { throw e; } } /****************************************************************************/ void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str) { unsigned int pos = 0; for (unsigned int i = 0; i < EC_ETH_ALEN; i++) { if (pos + 2 > str.size()) { stringstream err; err << "Incomplete MAC address!"; throwInvalidUsageException(err); } string byteStr = str.substr(pos, 2); pos += 2; stringstream s; s << byteStr; unsigned int byteValue; s >> hex >> byteValue; if (s.fail() || !s.eof() || byteValue > 0xff) { stringstream err; err << "Invalid MAC address!"; throwInvalidUsageException(err); } mac[i] = byteValue; while (pos < str.size() && (str[pos] == ':' || str[pos] == '-')) { pos++; } } } /****************************************************************************/ void CommandIp::parseIpv4Prefix(ec_ioctl_eoe_ip_t *io, const string &str) { size_t pos = str.find('/'); string host; io->subnet_mask_included = pos != string::npos; if (pos == string::npos) { // no prefix found host = str; } else { host = str.substr(0, pos); string prefixStr = str.substr(pos + 1, string::npos); stringstream s; s << prefixStr; unsigned int prefix; s >> prefix; if (s.fail() || !s.eof() || prefix > 32) { stringstream err; err << "Invalid prefix '" << prefixStr << "'!"; throwInvalidUsageException(err); } uint32_t mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF; io->subnet_mask.s_addr = htonl(mask); } resolveIpv4(&io->ip_address, host); } /****************************************************************************/ void CommandIp::resolveIpv4(struct in_addr *dst, const string &str) { struct addrinfo hints = {}; struct addrinfo *res; hints.ai_family = AF_INET; // only IPv4 int ret = getaddrinfo(str.c_str(), NULL, &hints, &res); if (ret) { stringstream err; err << "Lookup of '" << str << "' failed: " << gai_strerror(ret) << endl; throwCommandException(err.str()); } if (!res) { // returned list is empty stringstream err; err << "Lookup of '" << str << "' failed." << endl; throwCommandException(err.str()); } const struct sockaddr_in *in_addr = (const struct sockaddr_in *) res->ai_addr; *dst = in_addr->sin_addr; freeaddrinfo(res); } /****************************************************************************/