From 97ca91c03a90126ab12031b2e14a9d45e6d7fe77 Mon Sep 17 00:00:00 2001 From: chris-kirby Date: Tue, 11 Oct 2016 14:35:24 -0600 Subject: [PATCH] v10 --- wireless_tools/iwconfig.8 | 108 ++++++++++++ wireless_tools/iwconfig.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++ wireless_tools/iwpriv.c | 233 ++++++++++++++++++++++++++ wireless_tools/iwspy.8 | 72 ++++++++ wireless_tools/iwspy.c | 269 ++++++++++++++++++++++++++++++ 5 files changed, 1089 insertions(+) create mode 100644 wireless_tools/iwconfig.8 create mode 100644 wireless_tools/iwconfig.c create mode 100644 wireless_tools/iwpriv.c create mode 100644 wireless_tools/iwspy.8 create mode 100644 wireless_tools/iwspy.c diff --git a/wireless_tools/iwconfig.8 b/wireless_tools/iwconfig.8 new file mode 100644 index 0000000..b2e3d60 --- /dev/null +++ b/wireless_tools/iwconfig.8 @@ -0,0 +1,108 @@ +.\" Jean II - HPLB - 96 +.\" iwconfig.8 +.\" +.TH IWCONFIG 8 "31 October 1996" "net-tools" "Linux Programmer's Manual" +.\" +.\" NAME part +.\" +.SH NAME +iwconfig \- configure a wireless network interface +.\" +.\" SYNOPSIS part +.\" +.SH SYNOPSIS +.BI "iwconfig [" interface ] +.br +.BI "iwconfig " interface " [nwid " N "] [freq " F ] +.\" +.\" DESCRIPTION part +.\" +.SH DESCRIPTION +.B Iwconfig +is similar to +.IR ifconfig (8), +but is dedicated to the wireless interfaces. It is used to set the +parameters of the network interface which are specific to the wireless +operation (for example : the frequency). +.B Iwconfig +may also be used to display those parameters, and the wireless +statistics (extracted from +.IR /proc/net/wireless ). +.PP +All these parameters and statistics are device dependant. Each driver +will provide only some of them depending on the hardware support, and +the range of value may change. Please refer to the man page of each +device for details. +.\" +.\" PARAMETER part +.\" +.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). +.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). +.\" +.\" DISPLAY part +.\" +.SH DISPLAY +For each device which support wireless extensions, +.I iwconfig +will display the name of the +.B MAC protocol +used (name of device for proprietary protocols), the +.B NWID +and the +.B frequency +(if available). +.PP +If +.I /proc/net/wireless +exists, +.I iwconfig +will also display its content : +.TP +.B Link quality +Quality of the link or the modulation (how good the received signal is). +.TP +.B Signal level +Received signal strength (how strong the received signal is). +.TP +.B Noise level +Background noise level (when no packet is transmited). +.TP +.B invalid nwid +Number of packets received with a different NWID. Used to detect +configuration problems or adjacent network existence. +.TP +.B invalid crypt +Number of packets that the hardware was unable to decrypt. +.TP +.B invalid misc +Other packets lost in relation with specific wireless operations. +.\" +.\" 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 iwspy (8), +.BR iwpriv (8), +.BR wavelan (4), +.BR wavelan_cs (4), +.BR xircnw_cs (4). diff --git a/wireless_tools/iwconfig.c b/wireless_tools/iwconfig.c new file mode 100644 index 0000000..33bc879 --- /dev/null +++ b/wireless_tools/iwconfig.c @@ -0,0 +1,407 @@ +/* + * Hack my way... Jean II + */ +#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 */ + + +static void +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"); + 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"); +} + +static int if_getstats(char *ifname, iwstats * stats) +{ + 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.crypt); + bp = strtok(NULL, " ."); + sscanf(bp, "%d", &stats->discard.misc); + fclose(f); + return; + } + } + fclose(f); + return 0; +} + +/* Get wireless informations & config from the device driver */ +static int +get_info(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) + /* If no wireless name : no wireless extensions */ + return(-1); + else + strcpy(info->name, wrq.u.name); + + /* Get network ID */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWNWID, &wrq) >= 0) + { + info->has_nwid = 1; + info->nwid_on = wrq.u.nwid.on; + info->nwid = wrq.u.nwid.nwid; + } + + /* Get frequency / channel */ + strcpy(wrq.ifr_name, ifname); + if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0) + { + info->has_freq = 1; + info->freq = wrq.u.freq; + } + + /* Get stats */ + if(if_getstats(ifname, &(info->stats)) == 0) + { + info->has_stats = 1; + } + + /* Get ranges */ + strcpy(wrq.ifr_name, ifname); + wrq.u.data.pointer = (caddr_t) &(info->range); + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0) + { + info->has_range = 1; + } + + return(0); +} + + +static int +set_info(char * args[], /* Command line args */ + int count, /* Args count */ + char * ifname) /* Dev name */ +{ + struct iwreq wrq; + int i; + + /* Set dev name */ + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + /* 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")) + { + if(++i >= count) + usage(); + if(!strcasecmp(args[i], "off")) + wrq.u.nwid.on = 0; + else + if(sscanf(args[i], "%lX", &(wrq.u.nwid.nwid)) != 1) + usage(); + else + wrq.u.nwid.on = 1; + + if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno)); + return(-1); + } + continue; + } + + /* Set frequency / channel */ + if((!strncmp(args[i], "freq", 4)) || + (!strcmp(args[i], "channel"))) + { + if(++i >= count) + { + struct iw_range range; + int k; + + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = 0; + wrq.u.data.flags = 0; + if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) + { + fprintf(stderr, "SIOCGIWRANGE: %s\n", strerror(errno)); + return(-1); + } + + 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 */ + } + + 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; + + if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) + { + fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno)); + return(-1); + } + continue; + } + + /* Here we have an unrecognised arg... */ + fprintf(stderr, "Invalid argument : %s\n", args[i]); + usage(); + return(-1); + } /* for(index ... */ + return(0); +} + +static void +print_devices(char *ifname) +{ + char buff[1024]; + struct wireless_info info; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + if(ifname == (char *)NULL) + { + 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; + for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) + { + if(get_info(ifr->ifr_name, &info) < 0) + { + /* Could skip this message ? */ + fprintf(stderr, "%-8.8s no wireless extensions.\n\n", + ifr->ifr_name); + continue; + } + + print_info(&info); + } + } + else + { + if(get_info(ifname, &info) < 0) + { + fprintf(stderr, "%s: no wireless extensions.\n", + ifname); + usage(); + } + else + print_info(&info); + } +} + + +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; +} + +int +main(int argc, + char ** argv) +{ + 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_devices((char *)NULL); + close(skfd); + exit(0); + } + + /* The device name must be the first argument */ + if(argc == 2) + { + print_devices(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]); + + /* Close the socket. */ + close(skfd); + + return(goterr); +} diff --git a/wireless_tools/iwpriv.c b/wireless_tools/iwpriv.c new file mode 100644 index 0000000..32034ba --- /dev/null +++ b/wireless_tools/iwpriv.c @@ -0,0 +1,233 @@ +/* + * Warning : this program need wireless extensions... + */ +#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() +{ + 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; +} + +int +byte_size(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; +} + +int +main(int argc, + char ** argv) +{ + struct iwreq wrq; + char * ifname = argv[1]; + struct iw_priv_args priv[16]; + int k; + + if(argc < 2) + exit(0); + + /* Create a channel to the NET kernel. */ + if((skfd = sockets_open()) < 0) + { + perror("socket"); + exit(-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) + { + fprintf(stderr, "Interface doesn't provide private interface info...\n"); + fprintf(stderr, "SIOCGIWPRIV: %s\n", strerror(errno)); + return(-1); + } + + /* If no args... */ + if(argc < 3) + { + char * argtype[] = { " ", "byte", "char", "", "int", "float" }; + + 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]); + } + else + { + u_char buffer[1024]; + + /* 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; + + /* Warning : we may have no args to set... */ + + 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; + + /* Fetch args */ + for(i = 0; i < wrq.u.data.length; i++) + sscanf(argv[i + 3], "%d", buffer + i); + break; + + 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; + + /* Fetch args */ + for(i = 0; i < wrq.u.data.length; i++) + sscanf(argv[i + 3], "%d", ((u_int *) buffer) + i); + 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 + { + wrq.u.data.pointer = (caddr_t) buffer; + wrq.u.data.flags = 0; + } + + 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); + } + + /* 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 i; + int n; /* number of args */ + + 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; + + 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); + } + + } /* if args to set */ + + } /* if ioctl list else ioctl exec */ + + /* Close the socket. */ + close(skfd); + + return(1); +} diff --git a/wireless_tools/iwspy.8 b/wireless_tools/iwspy.8 new file mode 100644 index 0000000..099e227 --- /dev/null +++ b/wireless_tools/iwspy.8 @@ -0,0 +1,72 @@ +.\" Jean II - HPLB - 96 +.\" iwspy.8 +.\" +.TH IWSPY 8 "31 October 1996" "net-tools" "Linux Programmer's Manual" +.\" +.\" NAME part +.\" +.SH NAME +iwspy \- Get wireless statistics from specific nodes +.\" +.\" SYNOPSIS part +.\" +.SH SYNOPSIS +.BI "iwspy " interface +.br +.BI "iwspy " interface " [+] " IPADDR " | hw " HWADDR " [...]" +.br +.BI "iwspy " interface " off" +.\" +.\" DESCRIPTION part +.\" +.SH DESCRIPTION +.B Iwspy +is used to set a list of addresses in a wireless network interface and +to read back quality of link information for each of those. This +information is the same as the one available in +.I /proc/net/wireless +: quality of the link, signal strength and noise level. +.PP +This information is updated each time a new packet is received, so +each address of the list add some overhead in the driver. +.\" +.\" PARAMETER part +.\" +.SH PARAMETERS +You may set any number of addresses up to 8. +.TP +.B IPADDR +Set an IP address. As the hardware work with hardware addresses, +.B iwspy +will translate this address through +.IR ARP . +In some case, this address might not be in the ARP cache and +.B iwspy +will fail. In those case, +.IR ping (8) +this address and retry. +.TP +.B hw HWADDR +Set a hardware (MAC) address (this address is not translated & checked +like the IP one). +.TP +.B + +Add the new set of addresses at the end of the current list instead of +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 +.\" +.\" FILES part +.\" +.SH FILES +.I /proc/net/wireless +.\" +.\" SEE ALSO part +.\" +.SH SEE ALSO +.BR iwconfig (8), +.BR ifconfig (8), +.BR iwpriv (8). + diff --git a/wireless_tools/iwspy.c b/wireless_tools/iwspy.c new file mode 100644 index 0000000..3e66a86 --- /dev/null +++ b/wireless_tools/iwspy.c @@ -0,0 +1,269 @@ +/* + * Warning : this program need to be link against libsupport.a + * in net-tools-1.2.0 + * This program need also wireless extensions... + */ +#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() +{ + 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; +} + +int +main(int argc, + char ** argv) +{ + struct ifreq ifr; + struct iwreq wrq; + struct aftype *ap; + struct hwtype *hw; + char * ifname = argv[1]; + + if(argc < 2) + exit(0); + + /* Create a channel to the NET kernel. */ + if((skfd = sockets_open()) < 0) + { + perror("socket"); + exit(-1); + } + + /* 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)) + { + /* Deep trouble... */ + fprintf(stderr, "Interface %s unavailable\n", ifname); + exit(0); + } + +#ifdef DEBUG + printf("Interface : %d - %s - %s\n", ifr.ifr_addr.sa_family, + ap->name, ap->sprint(&ifr.ifr_addr, 1)); +#endif + + /* 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)) + { + /* Deep trouble... */ + fprintf(stderr, "Unable to get hardware address of the interface %s\n", + ifname); + exit(0); + } + +#ifdef DEBUG + printf("Hardware : %d - %s - %s\n", ifr.ifr_hwaddr.sa_family, + hw->name, hw->print(ifr.ifr_hwaddr.sa_data)); +#endif + + /* 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; + + 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); + } + + n = wrq.u.data.length; + + hwa = (struct sockaddr *) buffer; + qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n)); + + 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)" : ""); + } + 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)); + + i = 3; /* skip the "+" */ + } + + /* 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 */ + + + /* Check the number of addresses */ + if((nbr == 0) && strcmp(argv[2], "off")) + { + fprintf(stderr, "No valid addresses found : exiting...\n"); + exit(0); + } + + /* Check if there is some remaining arguments */ + if(i < argc) + { + fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY); + } + + /* 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); + } + } + + /* Close the socket. */ + close(skfd); + + return(1); +} -- 2.11.0