📄 iwlib.c
字号:
/* * Wireless Tools * * Jean II - HPLB 97->99 - HPL 99->03 * * Common subroutines to all the wireless tools... * * This file is released under the GPL license. * Copyright (c) 1997-2003 Jean Tourrilhes <jt@hpl.hp.com> *//***************************** INCLUDES *****************************/#include "iwlib.h" /* Header *//************************ CONSTANTS & MACROS ************************//* Various versions information *//* Recommended Wireless Extension version */#define WE_VERSION 16 /* ### don't forget #warning ### *//* Version of Wireless Tools */#define WT_VERSION 26/* * Verify a few things about Wireless Extensions. * I try to maximise backward and forward compatibility, but things are * tricky because I'm fixing bugs and adding new features. * Wireless Tools *must* be compiled with the same version of WE * as the driver. Sometime, the size or layout of some structure changes, * and might produce interesting results. * Wireless Tools will usually compile properly against different * versions of WE, thanks to the zillions of #ifdefs in my code. * Jean II */#if WIRELESS_EXT < 9#error "Wireless Extension v9 or newer required :-("#error "Use Wireless Tools v19 or update your kernel headers !"#endif#if WIRELESS_EXT < WE_VERSION && !defined(WEXT_HEADER)#warning "Wireless Extension earlier than v16 detected,"#warning "Not all tools features will be compiled in !"#warning "No worry, I'll try to make the best of it ;-)"#endif#if WIRELESS_EXT > WE_VERSION && !defined(WEXT_HEADER)#warning "Wireless Extension later than v16 detected,"#warning "Maybe you should get a more recent version"#warning "of the Wireless Tools package !"#endif/**************************** VARIABLES ****************************/const char * const iw_operation_mode[] = { "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor" };/* Disable runtime version warning in iw_get_range_info() */int iw_ignore_version = 0;/************************ SOCKET SUBROUTINES *************************//*------------------------------------------------------------------*//* * Open a socket. * Depending on the protocol present, open the right socket. The socket * will allow us to talk to the driver. */intiw_sockets_open(void){ static const int families[] = { AF_INET, AF_IPX, AF_AX25, AF_APPLETALK }; unsigned int i; int sock; /* * Now pick any (exisiting) useful socket family for generic queries * Note : don't open all the socket, only returns when one matches, * all protocols might not be valid. * Workaround by Jim Kaba <jkaba@sarnoff.com> * Note : in 99% of the case, we will just open the inet_sock. * The remaining 1% case are not fully correct... */ /* Try all families we support */ for(i = 0; i < sizeof(families)/sizeof(int); ++i) { /* Try to open the socket, if success returns it */ sock = socket(families[i], SOCK_DGRAM, 0); if(sock >= 0) return sock; } return -1;}/*------------------------------------------------------------------*//* * Extract the interface name out of /proc/net/wireless or /proc/net/dev. */static inline char *iw_get_ifname(char * name, /* Where to store the name */ int nsize, /* Size of name buffer */ char * buf) /* Current position in buffer */{ char * end; /* Skip leading spaces */ while(isspace(*buf)) buf++;#ifndef IW_RESTRIC_ENUM /* Get name up to the last ':'. Aliases may contain ':' in them, * but the last one should be the separator */ end = strrchr(buf, ':');#else /* Get name up to ": " * Note : we compare to ": " to make sure to process aliased interfaces * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee * a ' ' after the ':'*/ end = strstr(buf, ": ");#endif /* Not found ??? To big ??? */ if((end == NULL) || (((end - buf) + 1) > nsize)) return(NULL); /* Copy */ memcpy(name, buf, (end - buf)); name[end - buf] = '\0'; return(end + 2);}/*------------------------------------------------------------------*//* * Enumerate devices and call specified routine * The new way just use /proc/net/wireless, so get all wireless interfaces, * whether configured or not. This is the default if available. * The old way use SIOCGIFCONF, so get only configured interfaces (wireless * or not). */voidiw_enum_devices(int skfd, iw_enum_handler fn, char * args[], int count){ char buff[1024]; FILE * fh; struct ifconf ifc; struct ifreq *ifr; int i;#ifndef IW_RESTRIC_ENUM /* Check if /proc/net/wireless is available */ fh = fopen(PROC_NET_DEV, "r");#else /* Check if /proc/net/wireless is available */ fh = fopen(PROC_NET_WIRELESS, "r");#endif if(fh != NULL) { /* Success : use data from /proc/net/wireless */ /* Eat 2 lines of header */ fgets(buff, sizeof(buff), fh); fgets(buff, sizeof(buff), fh); /* Read each device line */ while(fgets(buff, sizeof(buff), fh)) { char name[IFNAMSIZ + 1]; char *s; /* Extract interface name */ s = iw_get_ifname(name, sizeof(name), buff); if(!s) /* Failed to parse, complain and continue */#ifndef IW_RESTRIC_ENUM fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");#else fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");#endif else /* Got it, print info about this interface */ (*fn)(skfd, name, args, count); } fclose(fh); } else { /* Get list of configured devices using "traditional" way */ 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++) (*fn)(skfd, ifr->ifr_name, args, count); }}/*********************** WIRELESS SUBROUTINES ************************//*------------------------------------------------------------------*//* * Get the range information out of the driver */intiw_get_range_info(int skfd, char * ifname, iwrange * range){ struct iwreq wrq; char buffer[sizeof(iwrange) * 2]; /* Large enough */ /* Cleanup */ memset(buffer, 0, sizeof(buffer)); wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = sizeof(buffer); wrq.u.data.flags = 0; if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0) return(-1); /* Copy stuff at the right place, ignore extra */ memcpy((char *) range, buffer, sizeof(iwrange)); /* Lots of people have driver and tools out of sync as far as Wireless * Extensions are concerned. It's because /usr/include/linux/wireless.h * and /usr/src/linux/include/linux/wireless.h are different. * We try to catch this stuff here... */ if(!iw_ignore_version) { /* For new versions, we can check the version directly, for old versions * we use magic. 300 bytes is a also magic number, don't touch... */ if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300)) {#if WIRELESS_EXT > 10 /* Version verification - for new versions */ if(range->we_version_compiled != WIRELESS_EXT) { fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled); fprintf(stderr, "of Wireless Extension, while this program is using version %d.\n", WIRELESS_EXT); fprintf(stderr, "Some things may be broken...\n\n"); } /* Driver version verification */ if(range->we_version_compiled < range->we_version_source) { fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source); fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled); fprintf(stderr, "may not be available...\n\n"); }#endif /* WIRELESS_EXT > 10 */ } else { /* Version verification - for old versions */ if(wrq.u.data.length != sizeof(iwrange)) { fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname); fprintf(stderr, "of Wireless Extension, while this program is using version %d.\n", WIRELESS_EXT); fprintf(stderr, "Some things may be broken...\n\n"); } } } /* Don't complain twice. * In theory, the test apply to each individual driver, but usually * all drivers are compiled from the same kernel, and most often * problem is the system/glibc headers. */ iw_ignore_version = 1; /* Note : we are only trying to catch compile difference, not source. * If the driver source has not been updated to the latest, it doesn't * matter because the new fields are set to zero */ return(0);}/*------------------------------------------------------------------*//* * Print the WE versions of the interface. */static intprint_iface_version_info(int skfd, char * ifname, char * args[], /* Command line args */ int count) /* Args count */{ struct iwreq wrq; char buffer[sizeof(iwrange) * 2]; /* Large enough */ struct iw_range * range; /* Avoid "Unused parameter" warning */ args = args; count = count; /* If no wireless name : no wireless extensions. * This enable us to treat the SIOCGIWRANGE failure below properly. */ if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0) return(-1); /* Cleanup */ memset(buffer, 0, sizeof(buffer)); wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = sizeof(buffer); wrq.u.data.flags = 0; if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0) { /* Interface support WE (see above), but not IWRANGE */ fprintf(stderr, "%-8.8s Driver has no Wireless Extension version information.\n\n", ifname); return(0); } /* Copy stuff at the right place, ignore extra */ range = (struct iw_range *) buffer; /* For new versions, we can check the version directly, for old versions * we use magic. 300 bytes is a also magic number, don't touch... */ if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300)) {#if WIRELESS_EXT > 10 printf("%-8.8s Recommend Wireless Extension v%d or later,\n", ifname, range->we_version_source); printf(" Currently compiled with Wireless Extension v%d.\n\n", range->we_version_compiled);#endif /* WIRELESS_EXT > 10 */ } else {#if 0 fprintf(stderr, "%-8.8s Wireless Extension version too old.\n\n", ifname);#endif } return(0);}/*------------------------------------------------------------------*//* * Print the WE versions of the tools. */intiw_print_version_info(char * toolname){ int skfd; /* generic raw socket desc. */ char buff[1024]; FILE * fh; char * p; int v; /* Create a channel to the NET kernel. */ if((skfd = iw_sockets_open()) < 0) { perror("socket"); return -1; } /* Information about the tools themselves */ if(toolname != NULL) printf("%-8.8s Version %d\n", toolname, WT_VERSION); printf(" Compatible with Wireless Extension v%d or earlier,\n", WE_VERSION); printf(" Currently compiled with Wireless Extension v%d.\n\n", WIRELESS_EXT); /* Check if /proc/net/wireless is available */ fh = fopen(PROC_NET_WIRELESS, "r"); if(fh != NULL) { /* Read the first line of buffer */ fgets(buff, sizeof(buff), fh); /* Check if it's WE-16 or later */ if(strstr(buff, "| WE") != NULL) { /* Read the second line of buffer */ fgets(buff, sizeof(buff), fh); /* Get to the last separator, to get the version */ p = strrchr(buff, '|'); if((p != NULL) && (sscanf(p + 1, "%d", &v) == 1)) /* That was it ! */ printf("Kernel Currently compiled with Wireless Extension v%d.\n\n", v); } /* Cleanup */ fclose(fh); } /* Version for each device */ iw_enum_devices(skfd, &print_iface_version_info, NULL, 0); close(skfd); return 0;}/*------------------------------------------------------------------*//* * Get information about what private ioctls are supported by the driver */intiw_get_priv_info(int skfd, char * ifname, iwprivargs * priv, int maxpriv){ struct iwreq wrq; /* Ask the driver */ wrq.u.data.pointer = (caddr_t) priv; wrq.u.data.length = maxpriv; wrq.u.data.flags = 0; if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0) return(-1); /* Return the number of ioctls */ return(wrq.u.data.length);}/*------------------------------------------------------------------*//* * Get essential wireless 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... * Note : compare to the version in iwconfig, we extract only * what's *really* needed to configure a device... */intiw_get_basic_config(int skfd, char * ifname, wireless_config * info){ struct iwreq wrq; memset((char *) info, 0, sizeof(struct wireless_config)); /* Get wireless name */ if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0) /* If no wireless name : no wireless extensions */ return(-1); else { strncpy(info->name, wrq.u.name, IFNAMSIZ); info->name[IFNAMSIZ] = '\0'; } /* Get network ID */ if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0) { info->has_nwid = 1; memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam)); } /* Get frequency / channel */ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -