📄 iwlib.c
字号:
/* * Wireless Tools * * Jean II - HPLB 97->99 - HPL 99->04 * * Common subroutines to all the wireless tools... * * This file is released under the GPL license. * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com> *//***************************** INCLUDES *****************************/#include "iwlib.h" /* Header *//************************ CONSTANTS & MACROS ************************//* * Constants fof WE-9->15 */#define IW15_MAX_FREQUENCIES 16#define IW15_MAX_BITRATES 8#define IW15_MAX_TXPOWER 8#define IW15_MAX_ENCODING_SIZES 8#define IW15_MAX_SPY 8#define IW15_MAX_AP 8/****************************** TYPES ******************************//* * Struct iw_range up to WE-15 */struct iw15_range{ __u32 throughput; __u32 min_nwid; __u32 max_nwid; __u16 num_channels; __u8 num_frequency; struct iw_freq freq[IW15_MAX_FREQUENCIES]; __s32 sensitivity; struct iw_quality max_qual; __u8 num_bitrates; __s32 bitrate[IW15_MAX_BITRATES]; __s32 min_rts; __s32 max_rts; __s32 min_frag; __s32 max_frag; __s32 min_pmp; __s32 max_pmp; __s32 min_pmt; __s32 max_pmt; __u16 pmp_flags; __u16 pmt_flags; __u16 pm_capa; __u16 encoding_size[IW15_MAX_ENCODING_SIZES]; __u8 num_encoding_sizes; __u8 max_encoding_tokens; __u16 txpower_capa; __u8 num_txpower; __s32 txpower[IW15_MAX_TXPOWER]; __u8 we_version_compiled; __u8 we_version_source; __u16 retry_capa; __u16 retry_flags; __u16 r_time_flags; __s32 min_retry; __s32 max_retry; __s32 min_r_time; __s32 max_r_time; struct iw_quality avg_qual;};/* * Union for all the versions of iwrange. * Fortunately, I mostly only add fields at the end, and big-bang * reorganisations are few. */union iw_range_raw{ struct iw15_range range15; /* WE 9->15 */ struct iw_range range; /* WE 16->current */};/* * Offsets in iw_range struct */#define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \ (char *) NULL)#define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \ (char *) NULL)/**************************** VARIABLES ****************************//* Modes as human readable strings */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 value currently unused, just make sure it's non-NULL */ return(end);}/*------------------------------------------------------------------*//* * 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/dev 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; /* Skip empty or almost empty lines. It seems that in some * cases fgets return a line with only a newline. */ if((buff[0] == '\0') || (buff[1] == '\0')) continue; /* 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 ************************//*------------------------------------------------------------------*//* * Extract WE version number from /proc/net/wireless * In most cases, you really want to get version information from * the range info (range->we_version_compiled), see below... * * If we have WE-16 and later, the WE version is available at the * end of the header line of the file. * For version prior to that, we can only detect the change from * v11 to v12, so we do an approximate job. Fortunately, v12 to v15 * are highly binary compatible (on the struct level). */intiw_get_kernel_we_version(void){ char buff[1024]; FILE * fh; char * p; int v; /* Check if /proc/net/wireless is available */ fh = fopen(PROC_NET_WIRELESS, "r"); if(fh == NULL) { fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n"); return(-1); } /* Read the first line of buffer */ fgets(buff, sizeof(buff), fh); if(strstr(buff, "| WE") == NULL) { /* Prior to WE16, so explicit version not present */ /* Black magic */ if(strstr(buff, "| Missed") == NULL) v = 11; else v = 15; fclose(fh); return(v); } /* 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)) { fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n"); fclose(fh); return(-1); } fclose(fh); return(v);}/*------------------------------------------------------------------*//* * 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.16s 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(wrq.u.data.length >= 300) { /* Version is always at the same offset, so it's ok */ printf("%-8.16s 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); } else { fprintf(stderr, "%-8.16s Wireless Extension version too old.\n\n", ifname); } return(0);}/*------------------------------------------------------------------*//* * Print the WE versions of the tools. */intiw_print_version_info(const char * toolname){ int skfd; /* generic raw socket desc. */ int we_kernel_version; /* 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.16s Wireless-Tools version %d\n", toolname, WT_VERSION); printf(" Compatible with Wireless Extension v11 to v%d.\n\n", WE_VERSION); /* Get version from kernel */ we_kernel_version = iw_get_kernel_we_version(); /* Only version >= 16 can be verified, other are guessed */ if(we_kernel_version > 15) printf("Kernel Currently compiled with Wireless Extension v%d.\n\n", we_kernel_version); /* Version for each device */ iw_enum_devices(skfd, &print_iface_version_info, NULL, 0); iw_sockets_close(skfd); return 0;}/*------------------------------------------------------------------*//* * Get the range information out of the driver */intiw_get_range_info(int skfd, const char * ifname, iwrange * range){ struct iwreq wrq; char buffer[sizeof(iwrange) * 2]; /* Large enough */ union iw_range_raw * range_raw; /* Cleanup */ bzero(buffer, 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); /* Point to the buffer */ range_raw = (union iw_range_raw *) 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(wrq.u.data.length < 300) { /* That's v10 or earlier. Ouch ! Let's make a guess...*/ range_raw->range.we_version_compiled = 9; } /* Check how it needs to be processed */ if(range_raw->range.we_version_compiled > 15) { /* This is our native format, that's easy... */ /* Copy stuff at the right place, ignore extra */ memcpy((char *) range, buffer, sizeof(iwrange)); } else { /* Zero unknown fields */ bzero((char *) range, sizeof(struct iw_range)); /* Initial part unmoved */ memcpy((char *) range, buffer, iwr15_off(num_channels)); /* Frequencies pushed futher down towards the end */ memcpy((char *) range + iwr_off(num_channels), buffer + iwr15_off(num_channels), iwr15_off(sensitivity) - iwr15_off(num_channels)); /* This one moved up */ memcpy((char *) range + iwr_off(sensitivity), buffer + iwr15_off(sensitivity), iwr15_off(num_bitrates) - iwr15_off(sensitivity)); /* This one goes after avg_qual */ memcpy((char *) range + iwr_off(num_bitrates), buffer + iwr15_off(num_bitrates), iwr15_off(min_rts) - iwr15_off(num_bitrates)); /* Number of bitrates has changed, put it after */ memcpy((char *) range + iwr_off(min_rts), buffer + iwr15_off(min_rts), iwr15_off(txpower_capa) - iwr15_off(min_rts)); /* Added encoding_login_index, put it after */ memcpy((char *) range + iwr_off(txpower_capa), buffer + iwr15_off(txpower_capa),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -