wireless-tools源码分析-iwlist
iwlist
iwlist主要用来显示无线网卡的一些附加信息。
iwlist的用法:
useage: iwlist [interface] options
scanning 扫描一定范围内的无线接入点和Ad-Hoc单元信息,包括ESSID,信号质量,频段以及无线模式等
frequency 频率
channel显示设备支持的频道及当前所在的频道
rate/bitrate 设备支持的速率
encryption 加密
key 密钥
power 电源
txpower 发送功率
retry 重传机制
ap 本地无线接入点及信号质量
peers 直连
event 设备支持的无线事件
auth 当前设置的WPA认证参数
wpa 罗列设备上设置的所有WPA加密密钥
modu 罗列设备支持的调制模式及当前开启的调制模式
iwlist中的main函数,内容如下:
/*------------------------------------------------------------------*/
/** The main !*/
int
main(int argc,char ** argv)
{int skfd; /* generic raw socket desc. */char *dev; /* device name */char *cmd; /* command */char **args; /* Command arguments */int count; /* Number of arguments */const iwlist_cmd *iwcmd;if(argc < 2)iw_usage(1);/* Those don't apply to all interfaces */if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))iw_usage(0);if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))return(iw_print_version_info("iwlist"));if(argc == 2){cmd = argv[1];dev = NULL;args = NULL;count = 0;}else{cmd = argv[2];dev = argv[1];args = argv + 3;count = argc - 3;}/* find a command */iwcmd = find_command(cmd);if(iwcmd == NULL)return 1;/* Check arg numbers */if((iwcmd->max_count >= 0) && (count > iwcmd->max_count)){fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",iwcmd->cmd, iwcmd->max_count);return 1;}/* Create a channel to the NET kernel. */if((skfd = iw_sockets_open()) < 0){perror("socket");return -1;}/* do the actual work */if (dev)(*iwcmd->fn)(skfd, dev, args, count);elseiw_enum_devices(skfd, iwcmd->fn, args, count);/* Close the socket. */iw_sockets_close(skfd);return 0;
}
iw_sockets_open
函数,该函数创建了iwlist命令使用的套接字。
iw_enum_devices
函数,该函数和iwconfig中的一样,也是在缺少参数的情况下打印出无线设备接口的配置信息。
iwlist_cmd
是定义的iwlist_entry
结构体数组,定义内容如下:
static const struct iwlist_entry iwlist_cmds[] = {{ "scanning", print_scanning_info, -1, "[essid NNN] [last]" },{ "frequency", print_freq_info, 0, NULL },{ "channel", print_freq_info, 0, NULL },{ "bitrate", print_bitrate_info, 0, NULL },{ "rate", print_bitrate_info, 0, NULL },{ "encryption", print_keys_info, 0, NULL },{ "keys", print_keys_info, 0, NULL },{ "power", print_pm_info, 0, NULL },
#ifndef WE_ESSENTIAL{ "txpower", print_txpower_info, 0, NULL },{ "retry", print_retry_info, 0, NULL },{ "ap", print_ap_info, 0, NULL },{ "accesspoints", print_ap_info, 0, NULL },{ "peers", print_ap_info, 0, NULL },{ "event", print_event_capa_info, 0, NULL },{ "auth", print_auth_info, 0, NULL },{ "wpakeys", print_wpakeys_info, 0, NULL },{ "genie", print_gen_ie_info, 0, NULL },{ "modulation", print_modul_info, 0, NULL },
#endif /* WE_ESSENTIAL */{ NULL, NULL, 0, 0 },
};
iwlist_entry
结构体定义了命令行参数条目,和调用了iw_enum_handler
函数。其中scanning调用的print_scanning_info
函数,内容如下:
/*------------------------------------------------------------------*/
/** Perform a scanning on one device*/
static int
print_scanning_info(int skfd,char * ifname,char * args[], /* Command line args */int count) /* Args count */
{struct iwreq wrq;struct iw_scan_req scanopt; /* Options for 'set' */int scanflags = 0; /* Flags for scan */unsigned char * buffer = NULL; /* Results */int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */struct iw_range range;int has_range;struct timeval tv; /* Select timeout */int timeout = 15000000; /* 15s *//* Avoid "Unused parameter" warning */args = args; count = count;/* Debugging stuff */if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN)){fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");fprintf(stderr, "*** and the following line :\n");fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);}/* Get range stuff */has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);/* Check if the interface could support scanning. */if((!has_range) || (range.we_version_compiled < 14)){fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n",ifname);
return(-1);}/* Init timeout value -> 250ms between set and first get */tv.tv_sec = 0;tv.tv_usec = 250000;/* Clean up set args */memset(&scanopt, 0, sizeof(scanopt));/* Parse command line arguments and extract options.* Note : when we have enough options, we should use the parser* from iwconfig... */while(count > 0){/* One arg is consumed (the option name) */count--;/** Check for Active Scan (scan with specific essid)*/if(!strncmp(args[0], "essid", 5)){if(count < 1){fprintf(stderr, "Too few arguments for scanning option [%s]\n",args[0]);
return(-1);}args++;count--;/* Store the ESSID in the scan options */scanopt.essid_len = strlen(args[0]);memcpy(scanopt.essid, args[0], scanopt.essid_len);/* Initialise BSSID as needed */if(scanopt.bssid.sa_family == 0){scanopt.bssid.sa_family = ARPHRD_ETHER;memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN);}/* Scan only this ESSID */scanflags |= IW_SCAN_THIS_ESSID;}else/* Check for last scan result (do not trigger scan) */if(!strncmp(args[0], "last", 4)){/* Hack */scanflags |= IW_SCAN_HACK;}else{fprintf(stderr, "Invalid scanning option [%s]\n", args[0]);
return(-1);}/* Next arg */args++;}/* Check if we have scan options */if(scanflags){wrq.u.data.pointer = (caddr_t) &scanopt;wrq.u.data.length = sizeof(scanopt);wrq.u.data.flags = scanflags;}else{wrq.u.data.pointer = NULL;wrq.u.data.flags = 0;wrq.u.data.length = 0;}/* If only 'last' was specified on command line, don't trigger a scan */if(scanflags == IW_SCAN_HACK){/* Skip waiting */tv.tv_usec = 0;}else{/* Initiate Scanning */if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0){if((errno != EPERM) || (scanflags != 0)){fprintf(stderr, "%-8.16s Interface doesn't support scanning : %s\n\n",ifname, strerror(errno));
return(-1);}/* If we don't have the permission to initiate the scan, we may* still have permission to read left-over results.* But, don't wait !!! */
#if 0/* Not cool, it display for non wireless interfaces... */fprintf(stderr, "%-8.16s (Could not trigger scanning, just reading left-over results)\n", ifname);
#endiftv.tv_usec = 0;}}timeout -= tv.tv_usec;/* Forever */while(1){fd_set rfds; /* File descriptors for select */int last_fd; /* Last fd */int ret;/* Guess what ? We must re-generate rfds each time */FD_ZERO(&rfds);last_fd = -1;/* In here, add the rtnetlink fd in the list *//* Wait until something happens */ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);/* Check if there was an error */if(ret < 0){if(errno == EAGAIN || errno == EINTR)continue;fprintf(stderr, "Unhandled signal - exiting...\n");
return(-1);}/* Check if there was a timeout */if(ret == 0){unsigned char * newbuf;realloc:/* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */newbuf = realloc(buffer, buflen);if(newbuf == NULL){if(buffer)free(buffer);fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
return(-1);}buffer = newbuf;/* Try to read the results */wrq.u.data.pointer = buffer;wrq.u.data.flags = 0;wrq.u.data.length = buflen;if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0){/* Check if buffer was too small (WE-17 only) */if((errno == E2BIG) && (range.we_version_compiled > 16)){/* Some driver may return very large scan results, either* because there are many cells, or because they have many* large elements in cells (like IWEVCUSTOM). Most will* only need the regular sized buffer. We now use a dynamic* allocation of the buffer to satisfy everybody. Of course,* as we don't know in advance the size of the array, we try* various increasing sizes. Jean II *//* Check if the driver gave us any hints. */if(wrq.u.data.length > buflen)buflen = wrq.u.data.length;elsebuflen *= 2;/* Try again */goto realloc;}/* Check if results not available yet */if(errno == EAGAIN){/* Restart timer for only 100ms*/tv.tv_sec = 0;tv.tv_usec = 100000;timeout -= tv.tv_usec;if(timeout > 0)continue; /* Try again later */}/* Bad error */free(buffer);fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n",ifname, strerror(errno));
return(-2);}else/* We have the results, go to process them */break;}/* In here, check if event and event type* if scan event, read results. All errors bad & no reset timeout */}if(wrq.u.data.length){struct iw_event iwe;struct stream_descr stream;struct iwscan_state state = { .ap_num = 1, .val_index = 0 };int ret;#ifdef DEBUG/* Debugging code. In theory useless, because it's debugged ;-) */int i;printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);for(i = 1; i < wrq.u.data.length; i++)printf(":%02X", buffer[i]);printf("]\n");
#endifprintf("%-8.16s Scan completed :\n", ifname);iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);do{/* Extract an event and print it */ret = iw_extract_event_stream(&stream, &iwe,range.we_version_compiled);if(ret > 0)print_scanning_token(&stream, &iwe, &state,&range, has_range);}while(ret > 0);printf("\n");}elseprintf("%-8.16s No scan results\n\n", ifname);free(buffer);
return(0);
}
iw_get_range_info
函数,将获取的驱动信息放入结构体iwrange
中。
iw_set_ext
和iw_get_ext
函数,和iwconfig中的使用相同,都是进行了ioctl操作。
其中扫描请求结构体定义iw_scan_req
/** Optional data for scan request** Note: these optional parameters are controlling parameters for the* scanning behavior, these do not apply to getting scan results* (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and* provide a merged results with all BSSes even if the previous scan* request limited scanning to a subset, e.g., by specifying an SSID.* Especially, scan results are required to include an entry for the* current BSS if the driver is in Managed mode and associated with an AP.*/
struct iw_scan_req
{__u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */__u8 essid_len;__u8 num_channels; /* num entries in channel_list;* 0 = scan all allowed channels */__u8 flags; /* reserved as padding; use zero, this may* be used in the future for adding flags* to request different scan behavior */struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or* individual address of a specific BSS *//** Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using* the current ESSID. This allows scan requests for specific ESSID* without having to change the current ESSID and potentially breaking* the current association.*/__u8 essid[IW_ESSID_MAX_SIZE];/** Optional parameters for changing the default scanning behavior.* These are based on the MLME-SCAN.request from IEEE Std 802.11.* TU is 1.024 ms. If these are set to 0, driver is expected to use* reasonable default values. min_channel_time defines the time that* will be used to wait for the first reply on each channel. If no* replies are received, next channel will be scanned after this. If* replies are received, total time waited on the channel is defined by* max_channel_time.*/__u32 min_channel_time; /* in TU */__u32 max_channel_time; /* in TU */struct iw_freq channel_list[IW_MAX_FREQUENCIES];
};
iw_range
结构体定义如下:
/* -------------------------- 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... *//* In theory this value should be the maximum benchmarked* TCP/IP throughput, because with most of these devices the* bit rate is meaningless (overhead an co) to estimate how* fast the connection will go and pick the fastest one.* I suggest people to play with Netperf or any benchmark...*//* NWID (or domain id) */__u32 min_nwid; /* Minimal NWID we are able to set */__u32 max_nwid; /* Maximal NWID we are able to set *//* Old Frequency (backward compat - moved lower ) */__u16 old_num_channels;__u8 old_num_frequency;/* Wireless event capability bitmasks */__u32 event_capa[6];/* signal level threshold range */__s32 sensitivity;/* Quality of link & SNR stuff *//* Quality range (link, level, noise)* If the quality is absolute, it will be in the range [0 ; max_qual],* if the quality is dBm, it will be in the range [max_qual ; 0].* Don't forget that we use 8 bit arithmetics... */struct iw_quality max_qual; /* Quality of the link *//* This should contain the average/typical values of the quality* indicator. This should be the threshold between a "good" and* a "bad" link (example : monitor going from green to orange).* Currently, user space apps like quality monitors don't have any* way to calibrate the measurement. With this, they can split* the range between 0 and max_qual in different quality level* (using a geometric subdivision centered on the average).* I expect that people doing the user space apps will feedback* us on which value we need to put in each driver... */struct iw_quality avg_qual; /* Quality of the link *//* Rates */__u8 num_bitrates; /* Number of entries in the list */__s32 bitrate[IW_MAX_BITRATES]; /* list, in bps *//* RTS threshold */__s32 min_rts; /* Minimal RTS threshold */__s32 max_rts; /* Maximal RTS threshold *//* Frag threshold */__s32 min_frag; /* Minimal frag threshold */__s32 max_frag; /* Maximal frag threshold *//* Power Management duration & timeout */__s32 min_pmp; /* Minimal PM period */__s32 max_pmp; /* Maximal PM period */__s32 min_pmt; /* Minimal PM timeout */__s32 max_pmt; /* Maximal PM timeout */__u16 pmp_flags; /* How to decode max/min PM period */__u16 pmt_flags; /* How to decode max/min PM timeout */__u16 pm_capa; /* What PM options are supported *//* Encoder stuff */__u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */__u8 num_encoding_sizes; /* Number of entry in the list */__u8 max_encoding_tokens; /* Max number of tokens *//* For drivers that need a "login/passwd" form */__u8 encoding_login_index; /* token index for login token *//* Transmit power */__u16 txpower_capa; /* What options are supported */__u8 num_txpower; /* Number of entries in the list */__s32 txpower[IW_MAX_TXPOWER]; /* list, in bps *//* Wireless Extension version info */__u8 we_version_compiled; /* Must be WIRELESS_EXT */__u8 we_version_source; /* Last update of source *//* Retry limits and lifetime */__u16 retry_capa; /* What retry options are supported */__u16 retry_flags; /* How to decode max/min retry limit */__u16 r_time_flags; /* How to decode max/min retry life */__s32 min_retry; /* Minimal number of retries */__s32 max_retry; /* Maximal number of retries */__s32 min_r_time; /* Minimal retry lifetime */__s32 max_r_time; /* Maximal retry lifetime *//* 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,* because each entry contain its channel index */__u32 enc_capa; /* IW_ENC_CAPA_* bit field *//* More power management stuff */__s32 min_pms; /* Minimal PM saving */__s32 max_pms; /* Maximal PM saving */__u16 pms_flags; /* How to decode max/min PM saving *//* All available modulations for driver (hw may support less) */__s32 modul_capa; /* IW_MODUL_* bit field *//* More bitrate stuff */__u32 bitrate_capa; /* Types of bitrates supported */
};
经过select非阻塞获取扫描数据信息,然后iw_init_event_stream
函数,将数据流放入stream_descr
结构体中,再经过iw_extract_event_stream
函数,提取数据流中的事件,放入一个iw_event
结构体,iw_extract_event_stream
函数内容如下:
/*------------------------------------------------------------------*/
/** Extract the next event from the event stream.*/
int
iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */struct iw_event * iwe, /* Extracted event */int we_version)
{const struct iw_ioctl_description * descr = NULL;int event_type = 0;unsigned int event_len = 1; /* Invalid */char * pointer;/* Don't "optimise" the following variable, it will crash */unsigned cmd_index; /* *MUST* be unsigned *//* Check for end of stream */if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
return(0);#ifdef DEBUGprintf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",stream->current, stream->value, stream->end);
#endif/* Extract the event header (to get the event id).* Note : the event may be unaligned, therefore copy... */memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);#ifdef DEBUGprintf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",iwe->cmd, iwe->len);
#endif/* Check invalid events */if(iwe->len <= IW_EV_LCP_PK_LEN)
return(-1);/* Get the type and length of that event */if(iwe->cmd <= SIOCIWLAST){cmd_index = iwe->cmd - SIOCIWFIRST;if(cmd_index < standard_ioctl_num)descr = &(standard_ioctl_descr[cmd_index]);}else{cmd_index = iwe->cmd - IWEVFIRST;if(cmd_index < standard_event_num)descr = &(standard_event_descr[cmd_index]);}if(descr != NULL)event_type = descr->header_type;/* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */event_len = event_type_size[event_type];/* Fixup for earlier version of WE */if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))event_len += IW_EV_POINT_OFF;/* Check if we know about this event */if(event_len <= IW_EV_LCP_PK_LEN){/* Skip to next event */stream->current += iwe->len;
return(2);}event_len -= IW_EV_LCP_PK_LEN;/* Set pointer on data */if(stream->value != NULL)pointer = stream->value; /* Next value in event */elsepointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */#ifdef DEBUGprintf("DBG - event_type = %d, event_len = %d, pointer = %p\n",event_type, event_len, pointer);
#endif/* Copy the rest of the event (at least, fixed part) */if((pointer + event_len) > stream->end){/* Go to next event */stream->current += iwe->len;
return(-2);}/* Fixup for WE-19 and later : pointer no longer in the stream *//* Beware of alignement. Dest has local alignement, not packed */if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,pointer, event_len);elsememcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);/* Skip event in the stream */pointer += event_len;/* Special processing for iw_point events */if(event_type == IW_HEADER_TYPE_POINT){/* Check the length of the payload */unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);if(extra_len > 0){/* Set pointer on variable part (warning : non aligned) */iwe->u.data.pointer = pointer;/* Check that we have a descriptor for the command */if(descr == NULL)/* Can't check payload -> unsafe... */iwe->u.data.pointer = NULL; /* Discard paylod */else{/* Those checks are actually pretty hard to trigger,* because of the checks done in the kernel... */unsigned int token_len = iwe->u.data.length * descr->token_size;/* Ugly fixup for alignement issues.* If the kernel is 64 bits and userspace 32 bits,* we have an extra 4+4 bytes.* Fixing that in the kernel would break 64 bits userspace. */if((token_len != extra_len) && (extra_len >= 4)){__u16 alt_dlen = *((__u16 *) pointer);unsigned int alt_token_len = alt_dlen * descr->token_size;if((alt_token_len + 8) == extra_len){
#ifdef DEBUGprintf("DBG - alt_token_len = %d\n", alt_token_len);
#endif/* Ok, let's redo everything */pointer -= event_len;pointer += 4;/* Dest has local alignement, not packed */memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,pointer, event_len);pointer += event_len + 4;iwe->u.data.pointer = pointer;token_len = alt_token_len;}}/* Discard bogus events which advertise more tokens than* what they carry... */if(token_len > extra_len)iwe->u.data.pointer = NULL; /* Discard paylod *//* Check that the advertised token size is not going to* produce buffer overflow to our caller... */if((iwe->u.data.length > descr->max_tokens)&& !(descr->flags & IW_DESCR_FLAG_NOMAX))iwe->u.data.pointer = NULL; /* Discard paylod *//* Same for underflows... */if(iwe->u.data.length < descr->min_tokens)iwe->u.data.pointer = NULL; /* Discard paylod */
#ifdef DEBUGprintf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
#endif}}else/* No data */iwe->u.data.pointer = NULL;/* Go to next event */stream->current += iwe->len;}else{/* Ugly fixup for alignement issues.* If the kernel is 64 bits and userspace 32 bits,* we have an extra 4 bytes.* Fixing that in the kernel would break 64 bits userspace. */if((stream->value == NULL)&& ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)|| ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||(event_type == IW_HEADER_TYPE_QUAL))) )){
#ifdef DEBUGprintf("DBG - alt iwe->len = %d\n", iwe->len - 4);
#endifpointer -= event_len;pointer += 4;/* Beware of alignement. Dest has local alignement, not packed */memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);pointer += event_len;}/* Is there more value in the event ? */if((pointer + event_len) <= (stream->current + iwe->len))/* Go to next value */stream->value = pointer;else{/* Go to next event */stream->value = NULL;stream->current += iwe->len;}}
return(1);
}
最后通过while循环,使用print_scanning_token
函数将扫描的信息分类打印出来,print_scanning_token
函数内容如下:
/***************************** SCANNING *****************************/
/** This one behave quite differently from the others** Note that we don't use the scanning capability of iwlib (functions* iw_process_scan() and iw_scan()). The main reason is that* iw_process_scan() return only a subset of the scan data to the caller,* for example custom elements and bitrates are ommited. Here, we* do the complete job...*//*------------------------------------------------------------------*/
/** Print one element from the scanning results*/
static inline void
print_scanning_token(struct stream_descr * stream, /* Stream of events */struct iw_event * event, /* Extracted token */struct iwscan_state * state,struct iw_range * iw_range, /* Range info */int has_range)
{char buffer[128]; /* Temporary buffer *//* Now, let's decode the event */switch(event->cmd){case SIOCGIWAP:printf(" Cell %02d - Address: %s\n", state->ap_num,iw_saether_ntop(&event->u.ap_addr, buffer));state->ap_num++;break;case SIOCGIWNWID:if(event->u.nwid.disabled)printf(" NWID:off/any\n");elseprintf(" NWID:%X\n", event->u.nwid.value);break;case SIOCGIWFREQ:{double freq; /* Frequency/channel */int channel = -1; /* Converted to channel */freq = iw_freq2float(&(event->u.freq));/* Convert to channel if possible */if(has_range)channel = iw_freq_to_channel(freq, iw_range);iw_print_freq(buffer, sizeof(buffer),freq, channel, event->u.freq.flags);printf(" %s\n", buffer);}break;case SIOCGIWMODE:/* Note : event->u.mode is unsigned, no need to check <= 0 */if(event->u.mode >= IW_NUM_OPER_MODE)event->u.mode = IW_NUM_OPER_MODE;printf(" Mode:%s\n",iw_operation_mode[event->u.mode]);break;case SIOCGIWNAME:printf(" Protocol:%-1.16s\n", event->u.name);break;case SIOCGIWESSID:{char essid[IW_ESSID_MAX_SIZE+1];memset(essid, '\0', sizeof(essid));if((event->u.essid.pointer) && (event->u.essid.length))memcpy(essid, event->u.essid.pointer, event->u.essid.length);if(event->u.essid.flags){/* Does it have an ESSID index ? */if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)printf(" ESSID:\"%s\" [%d]\n", essid,(event->u.essid.flags & IW_ENCODE_INDEX));elseprintf(" ESSID:\"%s\"\n", essid);}elseprintf(" ESSID:off/any/hidden\n");}break;case SIOCGIWENCODE:{unsigned char key[IW_ENCODING_TOKEN_MAX];if(event->u.data.pointer)memcpy(key, event->u.data.pointer, event->u.data.length);elseevent->u.data.flags |= IW_ENCODE_NOKEY;printf(" Encryption key:");if(event->u.data.flags & IW_ENCODE_DISABLED)printf("off\n");else{/* Display the key */iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,event->u.data.flags);printf("%s", buffer);/* Other info... */if((event->u.data.flags & IW_ENCODE_INDEX) > 1)printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);if(event->u.data.flags & IW_ENCODE_RESTRICTED)printf(" Security mode:restricted");if(event->u.data.flags & IW_ENCODE_OPEN)printf(" Security mode:open");printf("\n");}}break;case SIOCGIWRATE:if(state->val_index == 0)printf(" Bit Rates:");elseif((state->val_index % 5) == 0)printf("\n ");elseprintf("; ");iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);printf("%s", buffer);/* Check for termination */if(stream->value == NULL){printf("\n");state->val_index = 0;}elsestate->val_index++;break;case SIOCGIWMODUL:{unsigned int modul = event->u.param.value;int i;int n = 0;printf(" Modulations :");for(i = 0; i < IW_SIZE_MODUL_LIST; i++){if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask){if((n++ % 8) == 7)printf("\n ");elseprintf(" ; ");printf("%s", iw_modul_list[i].cmd);}}printf("\n");}break;case IWEVQUAL:iw_print_stats(buffer, sizeof(buffer),&event->u.qual, iw_range, has_range);printf(" %s\n", buffer);break;
#ifndef WE_ESSENTIALcase IWEVGENIE:/* Informations Elements are complex, let's do only some of them */iw_print_gen_ie(event->u.data.pointer, event->u.data.length);break;
#endif /* WE_ESSENTIAL */case IWEVCUSTOM:{char custom[IW_CUSTOM_MAX+1];if((event->u.data.pointer) && (event->u.data.length))memcpy(custom, event->u.data.pointer, event->u.data.length);custom[event->u.data.length] = '\0';printf(" Extra:%s\n", custom);}break;default:printf(" (Unknown Wireless Token 0x%04X)\n",event->cmd);} /* switch(event->cmd) */
}
可以看到分类打印,存在的则变换格式后直接打印,其它则信息分别调用了下列函数。
iw_saether_ntop //获取ethernet的mac地址
iw_print_freq //获取频率
iw_print_key //获取加密key
iw_print_bitrate //获取bit速率
iw_print_stats //获取无线状态
wireless-tools源码分析-iwlist相关推荐
- Spring Developer Tools 源码分析:二、类路径监控
在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...
- kazoo源码分析:Zookeeper客户端start概述
kazoo源码分析 kazoo-2.6.1 kazoo客户端 kazoo是一个由Python编写的zookeeper客户端,实现了zookeeper协议,从而提供了Python与zookeeper服务 ...
- kubeadm源码分析(内含kubernetes离线包,三步安装)
k8s离线安装包 三步安装,简单到难以置信 kubeadm源码分析 说句实在话,kubeadm的代码写的真心一般,质量不是很高. 几个关键点来先说一下kubeadm干的几个核心的事: kubeadm ...
- 《深入理解Spark:核心思想与源码分析》——1.2节Spark初体验
本节书摘来自华章社区<深入理解Spark:核心思想与源码分析>一书中的第1章,第1.2节Spark初体验,作者耿嘉安,更多章节内容可以访问云栖社区"华章社区"公众号查看 ...
- soundtouch源码分析__based on csdn :
1. soundtouch介绍和相关资源 The SoundTouch Library Copyright © Olli Parviainen 2001-2014 SoundTouch is an o ...
- linux nDPI 协议检测 源码分析
关于nDPI的基本功能就不在这介绍了,有兴趣了解的读者可以阅读官方的快速入门指南:https://github.com/ntop/nDPI/blob/dev/doc/nDPI_QuickStartGu ...
- java 源码分析_Java 源代码编译成 Class 文件的过程分析
原标题:Java 源代码编译成 Class 文件的过程分析 在上篇文章< Java三种编译方式:前端编译 JIT编译 AOT编译 >中了解到了它们各有什么优点和缺点,以及前端编译+JIT编 ...
- 【Android 插件化】VirtualApp 源码分析 ( 添加应用源码分析 | LaunchpadAdapter 适配器 | 适配器添加元素 | PackageAppData 元素 )
文章目录 一.添加应用源码分析 1.LaunchpadAdapter 适配器 2.适配器添加元素 3.PackageAppData 元素 一.添加应用源码分析 1.LaunchpadAdapter 适 ...
- zg手册 之 python2.7.7源码分析(1)-- python中的对象
为什么80%的码农都做不了架构师?>>> 源代码主要目录结构 Demo: python 的示例程序 Doc: 文档 Grammar: 用BNF的语法定义了Python的全部语法 ...
- PostgreSQL源码分析
PostgreSQL源码结构 PostgreSQL的使用形态 PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信 ...
最新文章
- python isinstance函数判断object的类型
- Android之ASD组件(一)
- 解决Eclipse中文乱码的方法
- android 再按一次退出程序
- python 读取excel表数据获取坐标_python读取并定位excel数据坐标系详解
- java对象与c网络语言通信,JAVA与C语言的网络通信代码案例.pdf
- Membership学习(二)membership入门[xgluxv]
- flask+apache2+ubuntu
- php 获取域名前缀,PHP获取域名方法
- MT666数字程序测试
- 守望先锋为何如此火爆
- Asp.net学习过程分解(学习路线)
- word-wrap和word-break
- Google搜索又变聪明了 Baidu你还能HOLD住吗
- VC++公安指纹识别系统
- 产品目标拆解:结构化思维
- 汽车软件合作开发中的分工、知识产权及质量责任
- Redis大Key优化
- 元宇宙的隐私保护:技术与监管
- 4.加载FeatureLayer
热门文章
- VC6-VC2008转移到VC2015问题记录
- 关于mac的open命令
- linux系统国产制图软件,国产操作系统也能用的国产图表绘制软件,替代Visio就用它了...
- 计算机体系结构与组成的区别
- android 模拟器 安装,夜神安卓模拟器安装环境
- 警方耗时19天抓捕了摄像头破解软件黑产,但你还要知道这些才能放心
- 无代码编程的兴起:借助无代码平台,无需编写任何基础代码即可开发软件
- 【问题和解决《NLTK PYTHON》自然语言处理中文翻译版中的一处代码错误
- java执行Sql脚本
- Linux常用命令,Linux常用基本命令大全