/* AP Radar * June 2002 * donald.g.park@iname.com * * Released under the MIT Open Source Licence * http://www.opensource.org/licenses/mit-license.php */ #include #include #include #include #include #include #include #include #include "NetworkInterface.h" #include "AccessPoint.h" #include "Config.h" NetworkInterface::NetworkInterface() { gatewayPingTime = 0; drivername = 0; } void NetworkInterface::setName(string* n) { name = n; } string* NetworkInterface::getName() { return name; } void NetworkInterface::associate(AccessPoint* ap) { // Set this interface to the parameters specified in the passed-in AccessPoint setEssid(ap->getEssid()); if(ap->getMode() == 1) { // ad-hoc setMode(1); } if(ap->getMode() == 2) { // managed setMode(2); } if(ap->getMode() == 3) { // master setMode(2); } if(config->getRunDhcp()) { // Kick off a DHCP request string cmdline = *(getConfig()->getDhcpCommand()) + " " + *getName() + " & "; cout << "Launching \"" << cmdline << "\"" << endl; system(cmdline.c_str()); } } void NetworkInterface::setEssid(string* e) { // IW_SET_EXT_ERR(skfd, ifname, SIOCSIWESSID, &wrq, "Set ESSID"); struct iwreq wrq; wrq.u.essid.flags = 1; wrq.u.essid.pointer = (caddr_t) e->c_str(); wrq.u.essid.length = strlen(e->c_str()) + 1; if(iw_set_ext(getConfig()->getSkfd(), (char*)getName()->c_str(), SIOCSIWESSID, &wrq) < 0) { cout << "Error setting essid" << endl; } } string* NetworkInterface::getEssid() { // return essid; /* Get ESSID */ struct iwreq wrq; char str[64]; memset((char *) &str, '\0', 64); wrq.u.essid.pointer = (caddr_t) str; wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; wrq.u.essid.flags = 0; if(iw_get_ext(getConfig()->getSkfd(), (char*)name->c_str(), SIOCGIWESSID, &wrq) >= 0) { return new string(str); } return new string("unknown"); } void NetworkInterface::setBssid(char* b) { } char* NetworkInterface::getBssid() { return ""; } void NetworkInterface::setMode(int m) { struct iwreq wrq; //IW_SET_EXT_ERR(skfd, ifname, SIOCSIWMODE, &wrq, "Set Mode"); wrq.u.mode = m; if(iw_set_ext(getConfig()->getSkfd(), (char*)getName()->c_str(), SIOCSIWMODE, &wrq) < 0) { cout << "Error setting operation mode" << endl; } } int NetworkInterface::getMode() { struct iwreq wrq; /* Get operation mode */ if(iw_get_ext(getConfig()->getSkfd(), (char*)name->c_str(), SIOCGIWMODE, &wrq) >= 0) { return wrq.u.mode; } return -1; } string* NetworkInterface::getModeString() { int mode = getMode(); string* modename = new string("unknown"); if(mode == 1) modename = new string("ad-hoc"); if(mode == 2) modename = new string("managed"); if(mode == 3) modename = new string("master"); // default case return modename; } void NetworkInterface::setWEP(int w) { } int NetworkInterface::getWEP() { return 0; } void NetworkInterface::setFrequency(float f) { } float NetworkInterface::getFrequency() { return 0; } #define ETHTOOL_BUSINFO_LEN 32 /* these strings are set to whatever the driver author decides... */ struct ethtool_drvinfo { // I couldnt get the asm/types.h u32 definiton to work :( unsigned int cmd; char driver[32]; /* driver short name, "tulip", "eepro100" */ char version[32]; /* driver version string */ char fw_version[32]; /* firmware version string, if applicable */ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ /* For PCI devices, use pci_dev->slot_name. */ char reserved1[32]; char reserved2[16]; unsigned int n_stats; /* number of u64's from ETHTOOL_GSTATS */ unsigned int testinfo_len; unsigned int eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ unsigned int regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ } drvinfo; string* NetworkInterface::getDriverName() { if(drivername != NULL) { return drivername; } int err; struct ifreq ifr; /* Setup our control structures. */ memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, name->c_str()); int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("ethtool-style open DGRAM socket failed"); } else { #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ drvinfo.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t)&drvinfo; #define SIOCETHTOOL 0x8946 err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { perror("ethtool driver name failed"); } else { cout << "ethtool-style driver name: " << drvinfo.driver << "(version: " << drvinfo.version << ")" << endl; if(strlen(drvinfo.driver)) { return new string(drvinfo.driver); } } } // fall-back driver detection attempt struct stat buf; int retval; drivername = new string("unknown"); // Test for aironet // look for /proc/driver/aironet string oo = "/proc/driver/aironet/" + *(getName()); cout << "testing " << oo << endl; retval = stat(oo.c_str() , &buf); if(retval == 0) { if(S_ISDIR(buf.st_mode)) { drivername = new string("aironet"); } } // Test for hostap string oo2 = "/proc/net/hostap/" + *(getName()); cout << "testing " << oo2 << endl; retval = stat(oo2.c_str() , &buf); // stat it if(retval == 0) { if(S_ISDIR(buf.st_mode)) { drivername = new string("hostap"); } } // Test for a driverloaded win32 driver (horrors) string oo3 = "/proc/net/driverloader/" + *(getName()); cout << "testing " << oo3 << endl; retval = stat(oo3.c_str() , &buf); // stat it if(retval == 0) { if(S_ISDIR(buf.st_mode)) { drivername = new string("driverloader"); } } return drivername; } void NetworkInterface::getStats() { // iwstats * stats; // struct iwreq wrq; // wrq.u.data.pointer = (caddr_t) stats; // wrq.u.data.length = 0; // wrq.u.data.flags = 1; /* Clear updated flag */ // strncpy(wrq.ifr_name, ifname, IFNAMSIZ); // if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0) // return false; } void NetworkInterface::ping(Ipv4Address* host) { if(host == NULL) return; ping(host->toString()); } void NetworkInterface::ping(string* host) { if(host == NULL) return; // ping the first default gateway that uses this interface int icmp_sock; /* socket file descriptor */ icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(icmp_sock == -1) { fprintf(stdout,"ping socket creation error. not running as root?\n"); return; } fcntl(icmp_sock,F_SETFL,O_NONBLOCK); struct hostent *hp = NULL; hp = gethostbyname( host->c_str() ); struct sockaddr_in taddr, faddr; if(hp != NULL ) { memcpy( &taddr.sin_addr, hp->h_addr_list[0], sizeof( taddr.sin_addr )); taddr.sin_port = 0; taddr.sin_family = AF_INET; } else if( inet_aton( host->c_str(), &taddr.sin_addr ) == 0 ) { return; } #define ICMP_MINLEN 8 #define HDRLEN ICMP_MINLEN #define PKTSIZE 64 #define DATALEN (PKTSIZE-HDRLEN) unsigned char buf[ HDRLEN + DATALEN ]; struct icmp *icp; icp = (struct icmp *)buf; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = getpid() & 0xFFFF; icp->icmp_cksum = ipchecksum((unsigned short *)icp, HDRLEN+DATALEN ); int retval; const sockaddr* fyouaddr = (const sockaddr*)&taddr; if(( retval = sendto( icmp_sock, buf, sizeof( buf ), 0, fyouaddr, sizeof( taddr ))) < 0 ) { cout << "ping sendto error" << endl; return ; } // Wait for answer // This should be in another thread time_t now = time(NULL); bool timewait = true; while(timewait) { socklen_t fromlen = sizeof(faddr); if ((retval = recvfrom(icmp_sock, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&faddr, &fromlen)) < 0) { if (errno == EINTR) { cout << "ping() EINTR error" << endl; return; } } else { cout << "ping() something received" << endl; timewait = false; setGatewayPingTime(time(NULL)); } // stop at one second if(time(NULL) - now >= 1) { timewait = false; } } } Ipv4Address* NetworkInterface::getIpv4Address() { struct ifreq ifr; struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; int sockfd, i; bzero(&ifr, sizeof(ifr)); sockfd = socket(AF_INET, SOCK_STREAM, 0); if(getName() != NULL) { strcpy(ifr.ifr_name, getName()->c_str()); } else { return NULL; cout << "cant get IP address. no interface name. " << endl; } sin->sin_family = AF_INET; if(ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) { unsigned int addr = sin->sin_addr.s_addr; return new Ipv4Address( addr & 0xff, (addr & 0xff00) >> 8, (addr & 0xff0000) >> 16, (addr & 0xff000000) >> 24); } return NULL; } Ipv4Address* NetworkInterface::getIpv4Gateway() { ifstream *in; in = new ifstream("/proc/net/route"); string f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11; while (*in >> f1 >> f2 >> f3 >> f4 >> f5 >> f6 >> f7 >> f8 >> f9 >> f10 >> f11) { if(f2 == "00000000") { // cout << "default route dev:" << f1 << " net:" << f2 << // " gw:" << f3 << endl; int i4 = (int)strtod(("0x"+f3.substr(0,2)).c_str(), NULL); int i3 = (int)strtod(("0x"+f3.substr(2,2)).c_str(), NULL); int i2 = (int)strtod(("0x"+f3.substr(4,2)).c_str(), NULL); int i1 = (int)strtod(("0x"+f3.substr(6,2)).c_str(), NULL); Ipv4Address* ip = new Ipv4Address(i1,i2,i3,i4); return ip; } } return NULL; } void NetworkInterface::setGatewayPingTime(time_t pingtime) { gatewayPingTime = pingtime; } const time_t NetworkInterface::getGatewayPingTime() { return gatewayPingTime; } unsigned short NetworkInterface::ipchecksum(unsigned short *addr, register int len) { register int nleft = len; const u_short *w = addr; register u_short answer; register int sum = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) sum += htons(*(u_char *)w << 8); /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } string* NetworkInterface::findDefaultRoute() { // the lame way - open /proc/net/route // the more kernel-foo way, open a NETLINK socket // int sock_fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); } /* * Copyright (c) 2002 Donald G. Park * The MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */