From: chris-kirby Date: Tue, 11 Oct 2016 20:42:04 +0000 (-0600) Subject: v19 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fexternal-wireless-tools.git;a=commitdiff_plain;h=b4660795a5c3dc792473889c326a30e7756e1c3b v19 --- diff --git a/wireless_tools/INSTALL b/wireless_tools/INSTALL new file mode 100644 index 0000000..9f39ed4 --- /dev/null +++ b/wireless_tools/INSTALL @@ -0,0 +1,35 @@ +You need : +-------- + o A kernel supporting wireless extensions + -> from 2.1.17 onward + -> from 2.0.30 onward + -> patch available for 1.2.13 + Note : CONFIG_NET_RADIO must be enabled + o Driver supporting wireless extensions + -> Wavelan isa from kernel 2.1.17 onward + -> Wavelan pcmcia from pcmcia 2.9.2 onward + -> Netwave pcmcia from pcmcia 2.9.12 onward + -> Wavelan IEEE pcmcia drivers + -> Proxim RangeLan2/Symphony driver + -> Patch your favourite driver + Note : more recent kernels and drivers are likely to support + more wireless extension features... + +Compile wireless tools : +---------------------- + In theory, a make should suffice. + In practice, there is big troubles with the headers. Depending +on which version of the kernel headers (might be different from +kernel) and library headers you have, you need to play with the +options buried in iwcommon.h. + + +This package was originally created by: + + Jean + +And is now being maintained by: + Justin Seger + +It seem that I've been taking over ! + Jean diff --git a/wireless_tools/Makefile b/wireless_tools/Makefile new file mode 100644 index 0000000..9764187 --- /dev/null +++ b/wireless_tools/Makefile @@ -0,0 +1,30 @@ +CC = gcc +RM = rm -f + +RM_CMD = $(RM) *.BAK *.bak *.o ,* *~ *.a + +CFLAGS=-O2 -Wall + +PROGS=iwconfig iwpriv iwspy +LIBS=-lm + +all:: $(PROGS) + +.c.o: + $(CC) $(CFLAGS) -c $< + +iwconfig: iwconfig.o iwcommon.o + gcc -O2 -o $@ $^ $(LIBS) + +iwpriv: iwpriv.o iwcommon.o + gcc -O2 -o $@ $^ $(LIBS) + +iwspy: iwspy.o iwcommon.o + gcc -O2 -o $@ $^ $(LIBS) + +clean:: + $(RM_CMD) + +depend:: + makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS) +# DO NOT DELETE diff --git a/wireless_tools/README b/wireless_tools/README new file mode 100644 index 0000000..4a706b4 --- /dev/null +++ b/wireless_tools/README @@ -0,0 +1,31 @@ + This package contain the Wireless tools, used to manipulate +the Wireless Extensions. The Wireless Extension is an interface +allowing you to set Wireless LAN specific parameters and get the +specific stats. + +iwconfig.c +---------- + The main wireless tool. Used for device configuration. + You need of course to compile it. + This also includes the functionality previously contained in iwpriv.c. + It allows you to access device specific extensions. + +iwspy.c +------- + Mobile IP support test and allow get get stats per MAC address + (instead of globally). + +iwpriv.c +-------- + Manipulate driver private ioctls. + +xwireless.c +----------- + Graphical tool for the Netwave created by Dag Brattli + + + The man page should describe adequately the behaviour of the tools. + The list of changes, credits and errata notes are in +iwcommon.h. Compilation might be tricky. + + Jean diff --git a/wireless_tools/compat.h b/wireless_tools/compat.h new file mode 100644 index 0000000..224e048 --- /dev/null +++ b/wireless_tools/compat.h @@ -0,0 +1,96 @@ +/* This whole file is flaky */ +/* This is all we need to compile and can't find only in linux headers. + * So, I did copy past here... + */ +#define __u8 unsigned char +#define __u16 unsigned short +#define __u32 unsigned long /* Hum, and on Alpha ? */ +#define __u64 unsigned long long /* Unsure about this one */ + +#define IFNAMSIZ 16 +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ETH_ALEN 6 /* Octets in one ethernet addr */ + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ +struct ifreq +{ +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_metric; + int ifru_mtu; +#if 0 + struct ifmap ifru_map; +#endif + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + caddr_t ifru_data; + } ifr_ifru; +}; +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf +{ + int ifc_len; /* size of buffer */ + union + { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + +/* Internet address. */ +struct in_addr { + __u32 s_addr; +}; + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Structure describing an Internet (IP) socket address. */ +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in { + short int sin_family; /* Address family */ + unsigned short int sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - + sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; + +#define ATF_COM 0x02 /* completed entry (ha valid) */ +/* ARP ioctl request. */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ + char arp_dev[16]; +}; + diff --git a/wireless_tools/iwcommon.c b/wireless_tools/iwcommon.c new file mode 100644 index 0000000..43de184 --- /dev/null +++ b/wireless_tools/iwcommon.c @@ -0,0 +1,392 @@ +/* + * Wireless Tools + * + * Jean II - HPLB '99 + * + * Common subroutines to all the wireless tools... + */ + +#include "iwcommon.h" /* Header */ + +/************************ SOCKET SUBROUTINES *************************/ + +/*------------------------------------------------------------------*/ +/* + * Open a socket. + * Depending on the protocol present, open the right socket. The socket + * will allow us to talk to the driver. + */ +int +sockets_open(void) +{ + int ipx_sock = -1; /* IPX socket */ + int ax25_sock = -1; /* AX.25 socket */ + int inet_sock = -1; /* INET socket */ + int ddp_sock = -1; /* Appletalk DDP socket */ + + inet_sock=socket(AF_INET, SOCK_DGRAM, 0); + ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0); + ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0); + ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0); + /* + * Now pick any (exisiting) useful socket family for generic queries + */ + if(inet_sock!=-1) + return inet_sock; + if(ipx_sock!=-1) + return ipx_sock; + if(ax25_sock!=-1) + return ax25_sock; + /* + * If this is -1 we have no known network layers and its time to jump. + */ + + return ddp_sock; +} + +/*********************** WIRELESS SUBROUTINES ************************/ + +/*------------------------------------------------------------------*/ +/* + * Get the range information out of the driver + */ +int +get_range_info(int skfd, + char * ifname, + iwrange * range) +{ + struct iwreq wrq; + + strcpy(wrq.ifr_name, ifname); + wrq.u.data.pointer = (caddr_t) range; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) + return(-1); + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Get information about what private ioctls are supported by the driver + */ +int +get_priv_info(int skfd, + char * ifname, + iwprivargs * priv) +{ + struct iwreq wrq; + + /* Ask the driver */ + strcpy(wrq.ifr_name, ifname); + wrq.u.data.pointer = (caddr_t) priv; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) + return(-1); + + /* Return the number of ioctls */ + return(wrq.u.data.length); +} + +/********************** FREQUENCY SUBROUTINES ***********************/ + +/*------------------------------------------------------------------*/ +/* + * Convert a floating point the our internal representation of + * frequencies. + * The kernel doesn't want to hear about floating point, so we use + * this custom format instead. + */ +void +float2freq(double in, + iwfreq * out) +{ + out->e = (short) (floor(log10(in))); + if(out->e > 8) + { + out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100; + out->e -= 8; + } + else + { + out->m = in; + out->e = 0; + } +} + +/*------------------------------------------------------------------*/ +/* + * Convert our internal representation of frequencies to a floating point. + */ +double +freq2float(iwfreq * in) +{ + return ((double) in->m) * pow(10,in->e); +} + + +/*********************** ADDRESS SUBROUTINES ************************/ +/* + * This section is mostly a cut & past from net-tools-1.2.0 + * manage address display and input... + */ + +/*------------------------------------------------------------------*/ +/* + * Check if interface support the right address types... + */ +int +check_addr_type(int skfd, + char * ifname) +{ + struct ifreq ifr; + + /* Get the type of interface address */ + strcpy(ifr.ifr_name, ifname); + if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) || + (ifr.ifr_addr.sa_family != AF_INET)) + { + /* Deep trouble... */ + fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname); + return(-1); + } + +#ifdef DEBUG + printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family, + *((unsigned long *) ifr.ifr_addr.sa_data)); +#endif + + /* Get the type of hardware address */ + strcpy(ifr.ifr_name, ifname); + if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) || + (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)) + { + /* Deep trouble... */ + fprintf(stderr, "Interface %s doesn't support MAC addresses\n", + ifname); + return(-1); + } + +#ifdef DEBUG + printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family, + pr_ether(ifr.ifr_hwaddr.sa_data)); +#endif + + return(0); +} + + +/*------------------------------------------------------------------*/ +/* + * Display an Ethernet address in readable format. + */ +char * +pr_ether(unsigned char *ptr) +{ + static char buff[64]; + + sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", + (ptr[0] & 0xFF), (ptr[1] & 0xFF), (ptr[2] & 0xFF), + (ptr[3] & 0xFF), (ptr[4] & 0xFF), (ptr[5] & 0xFF) + ); + return(buff); +} + +/*------------------------------------------------------------------*/ +/* + * Input an Ethernet address and convert to binary. + */ +int +in_ether(char *bufp, struct sockaddr *sap) +{ + unsigned char *ptr; + char c, *orig; + int i, val; + + sap->sa_family = ARPHRD_ETHER; + ptr = sap->sa_data; + + i = 0; + orig = bufp; + while((*bufp != '\0') && (i < ETH_ALEN)) { + val = 0; + c = *bufp++; + if (isdigit(c)) val = c - '0'; + else if (c >= 'a' && c <= 'f') val = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') val = c - 'A' + 10; + else { +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return(-1); + } + val <<= 4; + c = *bufp++; + if (isdigit(c)) val |= c - '0'; + else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10; + else { +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig); +#endif + errno = EINVAL; + return(-1); + } + *ptr++ = (unsigned char) (val & 0377); + i++; + + /* We might get a semicolon here - not required. */ + if (*bufp == ':') { + if (i == ETH_ALEN) { +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): trailing : ignored!\n", + orig) +#endif + ; /* nothing */ + } + bufp++; + } + } + + /* That's it. Any trailing junk? */ + if ((i == ETH_ALEN) && (*bufp != '\0')) { +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): trailing junk!\n", orig); + errno = EINVAL; + return(-1); +#endif + } + +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data)); +#endif + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Input an Internet address and convert to binary. + */ +int +in_inet(char *bufp, struct sockaddr *sap) +{ + struct hostent *hp; + struct netent *np; + char *name = bufp; + struct sockaddr_in *sin = (struct sockaddr_in *) sap; + + /* Grmpf. -FvK */ + sin->sin_family = AF_INET; + sin->sin_port = 0; + + /* Default is special, meaning 0.0.0.0. */ + if (!strcmp(name, "default")) { + sin->sin_addr.s_addr = INADDR_ANY; + return(1); + } + + /* Try the NETWORKS database to see if this is a known network. */ + if ((np = getnetbyname(name)) != (struct netent *)NULL) { + sin->sin_addr.s_addr = htonl(np->n_net); + strcpy(name, np->n_name); + return(1); + } + + if ((hp = gethostbyname(name)) == (struct hostent *)NULL) { + errno = h_errno; + return(-1); + } + memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length); + strcpy(name, hp->h_name); + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Input an address and convert to binary. + */ +int +in_addr(int skfd, + char * ifname, + char * bufp, + struct sockaddr *sap) +{ + /* Check if it is a hardware or IP address */ + if(index(bufp, ':') == NULL) + { + struct sockaddr if_address; + struct arpreq arp_query; + + /* Read interface address */ + if(in_inet(bufp, &if_address) < 0) + { + fprintf(stderr, "Invalid interface address %s\n", bufp); + return(-1); + } + + /* Translate IP addresses to MAC addresses */ + memcpy((char *) &(arp_query.arp_pa), + (char *) &if_address, + sizeof(struct sockaddr)); + arp_query.arp_ha.sa_family = 0; + arp_query.arp_flags = 0; + /* The following restrict the search to the interface only */ + /* For old kernels which complain, just comment it... */ + strcpy(arp_query.arp_dev, ifname); + if((ioctl(skfd, SIOCGARP, &arp_query) < 0) || + !(arp_query.arp_flags & ATF_COM)) + { + fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n", + bufp, ifname, errno); + return(-1); + } + + /* Store new MAC address */ + memcpy((char *) sap, + (char *) &(arp_query.arp_ha), + sizeof(struct sockaddr)); + +#ifdef DEBUG + printf("IP Address %s => Hw Address = %s\n", + bufp, pr_ether(sap->sa_data)); +#endif + } + else /* If it's an hardware address */ + /* Get the hardware address */ + if(in_ether(bufp, sap) < 0) + { + fprintf(stderr, "Invalid hardware address %s\n", bufp); + return(-1); + } + +#ifdef DEBUG + printf("Hw Address = %s\n", pr_ether(sap->sa_data)); +#endif + + return(0); +} + +/************************* MISC SUBROUTINES **************************/ + +/*------------------------------------------------------------------*/ +/* + */ +int +byte_size(int args) +{ + int ret = args & IW_PRIV_SIZE_MASK; + + if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) || + ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT)) + ret <<= 2; + + if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE) + return 0; + + return ret; +} + diff --git a/wireless_tools/iwcommon.h b/wireless_tools/iwcommon.h new file mode 100644 index 0000000..cfdea27 --- /dev/null +++ b/wireless_tools/iwcommon.h @@ -0,0 +1,268 @@ +/* + * Wireless Tools + * + * Jean II - HPLB '99 + * + * Common header for the wireless tools... + */ + +#ifndef IWCOMMON_H +#define IWCOMMON_H + +/************************** DOCUMENTATION **************************/ +/* + * None ? Todo... + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * wireless 16 : (Jean Tourrilhes) + * ----------- + * o iwconfig, iwpriv & iwspy + * + * wireless 17 : (Justin Seger) + * ----------- + * o Compile under glibc fix + * o merge iwpriv in iwconfig + * o Add Wavelan roaming support + * o Update man page of iwconfig + * + * wireless 18 : + * ----------- + * (From Andreas Neuhaus ) + * o Many fix to remove "core dumps" in iwconfig + * o Remove useless headers in iwconfig + * o CHAR wide private ioctl + * (From Jean Tourrilhes) + * o Create iwcommon.h and iwcommon.c + * o Separate iwpriv again for user interface issues + * The folllowing didn't make sense and crashed : + * iwconfig eth0 priv sethisto 12 15 nwid 100 + * o iwspy no longer depend on net-tools-1.2.0 + * o Reorganisation of the code, cleanup + * o Add ESSID stuff in iwconfig + * o Add display of level & noise in dBm (stats in iwconfig) + * o Update man page of iwconfig and iwpriv + * o Add xwireless (didn't check if it compiles) + * (From Dean W. Gehnert ) + * o Minor fixes + * (Jan Rafaj ) + * o Cosmetic changes (sensitivity relative, freq list) + * o Frequency computation on double + * o Compile clean on libc5 + * (From Jean Tourrilhes) + * o Move listing of frequencies to iwspy + * o Add AP address stuff in iwconfig + * o Add AP list stuff in iwspy + * + * wireless 19 : + * ----------- + * (From Jean Tourrilhes) + * o Allow for sensitivity in dBm (if < 0) [iwconfig] + * o Formatting changes in displaying ap address in [iwconfig] + * o Slightly improved man pages and usage display + * o Add channel number for each frequency in list [iwspy] + * o Add nickname... [iwconfig] + * o Add "port" private ioctl shortcut [iwpriv] + * o If signal level = 0, no range or dBms [iwconfig] + * o I think I now got set/get char strings right in [iwpriv] + * (From Thomas Ekstrom ) + * o Fix a very obscure bug in [iwspy] + */ + +/* ----------------------------- TODO ----------------------------- */ +/* + * One day, maybe... + * + * iwconfig : + * -------- + * Use new 802.11 parameters (rate, rts, frag)... + * + * iwpriv : + * ------ + * ? + * + * iwspy : + * ----- + * ? + * + * Doc & man pages : + * --------------- + * ? + */ + +/***************************** INCLUDES *****************************/ + +/* Standard headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* gethostbyname, getnetbyname */ + +/* This is our header selection. Try to hide the mess and the misery :-( + * Please choose only one of the define... + */ +#define KER2_2_HEADERS /* Kernel 2.2.X + Glibc - ok for most people */ +#undef LINUX_HEADERS /* Kernel 2.0.X + Glibc - Debian 2.0, RH5 */ +#undef LIBC5_HEADERS /* Kernel 2.0.X + libc5 - old systems */ +#undef PRIVATE_HEADERS /* Ugly last resort case */ + +#ifdef KER2_2_HEADERS +#include +#include /* For ARPHRD_ETHER */ +#include /* For AF_INET & struct sockaddr */ +#include /* For struct sockaddr_in */ + +/* Wireless extensions */ +#include + +#endif /* KER2_2_HEADERS */ + +#ifdef LINUX_HEADERS +#include /* For ARPHRD_ETHER */ +#include /* For AF_INET & struct sockaddr */ +#include /* For struct sockaddr_in */ + +/* Wireless extensions */ +#include + +#endif /* LINUX_HEADERS */ + +#ifdef LIBC5_HEADERS +#include /* For AF_INET & struct sockaddr & socket() */ +#include /* For ARPHRD_ETHER */ +#include /* For struct sockaddr_in */ + +/* Wireless extensions */ +#include + +#endif /* LIBC5_HEADERS */ + +#ifdef PRIVATE_HEADERS +#include +#include +#include +#include "compat.h" /* Don't ask ! */ + +/* Wireless extensions */ +#include "wireless.h" + +#endif /* PRIVATE_HEADERS */ + + +/****************************** DEBUG ******************************/ + + +/************************ CONSTANTS & MACROS ************************/ + +/* Some usefull constants */ +#define KILO 1e3 +#define MEGA 1e6 +#define GIGA 1e9 + +/* Some hack */ +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 /* Should be in wireless.h */ +#endif +#ifndef IW_MAX_AP +#define IW_MAX_AP 8 /* Should be in wireless.h */ +#endif + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct iw_statistics iwstats; +typedef struct iw_range iwrange; +typedef struct iw_freq iwfreq; +typedef struct iw_priv_args iwprivargs; +typedef struct sockaddr sockaddr; + +/* Structure for storing all wireless information for each device */ +typedef struct wireless_info +{ + char name[IFNAMSIZ]; /* Wireless/protocol name */ + int has_nwid; + int nwid_on; + u_long nwid; /* Network ID */ + int has_freq; + float freq; /* Frequency/channel */ + int has_sens; + int sens; /* sensitivity */ + int has_enc; + int enc_method; /* encoding method or off */ + long long enc_key; /* key used */ + int has_essid; + int essid_on; + char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID (extended network) */ + int has_nickname; + char nickname[IW_ESSID_MAX_SIZE + 1]; /* NickName */ + int has_ap_addr; + sockaddr ap_addr; /* Access point address */ + int has_bitrate; + long bitrate; /* Bit rate in bps */ + int bitrate_fixed; /* Fixed or auto */ + int has_rts; + long rts; /* RTS threshold in bytes */ + int rts_fixed; /* Fixed or auto */ + int has_frag; + long frag; /* Fragmentation threshold in bytes */ + int frag_fixed; /* Fixed or auto */ + + /* Stats */ + iwstats stats; + int has_stats; + iwrange range; + int has_range; +} wireless_info; + +/**************************** PROTOTYPES ****************************/ +/* + * All the functions in iwcommon.c + */ +/* ---------------------- SOCKET SUBROUTINES -----------------------*/ +int + sockets_open(void); +/* --------------------- WIRELESS SUBROUTINES ----------------------*/ +int + get_range_info(int skfd, + char * ifname, + iwrange * range); +int + get_priv_info(int skfd, + char * ifname, + iwprivargs * priv); +/* -------------------- FREQUENCY SUBROUTINES --------------------- */ +void + float2freq(double in, + iwfreq * out); +double + freq2float(iwfreq * in); +/* --------------------- ADDRESS SUBROUTINES ---------------------- */ +int + check_addr_type(int skfd, + char * ifname); +char * + pr_ether(unsigned char *ptr); +int + in_ether(char *bufp, struct sockaddr *sap); +int + in_inet(char *bufp, struct sockaddr *sap); +int + in_addr(int skfd, + char * ifname, + char * bufp, + struct sockaddr *sap); +/* ----------------------- MISC SUBROUTINES ------------------------ */ +int + byte_size(int args); + +/**************************** VARIABLES ****************************/ + +#endif /* IWCOMMON_H */ diff --git a/wireless_tools/iwconfig b/wireless_tools/iwconfig new file mode 100644 index 0000000..abc90a6 Binary files /dev/null and b/wireless_tools/iwconfig differ diff --git a/wireless_tools/iwconfig.8 b/wireless_tools/iwconfig.8 index b2e3d60..24c1e50 100644 --- a/wireless_tools/iwconfig.8 +++ b/wireless_tools/iwconfig.8 @@ -13,7 +13,11 @@ iwconfig \- configure a wireless network interface .SH SYNOPSIS .BI "iwconfig [" interface ] .br -.BI "iwconfig " interface " [nwid " N "] [freq " F ] +.BI "iwconfig " interface " [essid " X "] [nwid " N "] [freq " F "] [channel " C ] +.br +.BI " [sens " S "] [enc " E "] [ap " A "] [nick " NN ] +.br +.BI " [rate " R "] [rts " RT "] [frag " FT ] .\" .\" DESCRIPTION part .\" @@ -38,16 +42,101 @@ device for details. .\" .SH PARAMETERS .TP -.B nwid -Set the Network ID (in some products it is also called Domain). As all -adjacent wireless networks share the same medium, this number is used -to differenciate them (create virtual networks). +.B essid +Set the ESSID (or Network Name - in some products it may also called +Domain ID). The ESSID is used to identify cells which are part of the +same virtual network. +.br +As opposed to the NWID which defines a single cell, the ESSID defines +a group of cell connected via repeaters or infrastructure, where the +user may roam. With some card, you may disable the ESSID checking +(ESSID promiscuous) with +.IR off " (and " on +to reenable it). +.TP +.BR nwid / domain +Set the Network ID (in some products it is also called Domain ID). As +all adjacent wireless networks share the same medium, this parameter +is used to differenciate them (create logical colocated networks) and +identify nodes belonguing to the same cell. With some card, you may +disable the Network ID checking (NWID promiscuous) with +.IR off " (and " on +to reenable it). .TP .BR freq / channel Set the operating frequency or channel in the device. Value below 1000 are the channel number, value over this is the frequency in Hz. You -may prepend the suffix k, M or G to the value (for example, "2.46G" -for 2.46 GHz frequency). +must prepend the suffix k, M or G to the value (for example, "2.46G" +for 2.46 GHz frequency), or add enough '0'. +.br +Channels are usually numbered starting at 1, +and you may use +.IR iwpriv (8) +to get the total number of channels and list the available +frequencies. Depending on regulations, some frequencies/channels may +not be available. +.TP +.B sens +Set the sensitivity threshold. This is the lowest signal level for +which we attempt a packet reception, signal lower than this are not +received. This is used to avoid receiving background noise, so you +should set it according to the average noise level. Positive values +are assumed to be the raw value used by the hardware or a percentage, +negative values are assumed to be dBm. +.br +With some hardware, this parameter also control the defer threshold +(lowest signal level for which we consider the channel busy) and the +handover threshold (lowest signal level where we stay associated with +the current access point). +.TP +.B enc +Set the encryption or scrambing key (the syntax is +.IR XXXX-XXXX-XXXX-XXXX " or " XXXXXXXX ). +Used also to control the encryption feature +.RI ( on / off ). +.TP +.B ap +Register to the Access Point given by the address, if it is +possible. When the quality of the connection goes too low, the driver +may revert back to automatic mode. +.TP +.BR nick [ name ] +Set the nickname, or the station name. Most 802.11 products do define +it, but this is not used as far as the protocols (MAC, IP, TCP) are +concerned and completely accessory as far as configuration goes. In +fact only some diagnostic tools may use it. +.TP +.BR rate / bit [ rate ] +For cards supporting multiple bit rates, set the bit-rate in b/s. The +bit-rate is the speed at which bits are transmitted over the medium, +the user speed of the link is lower due to medium sharing and +overhead. +.br +You must prepend the suffix k, M or G to the value (decimal multiplier +: 10^3, 10^6 and 10^9 b/s), or add enough '0'. Values below 1000 are +card specific, usually an index in the bit-rate list. Use +.I auto +to select the automatic bit-rate mode (fallback to lower rate on noisy +channels), which is the default for most cards, and +.I fixed +to revert back to fixed setting. +.TP +.BR rts [ _threshold ] +RTS/CTS adds a handshake before each packet transmission to make sure +that the channel is clear. This adds overhead, but increase +performance in case of hidden nodes or large number of active +nodes. This parameters set the size of the smallest packet for which +the node sends RTS, a value equal to the maximum packet size disable +the scheme. You may also set this parameter to +.IR auto ", " fixed " or " off . +.TP +.BR frag [ mentation_threshold ] +Fragmentation allow to split a IP packet in a burst of smaller +fragments transmitted on the medium. In most cases this adds overhead, +but in very noisy environment this reduce the error penalty. This +parameter set the maximum fragment size, a value equal to the maximum +packet size disable the scheme. You may also set this parameter to +.IR auto ", " fixed " or " off . .\" .\" DISPLAY part .\" @@ -57,10 +146,24 @@ For each device which support wireless extensions, will display the name of the .B MAC protocol used (name of device for proprietary protocols), the -.B NWID -and the +.B ESSID +(Network Name), the +.BR NWID , +the .B frequency -(if available). +(or channel), the +.BR sensitivity , +the +.B Access Point +address, the +.B bit-rate +(with +.B (f) +if fixed), the +.BR "RTS threshold" ", the " "fragmentation threshold" , +and the +.B encryption key +(depending on availability). See above for explanations. .PP If .I /proc/net/wireless diff --git a/wireless_tools/iwconfig.c b/wireless_tools/iwconfig.c index 33bc879..8cb9f0c 100644 --- a/wireless_tools/iwconfig.c +++ b/wireless_tools/iwconfig.c @@ -1,121 +1,47 @@ /* - * Hack my way... Jean II + * Wireless Tools + * + * Jean II - HPLB '99 + * + * Main code for "iwconfig". This is the generic tool for most + * manipulations... + * You need to link this code against "iwcommon.c" and "-lm". */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Some usefull constants */ -#define KILO 1e3 -#define MEGA 1e6 -#define GIGA 1e9 - -typedef struct iw_statistics iwstats; -typedef struct iw_range iwrange; - -/* Structure for storing all wireless information for each device */ -struct wireless_info -{ - char dev[IFNAMSIZ]; /* Interface name (device) */ - char name[12]; /* Wireless name */ - int has_nwid; - int nwid_on; - u_long nwid; /* Network ID */ - int has_freq; - u_long freq; /* Frequency/channel */ - - /* Stats */ - iwstats stats; - int has_stats; - iwrange range; - int has_range; -}; - -int skfd = -1; /* generic raw socket desc. */ -int ipx_sock = -1; /* IPX socket */ -int ax25_sock = -1; /* AX.25 socket */ -int inet_sock = -1; /* INET socket */ -int ddp_sock = -1; /* Appletalk DDP socket */ +#include "iwcommon.h" /* Header */ + +/************************* MISC SUBROUTINES **************************/ +/*------------------------------------------------------------------*/ +/* + * Print usage string + */ static void -usage(void) +iw_usage(void) { - fprintf(stderr, "Usage: iwconfig interface\n"); - fprintf(stderr, " [nwid NN]\n"); - fprintf(stderr, " [freq N.NN (add k, M or G) ]\n"); - fprintf(stderr, " [channel N]\n"); + fprintf(stderr, "Usage: iwconfig interface [essid {NN|on|off}]\n"); + fprintf(stderr, " [nwid {NN|on|off}]\n"); + fprintf(stderr, " [freq N.NNNN[k|M|G]]\n"); + fprintf(stderr, " [channel N]\n"); + fprintf(stderr, " [sens N]\n"); + fprintf(stderr, " [nick N]\n"); + fprintf(stderr, " [rate {N|auto|fixed}]\n"); + fprintf(stderr, " [rts {N|auto|fixed|off}]\n"); + fprintf(stderr, " [frag {N|auto|fixed|off}]\n"); + fprintf(stderr, " [enc NNNN-NNNN]\n"); exit(1); } -static void -print_info(struct wireless_info * info) -{ - /* Display device name */ - printf("%-8.8s ", info->dev); - - /* Display wireless name */ - printf("%s ", info->name); - - /* Display Network ID */ - if(info->has_nwid) - if(info->nwid_on) - printf("NWID:%lX ", info->nwid); - else - printf("NWID:off "); - - /* Display frequency / channel */ - if(info->has_freq) - if(info->freq < KILO) - printf("Channel:%g ", (double) info->freq); - else - if(info->freq > GIGA) - printf("Frequency:%gGHz ", info->freq / GIGA); - else - if(info->freq > MEGA) - printf("Frequency:%gMHz ", info->freq / MEGA); - else - printf("Frequency:%gkHz ", info->freq / KILO); - - printf("\n"); - - if(info->has_stats) - { - if(info->has_range) - printf(" Link quality:%d/%d Signal level:%d/%d Noise level:%d/%d\n", - info->stats.qual.qual, info->range.max_qual.qual, - info->stats.qual.level, info->range.max_qual.level, - info->stats.qual.noise, info->range.max_qual.noise); - else - printf(" Link quality:%d Signal level:%d Noise level:%d\n", - info->stats.qual.qual, - info->stats.qual.level, - info->stats.qual.noise); - - printf(" Rx invalid nwid:%d invalid crypt:%d invalid misc:%d\n", - info->stats.discard.nwid, - info->stats.discard.crypt, - info->stats.discard.misc); - } - - printf("\n"); -} +/************************* DISPLAY ROUTINES **************************/ -static int if_getstats(char *ifname, iwstats * stats) +/*------------------------------------------------------------------*/ +/* + * Read /proc/net/wireless to get the latest statistics + */ +static int +iw_getstats(char * ifname, + iwstats * stats) { FILE *f=fopen("/proc/net/wireless","r"); char buf[256]; @@ -132,39 +58,42 @@ static int if_getstats(char *ifname, iwstats * stats) bp=strchr(bp,':'); bp++; bp = strtok(bp, " ."); - sscanf(bp, "%X", &stats->status); + sscanf(bp, "%X", (unsigned int *)&stats->status); bp = strtok(NULL, " ."); - sscanf(bp, "%d", &stats->qual.qual); + sscanf(bp, "%d", (unsigned int *)&stats->qual.qual); bp = strtok(NULL, " ."); - sscanf(bp, "%d", &stats->qual.level); + sscanf(bp, "%d", (unsigned int *)&stats->qual.level); bp = strtok(NULL, " ."); - sscanf(bp, "%d", &stats->qual.noise); + sscanf(bp, "%d", (unsigned int *)&stats->qual.noise); bp = strtok(NULL, " ."); sscanf(bp, "%d", &stats->discard.nwid); bp = strtok(NULL, " ."); - sscanf(bp, "%d", &stats->discard.crypt); + sscanf(bp, "%d", &stats->discard.code); bp = strtok(NULL, " ."); sscanf(bp, "%d", &stats->discard.misc); fclose(f); - return; + return 0; } } fclose(f); return 0; } -/* Get wireless informations & config from the device driver */ +/*------------------------------------------------------------------*/ +/* + * Get wireless informations & config from the device driver + * We will call all the classical wireless ioctl on the driver through + * the socket to know what is supported and to get the settings... + */ static int -get_info(char * ifname, +get_info(int skfd, + char * ifname, struct wireless_info * info) { struct iwreq wrq; memset((char *) info, 0, sizeof(struct wireless_info)); - /* Get device name */ - strcpy(info->dev, ifname); - /* Get wireless name */ strcpy(wrq.ifr_name, ifname); if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0) @@ -187,31 +116,352 @@ get_info(char * ifname, if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0) { info->has_freq = 1; - info->freq = wrq.u.freq; + info->freq = freq2float(&(wrq.u.freq)); } - /* Get stats */ - if(if_getstats(ifname, &(info->stats)) == 0) + /* Get sensitivity */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWSENS, &wrq) >= 0) { - info->has_stats = 1; + info->has_sens = 1; + info->sens = wrq.u.sensitivity; } - /* Get ranges */ + /* Get encryption information */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWENCODE, &wrq) >= 0) + { + info->has_enc = 1; + info->enc_method = wrq.u.encoding.method; + info->enc_key = wrq.u.encoding.code; + } + +#if WIRELESS_EXT > 5 + /* Get ESSID */ + strcpy(wrq.ifr_name, ifname); + wrq.u.data.pointer = (caddr_t) info->essid; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWESSID, &wrq) >= 0) + { + info->has_essid = 1; + info->essid_on = wrq.u.data.flags; + } + + /* Get AP address */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWAP, &wrq) >= 0) + { + info->has_ap_addr = 1; + memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr)); + } +#endif /* WIRELESS_EXT > 5 */ + +#if WIRELESS_EXT > 7 + /* Get NickName */ strcpy(wrq.ifr_name, ifname); - wrq.u.data.pointer = (caddr_t) &(info->range); + wrq.u.data.pointer = (caddr_t) info->nickname; wrq.u.data.length = 0; wrq.u.data.flags = 0; - if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0) + if(ioctl(skfd, SIOCGIWNICKN, &wrq) >= 0) + if(wrq.u.data.length > 1) + info->has_nickname = 1; + + /* Get bit rate */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWRATE, &wrq) >= 0) + { + info->has_bitrate = 1; + info->bitrate_fixed = wrq.u.bitrate.fixed; + info->bitrate = wrq.u.bitrate.value; + } + + /* Get RTS threshold */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWRTS, &wrq) >= 0) + { + info->has_rts = 1; + info->rts_fixed = wrq.u.rts.fixed; + info->rts = wrq.u.rts.value; + } + + /* Get fragmentation thershold */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWFRAG, &wrq) >= 0) + { + info->has_frag = 1; + info->frag_fixed = wrq.u.frag.fixed; + info->frag = wrq.u.frag.value; + } +#endif /* WIRELESS_EXT > 7 */ + + /* Get stats */ + if(iw_getstats(ifname, &(info->stats)) == 0) { - info->has_range = 1; + info->has_stats = 1; } + /* Get ranges */ + if(get_range_info(skfd, ifname, &(info->range)) >= 0) + info->has_range = 1; + return(0); } +/*------------------------------------------------------------------*/ +/* + * Print on the screen in a neat fashion all the info we have collected + * on a device. + */ +static void +display_info(struct wireless_info * info, + char * ifname) +{ + /* Display device name and wireless name (name of the protocol used) */ + printf("%-8.8s %s ", ifname, info->name); + + /* Display ESSID (extended network), if any */ + if(info->has_essid) + { + if(info->essid_on) + printf("ESSID:\"%s\" ", info->essid); + else + printf("ESSID:off "); + } + + /* Display NickName (station name), if any */ + if(info->has_nickname) + printf("Nickname:\"%s\"", info->nickname); + + /* Formatting */ + if(info->has_essid || info->has_nickname) + printf("\n "); + + /* Display Network ID */ + if(info->has_nwid) + { + /* Note : should display right number of digit according to info + * in range structure */ + if(info->nwid_on) + printf("NWID:%lX ", info->nwid); + else + printf("NWID:off/any "); + } + + /* Display frequency / channel */ + if(info->has_freq) + { + if(info->freq < KILO) + printf("Channel:%g ", info->freq); + else + { + if(info->freq >= GIGA) + printf("Frequency:%gGHz ", info->freq / GIGA); + else + { + if(info->freq >= MEGA) + printf("Frequency:%gMHz ", info->freq / MEGA); + else + printf("Frequency:%gkHz ", info->freq / KILO); + } + } + } + + /* Display sensitivity */ + if(info->has_sens) + { + if(info->has_range) + /* Display in dBm ? */ + if(info->sens < 0) + printf("Sensitivity:%d dBm ", info->sens); + else + printf("Sensitivity:%d/%d ", info->sens, info->range.sensitivity); + else + printf("Sensitivity:%d ", info->sens); + } + + /* Display the address of the current Access Point */ + if(info->has_ap_addr) + { + /* A bit of clever formatting */ + if((info->has_nwid + 2*info->has_freq + 2*info->has_sens + + !info->has_essid) > 3) + printf("\n "); + + printf("Access Point: %s", pr_ether(info->ap_addr.sa_data)); + } + + printf("\n "); + + /* Display the currently used/set bit-rate */ + if(info->has_bitrate) + { + printf("Bit Rate:"); + if(info->bitrate >= GIGA) + printf("%g Gb/s", info->bitrate / GIGA); + else + if(info->bitrate >= MEGA) + printf("%g Mb/s", info->bitrate / MEGA); + else + printf("%g kb/s", info->bitrate / KILO); + + /* Fixed ? */ + if(info->bitrate_fixed) + printf(" (f) "); + else + printf(" "); + } + + /* Display the RTS threshold */ + if(info->has_rts) + { + printf("RTS thr:%ld B", info->rts); + + /* Fixed ? */ + if(info->rts_fixed) + printf(" (f) "); + else + printf(" "); + } + + /* Display the fragmentation threshold */ + if(info->has_bitrate) + { + printf("Frag thr:%ld B", info->frag); + + /* Fixed ? */ + if(info->frag_fixed) + printf(" (f) "); + else + printf(" "); + } + + /* Formating */ + if((info->has_bitrate) || (info->has_rts) || (info->has_bitrate)) + printf("\n "); + + if(info->has_enc) + { + printf("Encryption key:"); + if(info->enc_method) + { + int i = 0; + u_short parts[4]; + long long key = info->enc_key; + + for(i = 3; i >= 0; i--) + { + parts[i] = key & 0xFFFF; + key >>= 16; + } + + i = 0; + while((parts[i] == 0) && (i < 3)) + i++; + for(; i < 3; i++) + printf("%.4X-", parts[i]); + printf("%.4X", parts[3]); + + if(info->enc_method > 1) + printf(" (%d)", info->enc_method); + printf("\n "); + } + else + printf("off\n "); + } + + if(info->has_stats) + { + if(info->has_range && (info->stats.qual.level != 0)) + /* If the statistics are in dBm */ + if(info->stats.qual.level > info->range.max_qual.level) + printf("Link quality:%d/%d Signal level:%d dBm Noise level:%d dBm\n", + info->stats.qual.qual, info->range.max_qual.qual, + info->stats.qual.level - 0x100, + info->stats.qual.noise - 0x100); + else + /* Statistics are relative values (0 -> max) */ + printf("Link quality:%d/%d Signal level:%d/%d Noise level:%d/%d\n", + info->stats.qual.qual, info->range.max_qual.qual, + info->stats.qual.level, info->range.max_qual.level, + info->stats.qual.noise, info->range.max_qual.noise); + else + /* We can't read the range, so we don't know... */ + printf("Link quality:%d Signal level:%d Noise level:%d\n", + info->stats.qual.qual, + info->stats.qual.level, + info->stats.qual.noise); + + printf(" Rx invalid nwid:%d invalid crypt:%d invalid misc:%d\n", + info->stats.discard.nwid, + info->stats.discard.code, + info->stats.discard.misc); + } + + printf("\n"); +} + +/*------------------------------------------------------------------*/ +/* + * Print on the screen in a neat fashion all the info we have collected + * on a device. + */ +static void +print_info(int skfd, + char * ifname) +{ + struct wireless_info info; + + if(get_info(skfd, ifname, &info) < 0) + { + fprintf(stderr, "%-8.8s no wireless extensions.\n\n", + ifname); + return; + } + + /* Display it ! */ + display_info(&info, ifname); +} + +/*------------------------------------------------------------------*/ +/* + * Get info on all devices and print it on the screen + */ +static void +print_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; + + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_info(skfd, ifr->ifr_name); +} + +/************************* SETTING ROUTINES **************************/ +/*------------------------------------------------------------------*/ +/* + * Set the wireless options requested on command line + * This function is too long and probably should be split, + * because it look like the perfect definition of spaghetti code, + * but I'm way to lazy + */ static int -set_info(char * args[], /* Command line args */ +set_info(int skfd, /* The socket */ + char * args[], /* Command line args */ int count, /* Args count */ char * ifname) /* Dev name */ { @@ -221,21 +471,41 @@ set_info(char * args[], /* Command line args */ /* Set dev name */ strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + /* if nothing after the device name */ + if(count<1) + iw_usage(); + /* The other args on the line specify options to be set... */ for(i = 0; i < count; i++) { - /* Set network ID */ - if(!strcmp(args[i], "nwid")) + /* ---------- Set network ID ---------- */ + if((!strcasecmp(args[i], "nwid")) || + (!strcasecmp(args[i], "domain"))) { - if(++i >= count) - usage(); - if(!strcasecmp(args[i], "off")) + i++; + if(i >= count) + iw_usage(); + if((!strcasecmp(args[i], "off")) || + (!strcasecmp(args[i], "any"))) wrq.u.nwid.on = 0; else - if(sscanf(args[i], "%lX", &(wrq.u.nwid.nwid)) != 1) - usage(); + if(!strcasecmp(args[i], "on")) + { + /* Get old nwid */ + if(ioctl(skfd, SIOCGIWNWID, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWNWID: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + wrq.u.nwid.on = 1; + } else - wrq.u.nwid.on = 1; + if(sscanf(args[i], "%lX", (unsigned long *) &(wrq.u.nwid.nwid)) + != 1) + iw_usage(); + else + wrq.u.nwid.on = 1; if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0) { @@ -245,133 +515,356 @@ set_info(char * args[], /* Command line args */ continue; } - /* Set frequency / channel */ + /* ---------- Set frequency / channel ---------- */ if((!strncmp(args[i], "freq", 4)) || (!strcmp(args[i], "channel"))) { + double freq; + + if(++i >= count) + iw_usage(); + if(sscanf(args[i], "%lg", &(freq)) != 1) + iw_usage(); + if(index(args[i], 'G')) freq *= GIGA; + if(index(args[i], 'M')) freq *= MEGA; + if(index(args[i], 'k')) freq *= KILO; + + float2freq(freq, &(wrq.u.freq)); + + if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno)); + return(-1); + } + continue; + } + + /* ---------- Set sensitivity ---------- */ + if(!strncmp(args[i], "sens", 4)) + { + if(++i >= count) + iw_usage(); + if(sscanf(args[i], "%d", &(wrq.u.sensitivity)) != 1) + iw_usage(); + + if(ioctl(skfd, SIOCSIWSENS, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWSENS: %s\n", strerror(errno)); + return(-1); + } + continue; + } + + /* ---------- Set encryption stuff ---------- */ + if(!strncmp(args[i], "enc", 3 )) + { + unsigned long long key = 0; + if(++i >= count) + iw_usage(); + + if(!strcasecmp(args[i], "off")) + wrq.u.encoding.method = 0; + else + { + if(!strcasecmp(args[i], "on")) + { + /* Get old encryption information */ + if(ioctl(skfd, SIOCGIWENCODE, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + } + else + { + char * buff; + char * p; + u_long temp; + + p = buff = malloc(strlen(args[i] + 1)); + strcpy(buff, args[i]); + + p = strtok(buff, "-:;.,*#"); + while(p != (char *) NULL) + { + key = key << 16; + if(sscanf(p, "%lX", &temp) != 1) + iw_usage(); + key += temp; + p = strtok((char *) NULL, "-:;.,*#"); + } + + free(buff); + wrq.u.encoding.code = key; + } + /* TODO : check for "(method)" in args list */ + wrq.u.encoding.method = 1; + } + + if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0) { - struct iw_range range; - int k; + fprintf(stderr, "SIOCSIWENCODE(%d): %s\n", + errno, strerror(errno)); + return(-1); + } + continue; + } + +#if WIRELESS_EXT > 5 + /* ---------- Set ESSID ---------- */ + if(!strcasecmp(args[i], "essid")) + { + char essid[IW_ESSID_MAX_SIZE + 1]; - wrq.u.data.pointer = (caddr_t) ⦥ - wrq.u.data.length = 0; + i++; + if(i >= count) + iw_usage(); + if((!strcasecmp(args[i], "off")) || + (!strcasecmp(args[i], "any"))) + { wrq.u.data.flags = 0; - if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) + essid[0] = '\0'; + } + else + if(!strcasecmp(args[i], "on")) + { + /* Get old essid */ + wrq.u.data.pointer = (caddr_t) essid; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWESSID: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + wrq.u.data.flags = 1; + } + else + if(strlen(args[i]) > IW_ESSID_MAX_SIZE) { - fprintf(stderr, "SIOCGIWRANGE: %s\n", strerror(errno)); - return(-1); + fprintf(stderr, "ESSID too long (max %d): ``%s''\n", + IW_ESSID_MAX_SIZE, args[i]); + iw_usage(); } + else + { + wrq.u.data.flags = 1; + strcpy(essid, args[i]); + } + + wrq.u.data.pointer = (caddr_t) essid; + wrq.u.data.length = strlen(essid) + 1; + if(ioctl(skfd, SIOCSIWESSID, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno)); + return(-1); + } + continue; + } + + /* ---------- Set AP address ---------- */ + if(!strcasecmp(args[i], "ap")) + { + if(++i >= count) + iw_usage(); - printf("%d channels ; available frequencies :", - range.num_channels); - for(k = 0; k < range.num_frequency; k++) - if(range.freq[k] > GIGA) - printf(" %gGHz ", range.freq[k] / GIGA); - else - if(range.freq[k] > MEGA) - printf(" %gMHz ", range.freq[k] / MEGA); - else - printf(" %gkHz ", range.freq[k] / KILO); - printf("\n"); - return; /* no more arg */ + /* Check if we have valid address types */ + if(check_addr_type(skfd, ifname) < 0) + { + fprintf(stderr, "%-8.8s Interface doesn't support MAC & IP addresses\n", ifname); + return(-1); } - if(sscanf(args[i], "%g", &(wrq.u.freq)) != 1) - usage(); - if(index(args[i], 'G')) wrq.u.freq *= GIGA; - if(index(args[i], 'M')) wrq.u.freq *= MEGA; - if(index(args[i], 'k')) wrq.u.freq *= KILO; + /* Get the address */ + if(in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0) + iw_usage(); - if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) + if(ioctl(skfd, SIOCSIWAP, &wrq) < 0) { - fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno)); + fprintf(stderr, "SIOCSIWAP: %s\n", strerror(errno)); return(-1); } continue; } +#endif /* WIRELESS_EXT > 5 */ - /* Here we have an unrecognised arg... */ - fprintf(stderr, "Invalid argument : %s\n", args[i]); - usage(); - return(-1); - } /* for(index ... */ - return(0); -} +#if WIRELESS_EXT > 7 + /* ---------- Set NickName ---------- */ + if(!strncmp(args[i], "nick", 4)) + { + i++; + if(i >= count) + iw_usage(); + if(strlen(args[i]) > IW_ESSID_MAX_SIZE) + { + fprintf(stderr, "Name too long (max %d) : ``%s''\n", + IW_ESSID_MAX_SIZE, args[i]); + iw_usage(); + } -static void -print_devices(char *ifname) -{ - char buff[1024]; - struct wireless_info info; - struct ifconf ifc; - struct ifreq *ifr; - int i; + wrq.u.data.pointer = (caddr_t) args[i]; + wrq.u.data.length = strlen(args[i]) + 1; + if(ioctl(skfd, SIOCSIWNICKN, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWNICKN: %s\n", strerror(errno)); + return(-1); + } + continue; + } - if(ifname == (char *)NULL) - { - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + /* ---------- Set Bit-Rate ---------- */ + if((!strncmp(args[i], "bit", 3)) || + (!strcmp(args[i], "rate"))) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); - return; + i++; + if(i >= count) + iw_usage(); + if(!strcasecmp(args[i], "auto")) + { + wrq.u.bitrate.value = -1; + wrq.u.bitrate.fixed = 0; + } + else + { + if(!strcasecmp(args[i], "fixed")) + { + /* Get old bitrate */ + if(ioctl(skfd, SIOCGIWRATE, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWRATE: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + } + else /* Should be a numeric value */ + { + double brate; + + if(sscanf(args[i], "%lg", &(brate)) != 1) + iw_usage(); + if(index(args[i], 'G')) brate *= GIGA; + if(index(args[i], 'M')) brate *= MEGA; + if(index(args[i], 'k')) brate *= KILO; + wrq.u.bitrate.value = (long) brate; + } + wrq.u.bitrate.fixed = 1; + } + + if(ioctl(skfd, SIOCSIWRATE, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWRATE: %s\n", strerror(errno)); + return(-1); + } + continue; } - ifr = ifc.ifc_req; - for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + /* ---------- Set RTS threshold ---------- */ + if(!strncmp(args[i], "rts", 3)) { - if(get_info(ifr->ifr_name, &info) < 0) + i++; + if(i >= count) + iw_usage(); + if(!strcasecmp(args[i], "auto")) { - /* Could skip this message ? */ - fprintf(stderr, "%-8.8s no wireless extensions.\n\n", - ifr->ifr_name); - continue; + wrq.u.rts.value = -1; + wrq.u.rts.fixed = 0; + } + else + { + if(!strcasecmp(args[i], "fixed")) + { + /* Get old RTS threshold */ + if(ioctl(skfd, SIOCGIWRTS, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWRTS: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + } + else + if(!strcasecmp(args[i], "off")) + wrq.u.rts.value = -1; /* i.e. max size */ + else /* Should be a numeric value */ + if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.rts.value)) + != 1) + iw_usage(); + + wrq.u.rts.fixed = 1; } - print_info(&info); + if(ioctl(skfd, SIOCSIWRTS, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWRTS: %s\n", strerror(errno)); + return(-1); + } + continue; } - } - else - { - if(get_info(ifname, &info) < 0) + + /* ---------- Set fragmentation threshold ---------- */ + if(!strncmp(args[i], "frag", 4)) { - fprintf(stderr, "%s: no wireless extensions.\n", - ifname); - usage(); + i++; + if(i >= count) + iw_usage(); + if(!strcasecmp(args[i], "auto")) + { + wrq.u.frag.value = -1; + wrq.u.frag.fixed = 0; + } + else + { + if(!strcasecmp(args[i], "fixed")) + { + /* Get old fragmentation threshold */ + if(ioctl(skfd, SIOCGIWFRAG, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWFRAG: %s\n", strerror(errno)); + return(-1); + } + strcpy(wrq.ifr_name, ifname); + } + else + if(!strcasecmp(args[i], "off")) + wrq.u.frag.value = -1; /* i.e. max size */ + else /* Should be a numeric value */ + if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.frag.value)) + != 1) + iw_usage(); + + wrq.u.frag.fixed = 1; + } + + if(ioctl(skfd, SIOCSIWFRAG, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWFRAG: %s\n", strerror(errno)); + return(-1); + } + continue; } - else - print_info(&info); - } +#endif /* WIRELESS_EXT > 7 */ + + /* Here we have an unrecognised arg... */ + fprintf(stderr, "Invalid argument : %s\n", args[i]); + iw_usage(); + return(-1); + } /* for(index ... */ + return(0); } +/******************************* MAIN ********************************/ -static int sockets_open() -{ - inet_sock=socket(AF_INET, SOCK_DGRAM, 0); - ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0); - ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0); - ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0); - /* - * Now pick any (exisiting) useful socket family for generic queries - */ - if(inet_sock!=-1) - return inet_sock; - if(ipx_sock!=-1) - return ipx_sock; - if(ax25_sock!=-1) - return ax25_sock; - /* - * If this is -1 we have no known network layers and its time to jump. - */ - - return ddp_sock; -} - +/*------------------------------------------------------------------*/ +/* + * The main ! + */ int main(int argc, char ** argv) { + int skfd = -1; /* generic raw socket desc. */ int goterr = 0; /* Create a channel to the NET kernel. */ @@ -384,7 +877,16 @@ main(int argc, /* No argument : show the list of all device + info */ if(argc == 1) { - print_devices((char *)NULL); + print_devices(skfd); + close(skfd); + exit(0); + } + + /* Special case for help... */ + if((!strncmp(argv[1], "-h", 9)) || + (!strcmp(argv[1], "--help"))) + { + iw_usage(); close(skfd); exit(0); } @@ -392,16 +894,18 @@ main(int argc, /* The device name must be the first argument */ if(argc == 2) { - print_devices(argv[1]); + print_info(skfd, argv[1]); close(skfd); exit(0); } /* The other args on the line specify options to be set... */ - goterr = set_info(argv + 2, argc - 2, argv[1]); + goterr = set_info(skfd, argv + 2, argc - 2, argv[1]); /* Close the socket. */ close(skfd); return(goterr); } + + diff --git a/wireless_tools/iwpriv b/wireless_tools/iwpriv new file mode 100644 index 0000000..4657f67 Binary files /dev/null and b/wireless_tools/iwpriv differ diff --git a/wireless_tools/iwpriv.8 b/wireless_tools/iwpriv.8 new file mode 100644 index 0000000..8acc2e8 --- /dev/null +++ b/wireless_tools/iwpriv.8 @@ -0,0 +1,113 @@ +.\" Jean II - HPLB - 96 +.\" iwpriv.8 +.\" +.TH IWPRIV 8 "31 October 1996" "net-tools" "Linux Programmer's Manual" +.\" +.\" NAME part +.\" +.SH NAME +iwpriv \- configure optionals (private) parameters of a wireless +network interface +.\" +.\" SYNOPSIS part +.\" +.SH SYNOPSIS +.BI "iwpriv [" interface ] +.br +.BI "iwpriv " interface " " private-command " [" private-parameters ] +.br +.BI "iwpriv " interface " roam " {on,off} +.br +.BI "iwpriv " interface " port " [ N ] +.\" +.\" DESCRIPTION part +.\" +.SH DESCRIPTION +.B Iwpriv +is the companion tool to +.IR iwconfig (8). +.B Iwpriv +deals with parameters and setting specific to each driver (as opposed to +.I iwconfig +which deals with generic ones) and a few commands that doesn't fit well in +.I iwconfig +(like listing the available frequencies). +.PP +Without any argument, +.B iwpriv +list the available private commands available on each interface, and +the parameters that they require. Using this information, the user may +apply those interface specific commands on the specified interface. +.PP +In theory, the documentation of each device driver should indicate how +to use those interface specific commands and their effect. +.\" +.\" PARAMETER part +.\" +.SH PARAMETERS +.TP +.B roam +Enable or disable roaming, if supported. Call the private command +.IR setroam . +Found in the +.I wavelan_cs +driver. +.TP +.B port +Read or configure the port type. Call the private commands +.IR gport_type " and " sport_type . +Found in the +.IR wavelan2_cs " and " wvlan_cs " drivers." +.TP +.I private-command +Execute the specified +.I private-command +on the interface. The command may take or require arguments, and may +display information. Refer to the device driver documentation for +information on how to use and the effect. +.\" +.\" DISPLAY part +.\" +.SH DISPLAY +For each device which support private commands, +.I iwpriv +will display the list of private commands available. +.PP +This include the name of the private command, the number or arguments +that may be set and their type, and the number or arguments that may +be display and their type. +.PP +For example, you may have the following display : +.br +.B "eth0 Available private ioctl :" +.br +.B " setqualthr (89F0) : set 1 byte & get 0" +.br +.B " gethisto (89F7) : set 0 & get 16 int" +.PP +This indicate that you may set the quality threshold and display an +histogram of up to 16 values with the following commands : +.br +.I " iwpriv eth0 setqualthr 20" +.br +.I " iwpriv eth0 gethisto" +.\" +.\" AUTHOR part +.\" +.SH AUTHOR +Jean Tourrilhes \- jt@hplb.hpl.hp.com +.\" +.\" FILES part +.\" +.SH FILES +.I /proc/net/wireless +.\" +.\" SEE ALSO part +.\" +.SH SEE ALSO +.BR ifconfig (8), +.BR iwconfig (8), +.BR iwspy (8), +.BR wavelan (4), +.BR wavelan_cs (4), +.BR xircnw_cs (4). diff --git a/wireless_tools/iwpriv.c b/wireless_tools/iwpriv.c index 32034ba..3e22f4b 100644 --- a/wireless_tools/iwpriv.c +++ b/wireless_tools/iwpriv.c @@ -1,230 +1,524 @@ /* - * Warning : this program need wireless extensions... + * Wireless Tools + * + * Jean II - HPLB '99 + * + * Main code for "iwconfig". This is the generic tool for most + * manipulations... + * You need to link this code against "iwcommon.c" and "-lm". */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int skfd = -1; /* generic raw socket desc. */ -int ipx_sock = -1; /* IPX socket */ -int ax25_sock = -1; /* AX.25 socket */ -int inet_sock = -1; /* INET socket */ -int ddp_sock = -1; /* Appletalk DDP socket */ - -static int sockets_open() + +#include "iwcommon.h" /* Header */ + +/************************* MISC SUBROUTINES **************************/ + +/*------------------------------------------------------------------*/ +/* + * Print usage string + */ +static void +iw_usage(void) { - inet_sock=socket(AF_INET, SOCK_DGRAM, 0); - ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0); - ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0); - ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0); - /* - * Now pick any (exisiting) useful socket family for generic queries - */ - if(inet_sock!=-1) - return inet_sock; - if(ipx_sock!=-1) - return ipx_sock; - if(ax25_sock!=-1) - return ax25_sock; - /* - * If this is -1 we have no known network layers and its time to jump. - */ - - return ddp_sock; + fprintf(stderr, "Usage: iwpriv interface [private-command [private-arguments]]\n"); + fprintf(stderr, " interface [roam {on|off}]\n"); + fprintf(stderr, " interface [port [n]]\n"); + exit(1); } -int -byte_size(args) +/************************ GENERIC FUNCTIONS *************************/ + +/*------------------------------------------------------------------*/ +/* + * Print on the screen in a neat fashion all the info we have collected + * on a device. + */ +static void +print_priv_info(int skfd, + char * ifname) { - int ret = args & IW_PRIV_SIZE_MASK; + int k; + iwprivargs priv[16]; + int n; + char * argtype[] = { " ", "byte", "char", "", "int", "float" }; - if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) || - ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT)) - ret <<= 2; + /* Read the private ioctls */ + n = get_priv_info(skfd, ifname, priv); + + /* Is there any ? */ + if(n <= 0) + { + /* Could skip this message ? */ + fprintf(stderr, "%-8.8s no private ioctls.\n\n", + ifname); + } + else + { + printf("%-8.8s Available private ioctl :\n", ifname); + /* Print the all */ + for(k = 0; k < n; k++) + printf(" %s (%X) : set %3d %s & get %3d %s\n", + priv[k].name, priv[k].cmd, + priv[k].set_args & IW_PRIV_SIZE_MASK, + argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12], + priv[k].get_args & IW_PRIV_SIZE_MASK, + argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]); + printf("\n"); + } +} - if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE) - return 0; +/*------------------------------------------------------------------*/ +/* + * Get info on all devices and print it on the screen + */ +static void +print_priv_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; - return ret; + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_priv_info(skfd, ifr->ifr_name); } -int -main(int argc, - char ** argv) +/************************* SETTING ROUTINES **************************/ + +/*------------------------------------------------------------------*/ +/* + * Execute a private command on the interface + */ +static int +set_private(int skfd, /* Socket */ + char * args[], /* Command line args */ + int count, /* Args count */ + char * ifname) /* Dev name */ { + u_char buffer[1024]; struct iwreq wrq; - char * ifname = argv[1]; - struct iw_priv_args priv[16]; - int k; + int i = 0; /* Start with first arg */ + int k; + iwprivargs priv[16]; + int number; - if(argc < 2) - exit(0); + /* Read the private ioctls */ + number = get_priv_info(skfd, ifname, priv); - /* Create a channel to the NET kernel. */ - if((skfd = sockets_open()) < 0) + /* Is there any ? */ + if(number <= 0) { - perror("socket"); - exit(-1); + /* Could skip this message ? */ + fprintf(stderr, "%-8.8s no private ioctls.\n\n", + ifname); + return(-1); } - strncpy(wrq.ifr_name, ifname, IFNAMSIZ); - wrq.u.data.pointer = (caddr_t) priv; - wrq.u.data.length = 0; - wrq.u.data.flags = 0; - if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) + /* Search the correct ioctl */ + k = -1; + while((++k < number) && strcmp(priv[k].name, args[i])); + + /* If not found... */ + if(k == number) { - fprintf(stderr, "Interface doesn't provide private interface info...\n"); - fprintf(stderr, "SIOCGIWPRIV: %s\n", strerror(errno)); + fprintf(stderr, "Invalid command : %s\n", args[i]); return(-1); } + + /* Next arg */ + i++; - /* If no args... */ - if(argc < 3) + /* If we have to set some data */ + if((priv[k].set_args & IW_PRIV_TYPE_MASK) && + (priv[k].set_args & IW_PRIV_SIZE_MASK)) { - char * argtype[] = { " ", "byte", "char", "", "int", "float" }; + switch(priv[k].set_args & IW_PRIV_TYPE_MASK) + { + case IW_PRIV_TYPE_BYTE: + /* Number of args to fetch */ + wrq.u.data.length = count - 1; + if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK)) + wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK; + + /* Fetch args */ + for(; i < wrq.u.data.length + 1; i++) + sscanf(args[i], "%d", (int *)(buffer + i - 1)); + break; + + case IW_PRIV_TYPE_INT: + /* Number of args to fetch */ + wrq.u.data.length = count - 1; + if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK)) + wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK; + + /* Fetch args */ + for(; i < wrq.u.data.length + 1; i++) + sscanf(args[i], "%d", ((u_int *) buffer) + i - 1); + break; + + case IW_PRIV_TYPE_CHAR: + if(i < count) + { + /* Size of the string to fetch */ + wrq.u.data.length = strlen(args[i]) + 1; + if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK)) + wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK; - printf("Available private ioctl :\n"); - for(k = 0; k < wrq.u.data.length; k++) - printf("%s (%lX) : set %3d %s & get %3d %s\n", - priv[k].name, priv[k].cmd, - priv[k].set_args & IW_PRIV_SIZE_MASK, - argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12], - priv[k].get_args & IW_PRIV_SIZE_MASK, - argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]); + /* Fetch string */ + memcpy(buffer, args[i], wrq.u.data.length); + buffer[sizeof(buffer) - 1] = '\0'; + i++; + } + else + { + wrq.u.data.length = 1; + buffer[0] = '\0'; + } + break; + + default: + fprintf(stderr, "Not yet implemented...\n"); + return(-1); + } + + if((priv[k].set_args & IW_PRIV_SIZE_FIXED) && + (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK))) + { + printf("The command %s need exactly %d argument...\n", + priv[k].name, priv[k].set_args & IW_PRIV_SIZE_MASK); + return(-1); + } + } /* if args to set */ + else + { + wrq.u.data.length = 0L; } + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + if((priv[k].set_args & IW_PRIV_SIZE_FIXED) && + (byte_size(priv[k].set_args) < IFNAMSIZ)) + memcpy(wrq.u.name, buffer, IFNAMSIZ); else { - u_char buffer[1024]; + wrq.u.data.pointer = (caddr_t) buffer; + wrq.u.data.flags = 0; + } - /* Seach the correct ioctl */ - k = -1; - while((++k < wrq.u.data.length) && strcmp(priv[k].name, argv[2])) - ; - /* If not found... */ - if(k == wrq.u.data.length) - fprintf(stderr, "Invalid argument : %s\n", argv[2]); - - /* If we have to set some data */ - if((priv[k].set_args & IW_PRIV_TYPE_MASK) && - (priv[k].set_args & IW_PRIV_SIZE_MASK)) - { - int i; + /* Perform the private ioctl */ + if(ioctl(skfd, priv[k].cmd, &wrq) < 0) + { + fprintf(stderr, "Interface doesn't accept private ioctl...\n"); + fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno)); + return(-1); + } - /* Warning : we may have no args to set... */ + /* If we have to get some data */ + if((priv[k].get_args & IW_PRIV_TYPE_MASK) && + (priv[k].get_args & IW_PRIV_SIZE_MASK)) + { + int j; + int n = 0; /* number of args */ - switch(priv[k].set_args & IW_PRIV_TYPE_MASK) - { - case IW_PRIV_TYPE_BYTE: - /* Number of args to fetch */ - wrq.u.data.length = argc - 3; - if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK)) - wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK; + printf("%-8.8s %s:", ifname, priv[k].name); - /* Fetch args */ - for(i = 0; i < wrq.u.data.length; i++) - sscanf(argv[i + 3], "%d", buffer + i); - break; + if((priv[k].get_args & IW_PRIV_SIZE_FIXED) && + (byte_size(priv[k].get_args) < IFNAMSIZ)) + { + memcpy(buffer, wrq.u.name, IFNAMSIZ); + n = priv[k].get_args & IW_PRIV_SIZE_MASK; + } + else + n = wrq.u.data.length; - case IW_PRIV_TYPE_INT: - /* Number of args to fetch */ - wrq.u.data.length = argc - 3; - if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK)) - wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK; + switch(priv[k].get_args & IW_PRIV_TYPE_MASK) + { + case IW_PRIV_TYPE_BYTE: + /* Display args */ + for(j = 0; j < n; j++) + printf("%d ", buffer[j]); + printf("\n"); + break; + + case IW_PRIV_TYPE_INT: + /* Display args */ + for(j = 0; j < n; j++) + printf("%d ", ((u_int *) buffer)[i]); + printf("\n"); + break; + + case IW_PRIV_TYPE_CHAR: + /* Display args */ + buffer[wrq.u.data.length - 1] = '\0'; + printf("%s\n", buffer); + break; + + default: + fprintf(stderr, "Not yet implemented...\n"); + return(-1); + } + } /* if args to set */ - /* Fetch args */ - for(i = 0; i < wrq.u.data.length; i++) - sscanf(argv[i + 3], "%d", ((u_int *) buffer) + i); - break; + return(0); +} - default: - fprintf(stderr, "Not yet implemented...\n"); - return(-1); - } +/********************** PRIVATE IOCTLS MANIPS ***********************/ +/* + * Convenient access to some private ioctls of some devices + */ - if((priv[k].set_args & IW_PRIV_SIZE_FIXED) && - (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK))) - { - printf("The command %s need exactly %d argument...\n", - priv[k].name, priv[k].set_args & IW_PRIV_SIZE_MASK); - return(-1); - } - } /* if args to set */ - else +/*------------------------------------------------------------------*/ +/* + * Set roaming mode on and off + * Found in wavelan_cs driver + */ +static int +set_roaming(int skfd, /* Socket */ + char * args[], /* Command line args */ + int count, /* Args count */ + char * ifname) /* Dev name */ +{ + u_char buffer[1024]; + struct iwreq wrq; + int i = 0; /* Start with first arg */ + int k; + iwprivargs priv[16]; + int number; + char RoamState; /* buffer to hold new roam state */ + char ChangeRoamState=0; /* whether or not we are going to + change roam states */ + + /* Read the private ioctls */ + number = get_priv_info(skfd, ifname, priv); + + /* Is there any ? */ + if(number <= 0) + { + /* Could skip this message ? */ + fprintf(stderr, "%-8.8s no private ioctls.\n\n", + ifname); + return(-1); + } + + if(count != 1) + iw_usage(); + + if(!strcasecmp(args[i], "on")) + { + printf("%-8.8s enable roaming\n", ifname); + if(!number) { - wrq.u.data.length = 0L; + fprintf(stderr, "This device doesn't support roaming\n"); + return(-1); + } + ChangeRoamState=1; + RoamState=1; + } + else + if(!strcasecmp(args[i], "off")) + { + i++; + printf("%-8.8s disable roaming\n", ifname); + if(!number) + { + fprintf(stderr, "This device doesn't support roaming\n"); + return(-1); + } + ChangeRoamState=1; + RoamState=0; + } + else + { + iw_usage(); + return(-1); + } + + if(ChangeRoamState) + { + k = -1; + while((++k < number) && strcmp(priv[k].name, "setroam")); + if(k == number) + { + fprintf(stderr, "This device doesn't support roaming\n"); + return(-1); } - strncpy(wrq.ifr_name, ifname, IFNAMSIZ); - if((priv[k].set_args & IW_PRIV_SIZE_FIXED) && - (byte_size(priv[k].set_args) < IFNAMSIZ)) - memcpy(wrq.u.name, buffer, IFNAMSIZ); - else + buffer[0]=RoamState; + + memcpy(wrq.u.name, &buffer, IFNAMSIZ); + + if(ioctl(skfd, priv[k].cmd, &wrq) < 0) { - wrq.u.data.pointer = (caddr_t) buffer; - wrq.u.data.flags = 0; + fprintf(stderr, "Roaming support is broken.\n"); + exit(0); } + } + i++; - if(ioctl(skfd, priv[k].cmd, &wrq) < 0) + return(i); +} + +/*------------------------------------------------------------------*/ +/* + * Get and set the port type + * Found in wavelan2_cs and wvlan_cs drivers + */ +static int +port_type(int skfd, /* Socket */ + char * args[], /* Command line args */ + int count, /* Args count */ + char * ifname) /* Dev name */ +{ + struct iwreq wrq; + int i = 0; /* Start with first arg */ + int k; + iwprivargs priv[16]; + int number; + char ptype = 0; + + /* Read the private ioctls */ + number = get_priv_info(skfd, ifname, priv); + + /* Is there any ? */ + if(number <= 0) + { + /* Could skip this message ? */ + fprintf(stderr, "%-8.8s no private ioctls.\n\n", ifname); + return(-1); + } + + /* Arguments ? */ + if(count == 0) + { + /* So, we just want to see the current value... */ + k = -1; + while((++k < number) && strcmp(priv[k].name, "gport_type")); + if(k == number) { - fprintf(stderr, "Interface doesn't accept private ioctl...\n"); - fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno)); + fprintf(stderr, "This device doesn't support getting port type\n"); return(-1); } + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); - /* If we have to get some data */ - if((priv[k].get_args & IW_PRIV_TYPE_MASK) && - (priv[k].get_args & IW_PRIV_SIZE_MASK)) + /* Get it */ + if(ioctl(skfd, priv[k].cmd, &wrq) < 0) { - int i; - int n; /* number of args */ + fprintf(stderr, "Port type support is broken.\n"); + exit(0); + } + ptype = *wrq.u.name; - if((priv[k].get_args & IW_PRIV_SIZE_FIXED) && - (byte_size(priv[k].get_args) < IFNAMSIZ)) - { - memcpy(buffer, wrq.u.name, IFNAMSIZ); - n = priv[k].get_args & IW_PRIV_SIZE_MASK; - } - else - n = wrq.u.data.length; + /* Display it */ + printf("%-8.8s Port type is %d.\n\n", ifname, ptype); - switch(priv[k].get_args & IW_PRIV_TYPE_MASK) - { - case IW_PRIV_TYPE_BYTE: - /* Display args */ - for(i = 0; i < n; i++) - printf("%d ", buffer[i]); - printf("\n"); - break; - - case IW_PRIV_TYPE_INT: - /* Display args */ - for(i = 0; i < n; i++) - printf("%d ", ((u_int *) buffer)[i]); - printf("\n"); - break; - - default: - fprintf(stderr, "Not yet implemented...\n"); - return(-1); - } + return(0); + } + + if(count != 1) + iw_usage(); + + /* Read it */ + if(sscanf(args[i], "%d", (int *) &ptype) != 1) + iw_usage(); + + k = -1; + while((++k < number) && strcmp(priv[k].name, "sport_type")); + if(k == number) + { + fprintf(stderr, "This device doesn't support setting port type\n"); + return(-1); + } + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + *(wrq.u.name) = ptype; + + if(ioctl(skfd, priv[k].cmd, &wrq) < 0) + { + fprintf(stderr, "Invalid port type\n"); + exit(0); + } + + i++; + return(i); +} + +/******************************* MAIN ********************************/ + +/*------------------------------------------------------------------*/ +/* + * The main ! + */ +int +main(int argc, + char ** argv) +{ + int skfd = -1; /* generic raw socket desc. */ + int goterr = 0; + + /* Create a channel to the NET kernel. */ + if((skfd = sockets_open()) < 0) + { + perror("socket"); + exit(-1); + } + + /* No argument : show the list of all device + info */ + if(argc == 1) + { + print_priv_devices(skfd); + close(skfd); + exit(0); + } - } /* if args to set */ + /* Special cases take one... */ + /* Help */ + if((!strncmp(argv[1], "-h", 9)) || + (!strcmp(argv[1], "--help"))) + { + iw_usage(); + close(skfd); + exit(0); + } + + /* The device name must be the first argument */ + /* Name only : show for that device only */ + if(argc == 2) + { + print_priv_info(skfd, argv[1]); + close(skfd); + exit(0); + } + + /* Special cases take two... */ + /* Roaming */ + if(!strncmp(argv[2], "roam", 4)) + { + goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]); + close(skfd); + exit(0); + } + + /* Port type */ + if(!strncmp(argv[2], "port", 4)) + { + goterr = port_type(skfd, argv + 3, argc - 3, argv[1]); + close(skfd); + exit(0); + } - } /* if ioctl list else ioctl exec */ + /* Otherwise, it's a private ioctl */ + goterr = set_private(skfd, argv + 2, argc - 2, argv[1]); /* Close the socket. */ close(skfd); diff --git a/wireless_tools/iwspy b/wireless_tools/iwspy new file mode 100644 index 0000000..f857716 Binary files /dev/null and b/wireless_tools/iwspy differ diff --git a/wireless_tools/iwspy.8 b/wireless_tools/iwspy.8 index 099e227..0a4c243 100644 --- a/wireless_tools/iwspy.8 +++ b/wireless_tools/iwspy.8 @@ -13,9 +13,15 @@ iwspy \- Get wireless statistics from specific nodes .SH SYNOPSIS .BI "iwspy " interface .br -.BI "iwspy " interface " [+] " IPADDR " | hw " HWADDR " [...]" +.BI "iwspy " interface " [+] " IPADDR " | " HWADDR " [...]" .br .BI "iwspy " interface " off" +.br +.BI "iwspy " interface " freq" +.br +.BI "iwspy " interface " ap" +.br +.BI "iwspy " interface " rate" .\" .\" DESCRIPTION part .\" @@ -29,6 +35,10 @@ information is the same as the one available in .PP This information is updated each time a new packet is received, so each address of the list add some overhead in the driver. +.PP +.B Iwspy +Can also display the list of frequencies available for the device or the +list of Access Points in range. .\" .\" PARAMETER part .\" @@ -36,7 +46,8 @@ each address of the list add some overhead in the driver. You may set any number of addresses up to 8. .TP .B IPADDR -Set an IP address. As the hardware work with hardware addresses, +Set an IP address, or in some cases a domain name. As the hardware +work with hardware addresses, .B iwspy will translate this address through .IR ARP . @@ -46,9 +57,11 @@ will fail. In those case, .IR ping (8) this address and retry. .TP -.B hw HWADDR +.B HWADDR Set a hardware (MAC) address (this address is not translated & checked -like the IP one). +like the IP one). The address must contain a semicolon +.RB ( : ) +to be recognised as a hardware address. .TP .B + Add the new set of addresses at the end of the current list instead of @@ -56,7 +69,21 @@ replacing it. The address list is unique for each device, so each user should use this option to avoid conflicts. .TP .B off -Remove the current list of addresses and disable the functionality +Remove the current list of addresses and disable the spy functionality +.TP +.B freq +Give the list of available frequencies in the device and the number of +defined channels. Please note that usually the driver returns the +total number of channels and only the frequencies available in the +present locale, so there is no one to one mapping between frequencies +displayed and channel numbers. +.TP +.B ap +Give the list of Access Points in range, and optionally the quality of +link to them. +.TP +.BR rate / bit [ rate ] +List the bit-rates supported by the device. .\" .\" FILES part .\" diff --git a/wireless_tools/iwspy.c b/wireless_tools/iwspy.c index 3e66a86..dd2d604 100644 --- a/wireless_tools/iwspy.c +++ b/wireless_tools/iwspy.c @@ -1,114 +1,429 @@ /* - * Warning : this program need to be link against libsupport.a - * in net-tools-1.2.0 - * This program need also wireless extensions... + * Wireless Tools + * + * Jean II - HPLB '99 + * + * Main code for "iwconfig". This is the generic tool for most + * manipulations... + * You need to link this code against "iwcommon.c" and "-lm". */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "support.h" - -int skfd = -1; /* generic raw socket desc. */ -int ipx_sock = -1; /* IPX socket */ -int ax25_sock = -1; /* AX.25 socket */ -int inet_sock = -1; /* INET socket */ -int ddp_sock = -1; /* Appletalk DDP socket */ - -static int sockets_open() + +#include "iwcommon.h" /* Header */ + +/************************* DISPLAY ROUTINES **************************/ + +/*------------------------------------------------------------------*/ +/* + * Display the spy list of addresses and the associated stats + */ +static void +print_spy_info(int skfd, + char * ifname) { - inet_sock=socket(AF_INET, SOCK_DGRAM, 0); - ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0); - ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0); - ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0); - /* - * Now pick any (exisiting) useful socket family for generic queries - */ - if(inet_sock!=-1) - return inet_sock; - if(ipx_sock!=-1) - return ipx_sock; - if(ax25_sock!=-1) - return ax25_sock; - /* - * If this is -1 we have no known network layers and its time to jump. - */ - - return ddp_sock; + struct iwreq wrq; + char buffer[(sizeof(struct iw_quality) + + sizeof(struct sockaddr)) * IW_MAX_SPY]; + struct sockaddr hwa[IW_MAX_SPY]; + struct iw_quality qual[IW_MAX_SPY]; + iwrange range; + int has_range = 0; + int n; + int i; + + /* Collect stats */ + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) buffer; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0) + { + fprintf(stderr, "%-8.8s Interface doesn't support wireless statistic collection\n\n", ifname); + return; + } + + /* Number of addresses */ + n = wrq.u.data.length; + + + + /* Check if we have valid address types */ + if(check_addr_type(skfd, ifname) < 0) + { + fprintf(stderr, "%-8.8s Interface doesn't support MAC & IP addresses\n\n", ifname); + return; + } + + /* Get range info if we can */ + if(get_range_info(skfd, ifname, &(range)) >= 0) + has_range = 1; + + /* Display it */ + if(n == 0) + printf("%-8.8s No statistics to collect\n", ifname); + else + printf("%-8.8s Statistics collected:\n", ifname); + + /* The two lists */ + + memcpy(hwa, buffer, n * sizeof(struct sockaddr)); + memcpy(qual, buffer + n*sizeof(struct sockaddr), n*sizeof(struct iw_quality)); + + for(i = 0; i < n; i++) + { + if(has_range && (qual[i].level != 0)) + /* If the statistics are in dBm */ + if(qual[i].level > range.max_qual.level) + printf(" %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, range.max_qual.qual, + qual[i].level - 0x100, qual[i].noise - 0x100, + qual[i].updated & 0x7 ? "(updated)" : ""); + else + printf(" %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, range.max_qual.qual, + qual[i].level, range.max_qual.level, + qual[i].noise, range.max_qual.noise, + qual[i].updated & 0x7 ? "(updated)" : ""); + else + printf(" %s : Quality %d ; Signal %d ; Noise %d %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, qual[i].level, qual[i].noise, + qual[i].updated & 0x7 ? "(updated)" : ""); + } + printf("\n"); } -int -main(int argc, - char ** argv) +/*------------------------------------------------------------------*/ +/* + * Get info on all devices and print it on the screen + */ +static void +print_spy_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; + + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_spy_info(skfd, ifr->ifr_name); +} + +/*------------------------------------------------------------------*/ +/* + * Print the number of channels and available frequency for the device + */ +static void +print_freq_info(int skfd, + char * ifname) { - struct ifreq ifr; struct iwreq wrq; - struct aftype *ap; - struct hwtype *hw; - char * ifname = argv[1]; + float freq; + struct iw_range range; + int k; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) + fprintf(stderr, "%-8.8s no frequency information.\n\n", + ifname); + else + { + if(range.num_frequency > 0) + { + printf("%-8.8s %d channels in total; available frequencies :\n", + ifname, range.num_channels); + /* Print them all */ + for(k = 0; k < range.num_frequency; k++) + { +#if WIRELESS_EXT > 7 + printf("\t Channel %.2d : ", range.freq[k].i); +#else + printf("\t "); +#endif + freq = freq2float(&(range.freq[k])); + if(freq >= GIGA) + printf("%g GHz\n", freq / GIGA); + else + if(freq >= MEGA) + printf("%g MHz\n", freq / MEGA); + else + printf("%g kHz\n", freq / KILO); + } + printf("\n\n"); + } + else + printf("%-8.8s %d channels\n\n", + ifname, range.num_channels); + } +} - if(argc < 2) - exit(0); +/*------------------------------------------------------------------*/ +/* + * Get frequency info on all devices and print it on the screen + */ +static void +print_freq_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; - /* Create a channel to the NET kernel. */ - if((skfd = sockets_open()) < 0) + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_freq_info(skfd, ifr->ifr_name); +} + +#if WIRELESS_EXT > 5 +/*------------------------------------------------------------------*/ +/* + * Display the list of ap addresses and the associated stats + * Exacly the same as the spy list, only with different IOCTL and messages + */ +static void +print_ap_info(int skfd, + char * ifname) +{ + struct iwreq wrq; + char buffer[(sizeof(struct iw_quality) + + sizeof(struct sockaddr)) * IW_MAX_AP]; + struct sockaddr * hwa; + struct iw_quality * qual; + iwrange range; + int has_range = 0; + int has_qual = 0; + int n; + int i; + + /* Collect stats */ + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) buffer; + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWAPLIST, &wrq) < 0) { - perror("socket"); - exit(-1); + fprintf(stderr, "%-8.8s Interface doesn't have a list of Access Points\n\n", ifname); + return; } - /* Get the type of interface address */ - strcpy(ifr.ifr_name, ifname); - if((ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0) || - ((ap = get_afntype(ifr.ifr_addr.sa_family)) == NULL)) + /* Number of addresses */ + n = wrq.u.data.length; + has_qual = wrq.u.data.flags; + + /* The two lists */ + hwa = (struct sockaddr *) buffer; + qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n)); + + /* Check if we have valid address types */ + if(check_addr_type(skfd, ifname) < 0) { - /* Deep trouble... */ - fprintf(stderr, "Interface %s unavailable\n", ifname); - exit(0); + fprintf(stderr, "%-8.8s Interface doesn't support MAC & IP addresses\n\n", ifname); + return; } -#ifdef DEBUG - printf("Interface : %d - %s - %s\n", ifr.ifr_addr.sa_family, - ap->name, ap->sprint(&ifr.ifr_addr, 1)); -#endif + /* Get range info if we can */ + if(get_range_info(skfd, ifname, &(range)) >= 0) + has_range = 1; - /* Get the type of hardware address */ - strcpy(ifr.ifr_name, ifname); - if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) || - ((hw = get_hwntype(ifr.ifr_hwaddr.sa_family)) == NULL)) + /* Display it */ + if(n == 0) + printf("%-8.8s No Access Point in range\n", ifname); + else + printf("%-8.8s Access Points in range:\n", ifname); + for(i = 0; i < n; i++) { - /* Deep trouble... */ - fprintf(stderr, "Unable to get hardware address of the interface %s\n", - ifname); - exit(0); + if(has_qual) + if(has_range) + /* If the statistics are in dBm */ + if(qual[i].level > range.max_qual.level) + printf(" %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, range.max_qual.qual, + qual[i].level - 0x100, qual[i].noise - 0x100, + qual[i].updated & 0x7 ? "(updated)" : ""); + else + printf(" %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, range.max_qual.qual, + qual[i].level, range.max_qual.level, + qual[i].noise, range.max_qual.noise, + qual[i].updated & 0x7 ? "(updated)" : ""); + else + printf(" %s : Quality %d ; Signal %d ; Noise %d %s\n", + pr_ether(hwa[i].sa_data), + qual[i].qual, qual[i].level, qual[i].noise, + qual[i].updated & 0x7 ? "(updated)" : ""); + else + printf(" %s\n", pr_ether(hwa[i].sa_data)); } + printf("\n"); +} -#ifdef DEBUG - printf("Hardware : %d - %s - %s\n", ifr.ifr_hwaddr.sa_family, - hw->name, hw->print(ifr.ifr_hwaddr.sa_data)); -#endif +/*------------------------------------------------------------------*/ +/* + * Get list of AP on all devices and print it on the screen + */ +static void +print_ap_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; + + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_ap_info(skfd, ifr->ifr_name); +} +#endif /* WIRELESS_EXT > 5 */ - /* Is there any arguments ? */ - if(argc < 3) - { /* Nope : read out from kernel */ - char buffer[(sizeof(struct iw_quality) + - sizeof(struct sockaddr)) * IW_MAX_SPY]; - struct sockaddr * hwa; - struct iw_quality *qual; - int n; - int i; +#if WIRELESS_EXT > 7 +/*------------------------------------------------------------------*/ +/* + * Print the number of available bitrates for the device + */ +static void +print_bitrate_info(int skfd, + char * ifname) +{ + struct iwreq wrq; + float bitrate; + struct iw_range range; + int k; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) + fprintf(stderr, "%-8.8s no bit-rate information.\n\n", + ifname); + else + { + if((range.num_bitrates > 0) && (range.num_bitrates < IW_MAX_BITRATES)) + { + printf("%-8.8s %d available bit-rates :\n", + ifname, range.num_bitrates); + /* Print them all */ + for(k = 0; k < range.num_bitrates; k++) + { + printf("\t "); + bitrate = range.bitrate[k]; + if(bitrate >= GIGA) + printf("%g Gb/s\n", bitrate / GIGA); + else + if(bitrate >= MEGA) + printf("%g Mb/s\n", bitrate / MEGA); + else + printf("%g kb/s\n", bitrate / KILO); + } + printf("\n\n"); + } + else + printf("%-8.8s No bit-rates ? Please update driver...\n\n", ifname); + } +} + +/*------------------------------------------------------------------*/ +/* + * Get bit-rate info on all devices and print it on the screen + */ +static void +print_bitrate_devices(int skfd) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + /* Get list of active devices */ + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + ifr = ifc.ifc_req; + + /* Print them */ + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + print_bitrate_info(skfd, ifr->ifr_name); +} +#endif /* WIRELESS_EXT > 7 */ + +/************************* SETTING ROUTINES **************************/ + +/*------------------------------------------------------------------*/ +/* + * Set list of addresses specified on command line in the driver. + */ +static int +set_spy_info(int skfd, /* The socket */ + char * args[], /* Command line args */ + int count, /* Args count */ + char * ifname) /* Dev name */ +{ + struct iwreq wrq; + int i; + int nbr; /* Number of valid addresses */ + struct sockaddr hw_address[IW_MAX_SPY]; + + /* Read command line */ + i = 0; /* first arg to read */ + nbr = 0; /* Number of args readen so far */ + + /* Check if we have valid address types */ + if(check_addr_type(skfd, ifname) < 0) + { + fprintf(stderr, "%-8.8s Interface doesn't support MAC & IP addresses\n", ifname); + return(-1); + } + + /* "off" : disable functionality (set 0 addresses) */ + if(!strcmp(args[0], "off")) + i = count; /* hack */ + + /* "+" : add all addresses already in the driver */ + if(!strcmp(args[0], "+")) + { + char buffer[(sizeof(struct iw_quality) + + sizeof(struct sockaddr)) * IW_MAX_SPY]; strncpy(wrq.ifr_name, ifname, IFNAMSIZ); wrq.u.data.pointer = (caddr_t) buffer; @@ -121,147 +436,162 @@ main(int argc, return(-1); } - n = wrq.u.data.length; + /* Copy old addresses */ + nbr = wrq.u.data.length; + memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr)); - hwa = (struct sockaddr *) buffer; - qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n)); + i = 1; /* skip the "+" */ + } - for(i = 0; i < n; i++) - printf("%s : Quality %d ; Signal %d ; Noise %d %s\n", - hw->print(hwa[i].sa_data), - qual[i].qual, qual[i].level, qual[i].noise, - qual[i].updated & 0x7 ? "(updated)" : ""); + /* Read other args on command line */ + while((i < count) && (nbr < IW_MAX_SPY)) + { + if(in_addr(skfd, ifname, args[i++], &(hw_address[nbr])) < 0) + continue; + nbr++; } - else - { /* Send addresses to kernel */ - int i; - int nbr; /* Number of valid addresses */ - struct sockaddr hw_address[IW_MAX_SPY]; - struct sockaddr if_address; - struct arpreq arp_query; - - /* Read command line */ - i = 2; /* first arg to read */ - nbr = 0; /* Number of args readen so far */ - - /* "off" : disable functionality (set 0 addresses) */ - if(!strcmp(argv[2], "off")) - i = argc; /* hack */ - - /* "+" : add all addresses already in the driver */ - if(!strcmp(argv[2], "+")) - { - char buffer[(sizeof(struct iw_quality) + - sizeof(struct sockaddr)) * IW_MAX_SPY]; - - strncpy(wrq.ifr_name, ifname, IFNAMSIZ); - wrq.u.data.pointer = (caddr_t) buffer; - wrq.u.data.length = 0; - wrq.u.data.flags = 0; - if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0) - { - fprintf(stderr, "Interface doesn't accept reading addresses...\n"); - fprintf(stderr, "SIOCGIWSPY: %s\n", strerror(errno)); - return(-1); - } - /* Copy old addresses */ - nbr = wrq.u.data.length; - memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr)); + /* Check the number of addresses */ + if((nbr == 0) && strcmp(args[0], "off")) + { + fprintf(stderr, "No valid addresses found : exiting...\n"); + exit(0); + } - i = 3; /* skip the "+" */ - } + /* Check if there is some remaining arguments */ + if(i < count) + { + fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY); + } - /* Read other args on command line */ - while((i < argc) && (nbr < IW_MAX_SPY)) - { - /* If it is not a hardware address (prefixed by hw)... */ - if(strcmp(argv[i], "hw")) - { - /* Read interface address */ - if(ap->input(argv[i++], &if_address) < 0) - { - fprintf(stderr, "Invalid interface address %s\n", argv[i - 1]); - continue; - } - - /* Translate IP addresses to MAC addresses */ - memcpy((char *) &(arp_query.arp_pa), - (char *) &if_address, - sizeof(struct sockaddr)); - arp_query.arp_ha.sa_family = 0; - arp_query.arp_flags = 0; - /* The following restrict the search to the interface only */ - strcpy(arp_query.arp_dev, ifname); - if((ioctl(inet_sock, SIOCGARP, &arp_query) < 0) || - !(arp_query.arp_flags & ATF_COM)) - { - fprintf(stderr, "Arp failed for %s... (%d) Try to ping the address before.\n", - ap->sprint(&if_address, 1), errno); - continue; - } - - /* Store new MAC address */ - memcpy((char *) &(hw_address[nbr++]), - (char *) &(arp_query.arp_ha), - sizeof(struct sockaddr)); - -#ifdef DEBUG - printf("IP Address %s => Hw Address = %s - %d\n", - ap->sprint(&if_address, 1), - hw->print(hw_address[nbr - 1].sa_data)); -#endif - } - else /* If it's an hardware address */ - { - if(++i >= argc) - { - fprintf(stderr, "hw must be followed by an address...\n"); - continue; - } - - /* Get the hardware address */ - if(hw->input(argv[i++], &(hw_address[nbr])) < 0) - { - fprintf(stderr, "Invalid hardware address %s\n", argv[i - 1]); - continue; - } - nbr++; - -#ifdef DEBUG - printf("Hw Address = %s - %d\n", - hw->print(hw_address[nbr - 1].sa_data)); -#endif - } - } /* Loop on all addresses */ + /* Time to do send addresses to the driver */ + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) hw_address; + wrq.u.data.length = nbr; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCSIWSPY, &wrq) < 0) + { + fprintf(stderr, "Interface doesn't accept addresses...\n"); + fprintf(stderr, "SIOCSIWSPY: %s\n", strerror(errno)); + return(-1); + } + return(0); +} - /* Check the number of addresses */ - if((nbr == 0) && strcmp(argv[2], "off")) - { - fprintf(stderr, "No valid addresses found : exiting...\n"); - exit(0); - } +/******************************* MAIN ********************************/ - /* Check if there is some remaining arguments */ - if(i < argc) - { - fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY); - } +/*------------------------------------------------------------------*/ +/* + * The main ! + */ +int +main(int argc, + char ** argv) +{ + int skfd = -1; /* generic raw socket desc. */ + int goterr = 0; - /* Time to do send addresses to the driver */ - strncpy(wrq.ifr_name, ifname, IFNAMSIZ); - wrq.u.data.pointer = (caddr_t) hw_address; - wrq.u.data.length = nbr; - wrq.u.data.flags = 0; - if(ioctl(skfd, SIOCSIWSPY, &wrq) < 0) - { - fprintf(stderr, "Interface doesn't accept addresses...\n"); - fprintf(stderr, "SIOCSIWSPY: %s\n", strerror(errno)); - return(-1); - } + /* Create a channel to the NET kernel. */ + if((skfd = sockets_open()) < 0) + { + perror("socket"); + exit(-1); + } + + /* No argument : show the list of all device + info */ + if(argc == 1) + { + print_spy_devices(skfd); + close(skfd); + exit(0); + } + + /* Special cases take one... */ + /* Help */ + if((!strncmp(argv[1], "-h", 9)) || + (!strcmp(argv[1], "--help"))) + { + fprintf(stderr, "Usage: iwspy interface [+] [MAC address] [IP address]\n"); + fprintf(stderr, " interface [freq]\n"); + fprintf(stderr, " interface [ap]\n"); + close(skfd); + exit(0); } + /* Frequency list */ + if((!strncmp(argv[1], "freq", 4)) || + (!strncmp(argv[1], "channel", 7))) + { + print_freq_devices(skfd); + close(skfd); + exit(0); + } + +#if WIRELESS_EXT > 5 + /* Access Point list */ + if(!strcasecmp(argv[1], "ap")) + { + print_ap_devices(skfd); + close(skfd); + exit(0); + } +#endif /* WIRELESS_EXT > 5 */ + +#if WIRELESS_EXT > 7 + /* Bit-rate list */ + if((!strncmp(argv[1], "bit", 3)) || + (!strcmp(argv[1], "rate"))) + { + print_bitrate_devices(skfd); + close(skfd); + exit(0); + } +#endif /* WIRELESS_EXT > 7 */ + + /* The device name must be the first argument */ + /* Name only : show spy list for that device only */ + if(argc == 2) + { + print_spy_info(skfd, argv[1]); + close(skfd); + exit(0); + } + + /* Special cases take two... */ + /* Frequency list */ + if((!strncmp(argv[2], "freq", 4)) || + (!strncmp(argv[2], "channel", 7))) + { + print_freq_info(skfd, argv[1]); + close(skfd); + exit(0); + } + +#if WIRELESS_EXT > 5 + /* Access Point list */ + if(!strcasecmp(argv[2], "ap")) + { + print_ap_info(skfd, argv[1]); + close(skfd); + exit(0); + } +#endif /* WIRELESS_EXT > 5 */ + +#if WIRELESS_EXT > 7 + /* Access Point list */ + if((!strncmp(argv[2], "bit", 3)) || + (!strcmp(argv[2], "rate"))) + { + print_bitrate_info(skfd, argv[1]); + close(skfd); + exit(0); + } +#endif /* WIRELESS_EXT > 7 */ + + /* Otherwise, it's a list of address to set in the spy list */ + goterr = set_spy_info(skfd, argv + 2, argc - 2, argv[1]); + /* Close the socket. */ close(skfd); diff --git a/wireless_tools/wireless.h b/wireless_tools/wireless.h new file mode 100644 index 0000000..0be1d51 --- /dev/null +++ b/wireless_tools/wireless.h @@ -0,0 +1,347 @@ +/* + * This file define a set of standard wireless extensions + * + * Version : 7 23.4.99 + * + * Authors : Jean Tourrilhes - HPLB - + */ + +#ifndef _LINUX_WIRELESS_H +#define _LINUX_WIRELESS_H + +/************************** DOCUMENTATION **************************/ +/* + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * + * The entry /proc/net/wireless give statistics and information on the + * driver. + * This is better than having each driver having its entry because + * its centralised and we may remove the driver module safely. + * + * Ioctl are used to configure the driver and issue commands. This is + * better than command line options of insmod because we may want to + * change dynamically (while the driver is running) some parameters. + * + * The ioctl mechanimsm are copied from standard devices ioctl. + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : + * net/core/dev.c (two place + add include) + * net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : + * net/core/dev.c (two other places) + * include/linux/netdevice.h (one place) + * include/linux/proc_fs.h (one place) + * + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. + * + * These wireless extensions are not magic : each driver has to provide + * support for them... + * + * IMPORTANT NOTE : As everything in the kernel, this is very much a + * work in progress. Contact me if you have ideas of improvements... + */ + +/***************************** INCLUDES *****************************/ + +#if 0 +#include /* for "caddr_t" et al */ +#include /* for "struct sockaddr" et al */ +#include /* for IFNAMSIZ and co... */ +#endif + +/**************************** CONSTANTS ****************************/ + +/* --------------------------- VERSION --------------------------- */ +/* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +#define WIRELESS_EXT 6 + +/* + * Changes : + * + * V2 to V3 + * -------- + * Alan Cox start some incompatibles changes. I've integrated a bit more. + * - Encryption renamed to Encode to avoid US regulation problems + * - Frequency changed from float to struct to avoid problems on old 386 + * + * V3 to V4 + * -------- + * - Add sensitivity + * + * V4 to V5 + * -------- + * - Missing encoding definitions in range + * - Access points stuff + * + * V5 to V6 + * -------- + * - 802.11 support (ESSID ioctls) + * + * V6 to V7 + * -------- + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP + */ + +/* -------------------------- IOCTL LIST -------------------------- */ + +/* Basic operations */ +#define SIOCSIWNAME 0x8B00 /* Unused ??? */ +#define SIOCGIWNAME 0x8B01 /* get name */ +#define SIOCSIWNWID 0x8B02 /* set network id */ +#define SIOCGIWNWID 0x8B03 /* get network id */ +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency */ +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency */ +#define SIOCSIWENCODE 0x8B06 /* set encoding info */ +#define SIOCGIWENCODE 0x8B07 /* get encoding info */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity */ + +/* Informative stuff */ +#define SIOCSIWRANGE 0x8B0A /* Unused ??? */ +#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ +#define SIOCSIWPRIV 0x8B0C /* Unused ??? */ +#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ + +/* Mobile IP support */ +#define SIOCSIWSPY 0x8B10 /* set spy addresses */ +#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + +/* Access Point manipulation */ +#define SIOCSIWAP 0x8B14 /* set access point hardware addresses */ +#define SIOCGIWAP 0x8B15 /* get access point hardware addresses */ +#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ + +/* 802.11 specific support */ +#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +#define SIOCGIWESSID 0x8B1B /* get ESSID */ +/* As the ESSID is a string up to 32 bytes long, it doesn't fit within the + * 'iwreq' structure, so we need to use the 'data' member to point to a + * string in user space, like it is done for RANGE... + * The "flags" member indicate if the ESSID is active or not. + */ + +/* ------------------------- IOCTL STUFF ------------------------- */ + +/* The first and the last (range) */ +#define SIOCIWFIRST 0x8B00 +#define SIOCIWLAST 0x8B1B + +/* Even : get (world access), odd : set (root access) */ +#define IW_IS_SET(cmd) (!((cmd) & 0x1)) +#define IW_IS_GET(cmd) ((cmd) & 0x1) + +/* ------------------------- PRIVATE INFO ------------------------- */ +/* + * The following is used with SIOCGIWPRIV. It allow a driver to define + * the interface (name, type of data) for its private ioctl. + * Privates ioctl are SIOCDEVPRIVATE -> SIOCDEVPRIVATE + 0xF + */ + +#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ +#define IW_PRIV_TYPE_NONE 0x0000 +#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ +#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ +#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +#define IW_PRIV_TYPE_FLOAT 0x5000 + +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ + +/* + * Note : if the number of args is fixed and the size < 16 octets, + * instead of passing a pointer we will put args in the iwreq struct... + */ + +/* ----------------------- OTHER CONSTANTS ----------------------- */ + +/* Maximum frequencies in the range struct */ +#define IW_MAX_FREQUENCIES 16 +/* Note : if you have something like 80 frequencies, + * don't increase this constant and don't fill the frequency list. + * The user will be able to set by channel anyway... */ + +/* Maximum of address that you may set with SPY */ +#define IW_MAX_SPY 8 + +/* Maximum of address that you may get in the + list of access points in range */ +#define IW_MAX_AP 8 + +/* Maximum size of the ESSID string */ +#define IW_ESSID_MAX_SIZE 32 + +/****************************** TYPES ******************************/ + +/* --------------------------- SUBTYPES --------------------------- */ +/* + * A frequency + * For numbers lower than 10^9, we encode the number in 'mant' and + * set 'exp' to 0 + * For number greater than 10^9, we divide it by a power of 10. + * The power of 10 is in 'exp', the result is in 'mant'. + */ +struct iw_freq +{ + __u32 m; /* Mantissa */ + __u16 e; /* Exponent */ +}; + +/* + * Quality of the link + */ +struct iw_quality +{ + __u8 qual; /* link quality (SNR or better...) */ + __u8 level; /* signal level */ + __u8 noise; /* noise level */ + __u8 updated; /* Flags to know if updated */ +}; + +/* + * Packet discarded in the wireless adapter due to + * "wireless" specific problems... + */ +struct iw_discarded +{ + __u32 nwid; /* Wrong nwid */ + __u32 code; /* Unable to code/decode */ + __u32 misc; /* Others cases */ +}; + +/* + * Encoding information (setting and so on) + * Encoding might be hardware encryption, scrambing or others + */ +struct iw_encoding +{ + __u8 method; /* Algorithm number / key used */ + __u64 code; /* Data/key used for algorithm */ +}; + + +/* ------------------------ WIRELESS STATS ------------------------ */ +/* + * Wireless statistics (used for /proc/net/wireless) + */ +struct iw_statistics +{ + __u8 status; /* Status + * - device dependent for now */ + + struct iw_quality qual; /* Quality of the link + * (instant/mean/max) */ + struct iw_discarded discard; /* Packet discarded counts */ +}; + +/* ------------------------ IOCTL REQUEST ------------------------ */ +/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... + * + * Note that it should fit on the same memory footprint ! + * You should check this when increasing the above structures (16 octets) + * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... + */ +struct iwreq +{ + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + /* Data part */ + union + { + /* Config - generic */ + char name[IFNAMSIZ]; + /* Name : used to verify the presence of wireless extensions. + * Name of the protocol/provider... */ + + struct /* network id (or domain) : used to to */ + { /* create logical channels on the air */ + __u32 nwid; /* value */ + __u8 on; /* active/unactive nwid */ + } nwid; + + struct iw_freq freq; /* frequency or channel : + * 0-1000 = channel + * > 1000 = frequency in Hz */ + + struct iw_encoding encoding; /* Encoding stuff */ + + __u32 sensitivity; /* signal level threshold */ + + struct sockaddr ap_addr; /* Access point address */ + + struct /* For all data bigger than 16 octets */ + { + caddr_t pointer; /* Pointer to the data + * (in user space) */ + __u16 length; /* fields or byte size */ + __u16 flags; /* Optional params */ + } data; + } u; +}; + +/* -------------------------- IOCTL DATA -------------------------- */ +/* + * For those ioctl which want to exchange mode data that what could + * fit in the above structure... + */ + +/* + * Range of parameters + */ + +struct iw_range +{ + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Frequency */ + __u16 num_channels; /* Number of channels [0; num - 1] */ + __u8 num_frequency; /* Number of entry in the list */ + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ + /* Note : this frequency list doesn't need to fit channel numbers */ + + /* signal level threshold range */ + __u32 sensitivity; + + /* Quality of link & SNR stuff */ + struct iw_quality max_qual; /* Quality of the link */ + + /* Encoder stuff */ + struct iw_encoding max_encoding; /* Encoding max range */ +}; + +/* + * Private ioctl interface information + */ + +struct iw_priv_args +{ + __u32 cmd; /* Number of the ioctl to issue */ + __u16 set_args; /* Type and number of args */ + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ +}; + +#endif /* _LINUX_WIRELESS_H */ diff --git a/wireless_tools/xwireless.c b/wireless_tools/xwireless.c new file mode 100644 index 0000000..dca0d48 --- /dev/null +++ b/wireless_tools/xwireless.c @@ -0,0 +1,241 @@ +/* Xwireless.c, status: experimental, do not distribute!! */ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +char* status[] = { "Scanning","Registering","Best AP","Good AP", + "Poor AP","Active Beacon Search","Static Load Balance", + "Balance Search" }; + +typedef struct privateData { + char *ifname; + Pixel currentColor; + Pixel highColor; + Pixel lowColor; + Pixel criticalColor; + Pixel foreground; + int highValue; + int lowValue; + int delay; + String geometry; + struct iw_statistics stats; + struct iw_range range; +} privateData; + +static XtAppContext app_context; +static Widget scrollbar; +static Widget topLevel; +static Widget label; +static XtIntervalId timerId; +static privateData priv; + +static int getstats(char *ifname, struct iw_statistics *stats) +{ + struct iwreq wrq; + FILE *f=fopen("/proc/net/wireless","r"); + char buf[256]; + char *bp; + if(f==NULL) + return -1; + while(fgets(buf,255,f)) + { + bp=buf; + while(*bp&&isspace(*bp)) + bp++; + if( strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':') { + bp=strchr(bp,':'); + bp++; + bp = strtok(bp, " ."); + sscanf(bp, "%X", &stats->status); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->qual.qual); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->qual.level); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->qual.noise); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->discard.nwid); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->discard.code); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->discard.misc); + fclose(f); + return 0; + } else { + stats->status = -1; + stats->qual.qual = 0; + stats->qual.level = 0; + stats->qual.noise = 0; + } + } + fclose(f); + + /*strcpy(wrq.ifr_name, ifname); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0) { + info->has_range = 1; + }*/ + + return 0; +} + +static void update( XtPointer client_data, XtIntervalId *id ) +{ + char buf[128]; + static int pixel = -1; + static int lpixel = -1; + static int bpixel = -1; + + getstats( priv.ifname, &(priv.stats)); + + if(status < 8) + sprintf( buf, "%s", status[priv.stats.status] ); + else + sprintf( buf, "%s", "buggy" ); + XtVaSetValues( label, XtNlabel, buf, NULL ); + + if (priv.stats.qual.qual <= priv.lowValue) { + if (pixel != priv.criticalColor) + XtVaSetValues( scrollbar, XtNforeground, + pixel = priv.criticalColor, NULL ); + if (bpixel != priv.criticalColor) + XtVaSetValues( scrollbar, XtNborderColor, + bpixel = priv.criticalColor, NULL ); + } else if (priv.stats.qual.qual <= priv.highValue) { + if (pixel != priv.lowColor) + XtVaSetValues( scrollbar, + XtNforeground, pixel = priv.lowColor, NULL ); + if (bpixel != priv.foreground) + XtVaSetValues( scrollbar, XtNborderColor, + bpixel = priv.foreground, NULL ); + } else { + if (pixel != priv.highColor ) + XtVaSetValues( scrollbar, + XtNforeground, pixel = priv.highColor, NULL ); + } + + XawScrollbarSetThumb( scrollbar, 0.0, priv.stats.qual.qual / 255.0 ); + + timerId = XtAppAddTimeOut( app_context, 1000 , update, app_context ); +} + +#define offset(field) XtOffsetOf( privateData, field ) +static XtResource resources[] = { + { "highColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(highColor), XtRString, "green" }, + { "lowColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(lowColor), XtRString, "orange" }, + { "criticalColor", XtCForeground, XtRPixel, sizeof(Pixel), + offset(criticalColor), XtRString, "red" }, + { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), + offset(foreground), XtRString, XtDefaultForeground }, + { "highValue", XtCValue, XtRInt, sizeof(int), + offset(highValue), XtRImmediate, (XtPointer)50 }, + { "lowValue", XtCValue, XtRInt, sizeof(int), + offset(lowValue), XtRImmediate, (XtPointer)10 }, + { "geometry", XtCString, XtRString, sizeof( String ), + offset(geometry), XtRString, (XtPointer)"10x100" }, + { "delay", XtCValue, XtRInt, sizeof(int), + offset(delay), XtRImmediate, (XtPointer)1 }, +}; + +int main( int argc, char **argv ) { + Cursor cursor; + int c; + Widget form; + XFontStruct *fs; + int fontWidth, fontHeight; + int width = 120; + + /* The device name must be the first argument */ + if(argc < 2) { + printf("Hmm\n"); + } + priv.ifname = argv[1]; + + if( priv.ifname == (char *) NULL) { + printf("Usage: xwireless \n"); + exit(-1); + } + + topLevel = XtVaAppInitialize( &app_context, "Xwireless", + NULL, 0, + &argc, argv, NULL, NULL ); + + XtGetApplicationResources( topLevel, + &priv, + resources, + XtNumber( resources ), + NULL, 0 ); + priv.lowValue = 85; + priv.highValue = 170; + +/* printf( "highColor = %ld\n", priv.highColor ); + printf( "lowColor = %ld\n", priv.lowColor ); + printf( "criticalColor = %ld\n", priv.criticalColor ); + printf( "foreground = %ld\n", priv.foreground ); + printf( "highValue = %d\n", priv.highValue ); + printf( "lowValue = %d\n", priv.lowValue ); + printf( "geometry = %s\n", priv.geometry );*/ + + cursor = XCreateFontCursor( XtDisplay( topLevel ), XC_top_left_arrow ); + + form = XtVaCreateManagedWidget( "form", + formWidgetClass, topLevel, + XtNorientation, XtorientHorizontal, + XtNborderWidth, 0, + XtNdefaultDistance, 2, + NULL ); + + label = XtVaCreateManagedWidget( "label", + labelWidgetClass, form, + XtNleft, XtChainLeft, + XtNinternalHeight, 0, + XtNinternalWidth, 0, + XtNborderWidth, 0, + XtNlabel, "Status", + NULL ); + + XtVaGetValues( label, XtNfont, &fs, NULL ); + fontWidth = fs->max_bounds.width; + fontHeight = fs->max_bounds.ascent + fs->max_bounds.descent; + XtVaSetValues( label, XtNwidth, fontWidth * 8, NULL ); + + scrollbar = XtVaCreateManagedWidget( "scrollbar", + scrollbarWidgetClass, form, + XtNhorizDistance, 3, + XtNfromHoriz, label, + XtNorientation, XtorientHorizontal, + XtNscrollHCursor, cursor, + XtNthickness, fontHeight, + XtNlength, (width > fontWidth*4 - 6) + ? width - fontWidth * 4 - 6 + : fontWidth * 4, + NULL ); + + XawScrollbarSetThumb( scrollbar, 0.0, 0.0 ); +/* XtVaSetValues( scrollbar, + XtNtranslations, XtParseTranslationTable( "" ), NULL ); + */ + XtRealizeWidget( topLevel ); + timerId = XtAppAddTimeOut( app_context, 0, update, app_context ); + XtAppMainLoop( app_context ); + + return 0; +} diff --git a/wireless_tools/xwireless.make b/wireless_tools/xwireless.make new file mode 100644 index 0000000..758d827 --- /dev/null +++ b/wireless_tools/xwireless.make @@ -0,0 +1,53 @@ +# Makefile for Xwireless +CC = gcc +RM = rm -f + +RM_CMD = $(RM) *.BAK *.bak *.o ,* *~ *.a + +INCLUDES = $(SYS_INCLUDES) $(LOCAL_INCLUDES) +LIBRARIES = $(LOCAL_LIBRARIES) $(SYS_LIBRARIES) +LIBPATH = $(SYS_LIBPATH) $(LOCAL_LIBPATH) + +# +# System stuff +# +SYS_INCLUDES = -I/usr/include -I/usr/X11R6/include +SYS_LIBRARIES = -lXaw -lXmu -lXt -lXext -lSM -lICE -lX11 +SYS_LIBPATH = -L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib + +# +# Local stuff +# +LOCAL_INCLUDES = +LOCAL_LIBRARIES = +LOCAL_LIBPATH = + +XTRACFLAGS=-Wall -pipe -I. + +# Uncomment these lines for a production compile +#CFLAGS=-O3 -m486 -fomit-frame-pointer +#LDFLAGS=-s +CFLAGS=-g + +# +# Files to make +# +PROGS=xwireless + +SRCS = $(PROGS).c +OBJS = $(PROGS).o + +all:: $(PROGS) + +xwireless: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(INCLUDES) $(LIBPATH) $(LIBRARIES) + +.c.o: + $(CC) $(CFLAGS) $(XTRACFLAGS) -c $(INCLUDES) -DNARROWPROTO $< + +clean:: + $(RM_CMD) + +depend:: + makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS) +# DO NOT DELETE