iwlibs.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 # Python WiFi -- a library to access wireless card properties via Python
00003 # Copyright (C) 2004 - 2008 R�man Joost
00004 # Copyright (C) 2008 - 2009 Sean Robinson
00005 #
00006 # Contributions from:
00007 #   Mike Auty <m.auty@softhome.net> (Iwscanresult, Iwscan)
00008 #
00009 #    This library is free software; you can redistribute it and/or
00010 #    modify it under the terms of the GNU Lesser General Public License
00011 #    as published by the Free Software Foundation; either version 2.1 of
00012 #    the License, or (at your option) any later version.
00013 #
00014 #    This library is distributed in the hope that it will be useful, but
00015 #    WITHOUT ANY WARRANTY; without even the implied warranty of
00016 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017 #    Lesser General Public License for more details.
00018 #
00019 #    You should have received a copy of the GNU Lesser General Public
00020 #    License along with this library; if not, write to the Free Software
00021 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022 #    USA
00023 
00024 import struct
00025 import array
00026 import math
00027 import errno
00028 import fcntl
00029 import os
00030 import socket
00031 import time
00032 import re
00033 
00034 from . import flags as wifi_flags
00035 from types import StringType, IntType, TupleType
00036 
00037 
00038 KILO = 10**3
00039 MEGA = 10**6
00040 GIGA = 10**9
00041 
00042 
00043 def getNICnames():
00044     """ Extract network device names from /proc/net/dev.
00045 
00046         Returns list of device names.  Returns empty list if no network
00047         devices are present.
00048 
00049         >>> getNICnames()
00050         ['lo', 'eth0']
00051 
00052     """
00053     device = re.compile('[a-z]{2,}[0-9]*:')
00054     ifnames = []
00055 
00056     fp = open('/proc/net/dev', 'r')
00057     for line in fp:
00058         try:
00059             # append matching pattern, without the trailing colon
00060             ifnames.append(device.search(line).group()[:-1])
00061         except AttributeError:
00062             pass
00063     return ifnames
00064 
00065 def getWNICnames():
00066     """ Extract wireless device names from /proc/net/wireless.
00067 
00068         Returns empty list if no devices are present.
00069 
00070         >>> getWNICnames()
00071         ['eth1', 'wifi0']
00072 
00073     """
00074     device = re.compile('[a-z]{2,}[0-9]*:')
00075     ifnames = []
00076 
00077     fp = open('/proc/net/wireless', 'r')
00078     for line in fp:
00079         try:
00080             # append matching pattern, without the trailing colon
00081             ifnames.append(device.search(line).group()[:-1])
00082         except AttributeError:
00083             pass
00084     # if we couldn't lookup the devices, try to ask the kernel
00085     if ifnames == []:
00086         ifnames = getConfiguredWNICnames()
00087 
00088     return ifnames
00089 
00090 def getConfiguredWNICnames():
00091     """ Get the *configured* ifnames by a systemcall.
00092 
00093        >>> getConfiguredWNICnames()
00094        []
00095 
00096     """
00097     iwstruct = Iwstruct()
00098     ifnames = []
00099     buff = array.array('c', '\0'*1024)
00100     caddr_t, length = buff.buffer_info()
00101     datastr = iwstruct.pack('iP', length, caddr_t)
00102     result = iwstruct._fcntl(wifi_flags.SIOCGIFCONF, datastr)
00103     # get the interface names out of the buffer
00104     for i in range(0, 1024, 32):
00105         ifname = buff.tostring()[i:i+32]
00106         ifname = struct.unpack('32s', ifname)[0]
00107         ifname = ifname.split('\0', 1)[0]
00108         if ifname:
00109             # verify if ifnames are really wifi devices
00110             wifi = Wireless(ifname)
00111             try:
00112                 result = wifi.getAPaddr()
00113             except IOError, (errno, strerror):
00114                 # don't stop on an individual error
00115                 pass
00116             if result[0] == 0:
00117                 ifnames.append(ifname)
00118     return ifnames
00119 
00120 def makedict(**kwargs):
00121     return kwargs
00122 
00123 def hex2int(hexstring):
00124     """ Convert hex string to integer. """
00125     return int(hexstring, 16)
00126 
00127 
00128 class Wireless(object):
00129     """ Provides high-level access to wireless interfaces.
00130 
00131         This class uses WirelessInfo for most access.
00132 
00133     """
00134 
00135     def __init__(self, ifname):
00136         self.sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
00137         self.ifname = ifname
00138         self.iwstruct = Iwstruct()
00139         self.wireless_info = WirelessInfo(self.ifname)
00140 
00141     def getAPaddr(self):
00142         """ Returns the access point MAC address.
00143 
00144             >>> from iwlibs import Wireless, getNICnames
00145             >>> ifnames = getNICnames()
00146             >>> ifnames
00147             ['eth1', 'wifi0']
00148             >>> wifi = Wireless(ifnames[0])
00149             >>> wifi.getAPaddr()
00150             '00:0D:88:8E:4E:93'
00151 
00152             Test with non-wifi card:
00153             >>> wifi = Wireless('eth0')
00154             >>> wifi.getAPaddr()
00155             (95, 'Operation not supported')
00156 
00157             Test with non-existant card:
00158             >>> wifi = Wireless('eth2')
00159             >>> wifi.getAPaddr()
00160             (19, 'No such device')
00161 
00162         """
00163         return self.wireless_info.getAPaddr()
00164 
00165     def setAPaddr(self, addr):
00166         """ Sets the access point MAC address.
00167 
00168             translated from iwconfig.c
00169             
00170             FIXME: This needs to check address type before acting.
00171 
00172         """
00173         addr = addr.upper()
00174         if (addr == "AUTO" or addr == "ANY"):
00175             mac_addr = "\xFF"*wifi_flags.ETH_ALEN
00176         elif addr == "OFF":
00177             mac_addr = '\x00'*wifi_flags.ETH_ALEN
00178         else:
00179             if ":" not in addr:
00180                 # not a hardware address
00181                 raise IOError(errno.ENOSYS, os.strerror(errno.ENOSYS))
00182             mac_addr = "%c%c%c%c%c%c" % tuple(map(hex2int, addr.split(':')))
00183 
00184         iwreq = self.iwstruct.pack("H14s", 1, mac_addr)
00185         status, result = self.iwstruct.iw_set_ext(self.ifname,
00186                                                wifi_flags.SIOCSIWAP,
00187                                                iwreq)
00188 
00189     def _formatBitrate(self, raw_bitrate):
00190         """ Returns formatted bitrate.
00191 
00192             'raw_bitrate' -- long -- The unformatted bitrate as a long integer.
00193 
00194         """
00195         if raw_bitrate >= GIGA:
00196             return "%g Gb/s" % (float(raw_bitrate)/GIGA)
00197         if raw_bitrate >= MEGA:
00198             return "%g Mb/s" % (float(raw_bitrate)/MEGA)
00199         if raw_bitrate >= KILO:
00200             return "%g kb/s" % (float(raw_bitrate)/KILO)
00201 
00202     def getBitrate(self):
00203         """ Returns the device's currently set bit rate in Mbit.
00204 
00205             >>> from iwlibs import Wireless
00206             >>> wifi = Wireless('eth1')
00207             >>> wifi.getBitrate()
00208             '11 Mb/s'
00209 
00210         """
00211         iwparam = self.wireless_info.getBitrate()
00212         return self._formatBitrate(iwparam.value)
00213 
00214     def getBitrates(self):
00215         """ Returns the number of bitrates available for the device.
00216 
00217             >>> from iwlibs import Wireless
00218             >>> wifi = Wireless('eth1')
00219             >>> num, rates = wifi.getBitrates()
00220             >>> num == len(rates)
00221             True
00222 
00223         """
00224         num_bitrates, bitrates = self.wireless_info.getBitrates()
00225         cooked_rates = []
00226         for rate in bitrates:
00227             cooked_rates.append(self._formatBitrate(rate))
00228         return (num_bitrates, cooked_rates)
00229 
00230     def _formatFrequency(self, raw_frequency):
00231         """ Returns formatted frequency.
00232 
00233             'raw_frequency' -- long -- The unformatted frequency as a long
00234                 integer.
00235 
00236         """
00237         raw_frequency = float(raw_frequency)
00238         if raw_frequency >= GIGA:
00239             return "%0.3f GHz" % (raw_frequency/GIGA)
00240         if raw_frequency >= MEGA:
00241             return "%0.3f MHZ" % (raw_frequency/MEGA)
00242         if raw_frequency >= KILO:
00243             return "%0.3f kHz" % (raw_frequency/KILO)
00244         # This is probably a channel number
00245         raw_frequency = int(raw_frequency)
00246         try:
00247             return self.getChannelInfo()[1][raw_frequency-1]
00248         except IndexError:
00249             # probably auto (i.e. -1 (a.k.a. 255))
00250             pass
00251         return raw_frequency
00252 
00253     def getChannelInfo(self):
00254         """ Returns the number of channels and available frequencies for
00255            the device.
00256 
00257             >>> from iwlibs import Wireless
00258             >>> wifi = Wireless('eth1')
00259             >>> num, rates = wifi.getChannelInfo()
00260             >>> num == len(rates)
00261             True
00262 
00263         """
00264         iwrange = Iwrange(self.ifname)
00265         frequencies = []
00266         for freq in iwrange.frequencies:
00267             frequencies.append(self._formatFrequency(freq))
00268         return (iwrange.num_channels, frequencies)
00269 
00270     def getEssid(self):
00271         """ Returns the current ESSID information.
00272 
00273             >>> from iwlibs import Wireless
00274             >>> wifi = Wireless('eth1')
00275             >>> wifi.getEssid()
00276             'romanofski'
00277 
00278         """
00279         return self.wireless_info.getEssid()
00280 
00281     def setEssid(self, essid):
00282         """ Sets the ESSID.
00283 
00284             >>> from iwlibs import Wireless
00285             >>> wifi = Wireless('eth1')
00286             >>> wifi.getEssid()
00287             'romanofski'
00288             >>> wifi.setEssid('Joost')
00289             >>> wifi.getEssid()
00290             'Joost'
00291 
00292         """
00293         if len(essid) > wifi_flags.IW_ESSID_MAX_SIZE:
00294             raise OverflowError(errno.EOVERFLOW, os.strerror(errno.EOVERFLOW))
00295         iwpoint = Iwpoint(essid, 1)
00296         status, result = self.iwstruct.iw_set_ext(self.ifname,
00297                                              wifi_flags.SIOCSIWESSID,
00298                                              data=iwpoint.packed_data)
00299 
00300     def getEncryption(self):
00301         """ Get the association mode, which is probably a string of '*',
00302             'open', 'private', 'off'.
00303 
00304             As a normal user, you will get an 'Operation not permitted'
00305             error:
00306 
00307             >>> from iwlibs import Wireless
00308             >>> wifi = Wireless('eth1')
00309             >>> wifi.getEncryption()
00310             (1, 'Operation not permitted')
00311 
00312         """
00313         # use an IW_ENCODING_TOKEN_MAX-cell array of NULLs
00314         #   as space for ioctl to write encryption info
00315         iwpoint = Iwpoint('\x00'*wifi_flags.IW_ENCODING_TOKEN_MAX)
00316         status, result = self.iwstruct.iw_get_ext(self.ifname,
00317                                              wifi_flags.SIOCGIWENCODE,
00318                                              data=iwpoint.packed_data)
00319         iwpoint.update(result)
00320 
00321         if iwpoint.flags & wifi_flags.IW_ENCODE_NOKEY > 0:
00322             return '**'*iwpoint.length
00323         elif iwpoint.flags & wifi_flags.IW_ENCODE_OPEN > 0:
00324             return 'open'
00325         elif iwpoint.flags & wifi_flags.IW_ENCODE_RESTRICTED > 0:
00326             return 'restricted'
00327         elif iwpoint.flags & wifi_flags.IW_ENCODE_DISABLED > 0:
00328             return 'off'
00329 
00330     def setEncryption(self, mode):
00331         """ Set the association mode.
00332 
00333             As a normal user, you will get an 'Operation not permitted'
00334             error:
00335 
00336             >>> from iwlibs import Wireless
00337             >>> wifi = Wireless('eth1')
00338             >>> wifi.setEncryption()
00339             (1, 'Operation not permitted')
00340 
00341         """
00342         if type(mode) == IntType:
00343             mode = mode
00344         else:
00345             mode = mode.upper()
00346         numeric_mode = self.getEncryption(symbolic=False)
00347         # turn off all associate modes, but do not touch other flag bits
00348         numeric_mode = numeric_mode & ~wifi_flags.IW_ENCODE_OPEN \
00349                         & ~wifi_flags.IW_ENCODE_RESTRICTED \
00350                         & ~wifi_flags.IW_ENCODE_DISABLED
00351         if (mode == 'OPEN') or (mode == wifi_flags.IW_ENCODE_OPEN):
00352             numeric_mode = numeric_mode | wifi_flags.IW_ENCODE_OPEN
00353         elif (mode == 'RESTRICTED') or (mode == wifi_flags.IW_ENCODE_RESTRICTED):
00354             numeric_mode = numeric_mode | wifi_flags.IW_ENCODE_RESTRICTED
00355         elif (mode == 'OFF') or (mode == wifi_flags.IW_ENCODE_DISABLED):
00356             numeric_mode = numeric_mode | wifi_flags.IW_ENCODE_DISABLED
00357         iwpoint = Iwpoint('\x00'*wifi_flags.IW_ENCODING_TOKEN_MAX, numeric_mode)
00358         status, result = self.iwstruct.iw_get_ext(self.ifname,
00359                                              wifi_flags.SIOCSIWENCODE,
00360                                              data=iwpoint.packed_data)
00361 
00362     def getKey(self, key=0, formatted=True):
00363         """ Get an encryption key.
00364 
00365             key 0 is current key, otherwise, retrieve specific key (1-4)
00366 
00367             As a normal user, you will get an 'Operation not permitted'
00368             error:
00369 
00370             >>> from iwlibs import Wireless
00371             >>> wifi = Wireless('eth1')
00372             >>> wifi.getKey()
00373             ABCD-9512-34
00374 
00375         """
00376         iwpoint = self.wireless_info.getKey(key)
00377 
00378         # build a list of each char in key
00379         raw_key = map(ord, iwpoint.buff.tolist())[:iwpoint.length]
00380         if sum(raw_key) == 0:
00381             return "off"
00382         if not formatted:
00383             return raw_key
00384 
00385         # format key in standard form
00386         key = "%.2X" % raw_key[0]
00387         for i in range(1, iwpoint.length):
00388             if ( i & 0x1 ) == 0:
00389                     key = key + '-'
00390             key = key + "%.2X" % raw_key[i]
00391         return key
00392 
00393     def setKey(self, key, index=1):
00394         """ Set an encryption key.
00395 
00396             As a normal user, you will get an 'Operation not permitted'
00397             error:
00398 
00399             >>> from iwlibs import Wireless
00400             >>> wifi = Wireless('eth1')
00401             >>> wifi.setKey()
00402 
00403         """
00404         if index not in range(1, wifi_flags.IW_ENCODE_INDEX):
00405             raise IndexError
00406 
00407         if key:
00408             cooked_key = ''
00409             for i in range(0, len(key), 2):
00410                 cooked_key = cooked_key + chr(hex2int(key[i:i+2]))
00411         else:
00412             raw_key = self.getKey(index, False)
00413             cooked_key = map(chr, raw_key)
00414 
00415         iwpoint = Iwpoint(cooked_key,
00416                     index + wifi_flags.IW_ENCODE_ENABLED)
00417         status, result = self.iwstruct.iw_get_ext(self.ifname,
00418                                              wifi_flags.SIOCSIWENCODE,
00419                                              data=iwpoint.packed_data)
00420 
00421     def getKeys(self):
00422         """ Get all encryption keys.
00423 
00424             Returns a list of tuples.
00425 
00426             As a normal user, you will get a 'Operation not permitted'
00427             error:
00428 
00429             >>> from iwlibs import Wireless
00430             >>> wifi = Wireless('eth1')
00431             >>> wifi.getKeys()
00432             [(1, '1234-5678-91'), (2, None), (3, 'ABCD-EFAB-CD'), (4, None)]
00433 
00434         """
00435         iwrange = Iwrange(self.ifname);
00436         keys = []
00437         if iwrange.max_encoding_tokens > 0:
00438             for i in range(1, iwrange.max_encoding_tokens+1):
00439                 keys.append((i, self.getKey(i)))
00440         return keys
00441 
00442     def getFragmentation(self):
00443         """ Returns the fragmentation threshold.
00444 
00445             It depends on what the driver says. If you have fragmentation
00446             threshold turned on, you'll get an int. If it's turned off
00447             you'll get a string: 'off'.
00448 
00449             >>> from iwlibs import Wireless
00450             >>> wifi = Wireless('eth1')
00451             >>> wifi.getFragmentation()
00452             'off'
00453 
00454         """
00455         iwparam = self.wireless_info.getFragmentation()
00456         if iwparam.disabled:
00457             return "off"
00458         return iwparam.value
00459 
00460     def getFrequency(self):
00461         """ Returns currently set frequency of the card.
00462 
00463             >>> from iwlibs import Wireless
00464             >>> wifi = Wireless('eth1')
00465             >>> wifi.getFrequency()
00466             '2.417 GHz'
00467 
00468         """
00469         iwfreq = self.wireless_info.getFrequency()
00470         return self._formatFrequency(iwfreq.getFrequency())
00471 
00472     def setFrequency(self, freq):
00473         """ Sets the frequency on the card.
00474 
00475            translated from iwconfig.c
00476 
00477         """
00478         format = "lhBB"
00479         iwstruct = Iwstruct()
00480         if freq == "auto":
00481             iwreq = iwstruct.pack(format, -1, 0, 0, wifi_flags.IW_FREQ_AUTO)
00482         else:
00483             if freq == "fixed":
00484                 freq = self.getFrequency()
00485             freq_pattern = re.compile("([\d\.]+)\s?([GMk])\w?", re.I|re.M|re.S)
00486             freq_match = freq_pattern.search(freq)
00487             if freq_match is None:
00488                 # match failed, try to just find a number (no units)
00489                 freq_pattern = re.compile("([\d\.]+)", re.I|re.M|re.S)
00490                 freq_match = freq_pattern.search(freq)
00491                 freq_num, unit = (freq_match.groups()[0], "")
00492             else:
00493                 freq_num, unit = freq_match.groups()
00494             freq_num = float(freq_num)
00495             if unit == "G": freq_num = freq_num * GIGA
00496             if unit == "M": freq_num = freq_num * MEGA
00497             if unit == "k": freq_num = freq_num * KILO
00498             e = int(math.floor(math.log10(freq_num)))
00499             if e > 8:
00500                 m = int(math.floor(freq_num / math.pow(10, e - 6))) * 100
00501                 e = e - 8
00502             else:
00503                 m = int(freq_num)
00504                 e = 0
00505             iwreq = iwstruct.pack(format, m, e, 0, wifi_flags.IW_FREQ_FIXED)
00506         status, result = iwstruct.iw_set_ext(self.ifname,
00507                                                wifi_flags.SIOCSIWFREQ,
00508                                                iwreq)
00509 
00510     def getMode(self):
00511         """ Returns currently set operation mode.
00512 
00513             >>> from iwlibs import Wireless
00514             >>> wifi = Wireless('eth1')
00515             >>> wifi.getMode()
00516             'Managed'
00517 
00518         """
00519         return wifi_flags.modes[self.wireless_info.getMode()]
00520 
00521     def setMode(self, mode):
00522         """ Sets the operation mode.
00523 
00524         """
00525         this_modes = [x.lower() for x in wifi_flags.modes]
00526         mode = mode.lower()
00527         try:
00528             wifimode = this_modes.index(mode)
00529         except ValueError, detail:
00530             raise ValueError("Invalid mode")
00531         datastr = self.iwstruct.pack('I', wifimode)
00532         status, result = self.iwstruct.iw_set_ext(self.ifname,
00533                                              wifi_flags.SIOCSIWMODE,
00534                                              data=datastr)
00535 
00536     def getWirelessName(self):
00537         """ Returns the wireless name.
00538 
00539             >>> from iwlibs import Wireless
00540             >>> wifi = Wireless('eth1')
00541             >>> wifi.getWirelessName()
00542             'IEEE 802.11-DS'
00543 
00544         """
00545         return self.wireless_info.getWirelessName()
00546 
00547     def getPowermanagement(self):
00548         """ Returns the power management settings.
00549 
00550             #>>> from iwlibs import Wireless
00551             #>>> wifi = Wireless('eth1')
00552             #>>> wifi.getPowermanagement()
00553             #'off'
00554 
00555         """
00556         iwrange = Iwrange(self.ifname)
00557         iwparam = self.wireless_info.getPower()
00558         return (iwrange.pm_capa,
00559                 (iwrange.pmp_flags, iwrange.min_pmp, iwrange.max_pmp),
00560                 (iwrange.pmt_flags, iwrange.min_pmt, iwrange.max_pmt),
00561                 (iwrange.pms_flags, iwrange.min_pms, iwrange.max_pms),
00562                 iwparam)
00563 
00564     def getQualityMax(self):
00565         """ Returns an Iwquality object with maximum quality information.
00566 
00567             >>> from iwlibs import Wireless
00568             >>> wifi = Wireless('eth1')
00569             >>> mq = wifi.getQualityMax()
00570             >>> print "quality:", mq.quality, "signal:", mq.siglevel, "noise:", mq.nlevel
00571             quality: 38 signal: 13 noise: 0
00572 
00573         """
00574         iwrange = Iwrange(self.ifname)
00575         if iwrange.errorflag:
00576             return (iwrange.errorflag, iwrange.error)
00577         return iwrange.max_qual
00578 
00579     def getQualityAvg(self):
00580         """ Returns an Iwquality object with average quality information.
00581 
00582             >>> from iwlibs import Wireless
00583             >>> wifi = Wireless('eth1')
00584             >>> aq = wifi.getQualityAvg()
00585             >>> print "quality:", aq.quality, "signal:", aq.siglevel, "noise:", aq.nlevel
00586             quality: 38 signal: 13 noise: 0
00587 
00588         """
00589         iwrange = Iwrange(self.ifname)
00590         if iwrange.errorflag:
00591             return (iwrange.errorflag, iwrange.error)
00592         return iwrange.avg_qual
00593 
00594     def getRetrylimit(self):
00595         """ Returns the retry/lifetime limit.
00596 
00597             man iwconfig:
00598                 "Most cards have MAC retransmissions, and some allow to set
00599                 the behaviour of the retry mechanism."
00600 
00601             >>> from iwlibs import Wireless
00602             >>> wifi = Wireless('eth1')
00603             >>> wifi.getRetrylimit()
00604             16
00605 
00606         """
00607         iwparam = self.wireless_info.getRetry()
00608         return iwparam.value
00609 
00610     def getRTS(self):
00611         """ Returns the RTS threshold, likely to be int, 'auto',
00612             'fixed', 'off'
00613 
00614             man iwconfig:
00615                 "RTS/CTS adds a handshake before each packet transmission to
00616                 make sure that the channel is clear. This adds overhead, but
00617                 increases performance in case of hidden nodes or a large
00618                 number of active nodes. This parameter sets the size of the
00619                 smallest packet for which the node sends RTS; a value equal
00620                 to the maximum packet size disable the mechanism."
00621 
00622             >>> from iwlibs import Wireless
00623             >>> wifi = Wireless('eth1')
00624             >>> wifi.getRTS()
00625             'off'
00626 
00627         """
00628         iwparam = self.wireless_info.getRTS()
00629         if iwparam.disabled:
00630             return "off"
00631         return iwparam.value
00632 
00633     def getSensitivity(self):
00634         """ Returns sensitivity information.
00635 
00636             man iwconfig:
00637                 "This is the lowest signal level for which the hardware
00638                 attempt packet reception, signals weaker than this are
00639                 ignored. This is used to avoid receiving background noise,
00640                 so you should set it according to the average noise
00641                 level. Positive values are assumed to be the raw value used
00642                 by the hardware or a percentage, negative values are
00643                 assumed to be dBm."
00644 
00645             >>> from iwlibs import Wireless
00646             >>> wifi = Wireless('eth1')
00647             >>> wifi.getSensitivity()
00648             'off'
00649 
00650         """
00651         iwparam = self.wireless_info.getSensitivity()
00652         return iwparam.value
00653 
00654     def getTXPower(self):
00655         """ Returns the transmit power in dBm.
00656 
00657             >>> from iwlibs import Wireless
00658             >>> wifi = Wireless('eth1')
00659             >>> wifi.getTXPower()
00660             '17 dBm'
00661 
00662         """
00663         def mw2dbm(self, mwatt):
00664             """ Converts mW to dBm (float). """
00665             if mwatt == 0:
00666                 return 0
00667             return math.ceil(10.0 * math.log10(mwatt))
00668 
00669         iwparam = self.wireless_info.getTXPower()
00670         return "%i dBm" % iwparam.value
00671 
00672     def getStatistics(self):
00673         """ Returns statistics information which can also be found in
00674             /proc/net/wireless.
00675 
00676         """
00677         iwstats = Iwstats(self.ifname)
00678         if iwstats.errorflag > 0:
00679             return (iwstats.errorflag, iwstats.error)
00680         return [iwstats.status, iwstats.qual, iwstats.discard,
00681             iwstats.missed_beacon]
00682 
00683     def scan(self):
00684         """ Returns Iwscanresult objects, after a successful scan. """
00685         return Iwscan(self.ifname)
00686 
00687     def commit(self):
00688         """ Commit pending changes. """
00689         status, result = self.iwstruct.iw_set_ext(self.ifname,
00690                                                   wifi_flags.SIOCSIWCOMMIT)
00691         return (status, result)
00692 
00693 
00694 class WirelessConfig(object):
00695     """ Low level access to wireless information on a device.  This class
00696         contains only those things absolutely needed to configure a card.
00697 
00698         WirelessConfig implements the wireless_config struct in iwlib.h.
00699         It will probably never be called directly, but instead be used via
00700         WirelessInfo.
00701 
00702     """
00703 
00704     def __init__(self, ifname):
00705         self.sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
00706         self.ifname = ifname
00707         self.iwstruct = Iwstruct()
00708         #self.nwid = Iwparam
00709         self.freq_flags = 0
00710 
00711     def getWirelessName(self):
00712         """ Returns the wireless name.
00713 
00714             >>> from iwlibs import Wireless
00715             >>> wifi = Wireless('eth1')
00716             >>> wifi.getWirelessName()
00717             'IEEE 802.11-DS'
00718 
00719         """
00720         status, result = self.iwstruct.iw_get_ext(self.ifname,
00721                                              wifi_flags.SIOCGIWNAME)
00722         return result.tostring().strip('\x00')
00723 
00724     def getEncryption(self):
00725         """ Returns the encryption status.
00726 
00727             >>> from iwlibs import Wireless
00728             >>> wifi = Wireless('eth1')
00729             >>> wifi.getEncryption()
00730             'off'
00731 
00732         """
00733         # use an IW_ENCODING_TOKEN_MAX-cell array of NULLs
00734         #   as space for ioctl to write encryption info
00735         iwpoint = Iwpoint('\x00'*wifi_flags.IW_ENCODING_TOKEN_MAX)
00736         status, result = self.iwstruct.iw_get_ext(self.ifname,
00737                                              wifi_flags.SIOCGIWENCODE,
00738                                              data=iwpoint.packed_data)
00739         iwpoint.update(result)
00740 
00741         return iwpoint
00742 
00743     def getFrequency(self):
00744         """ Returns currently set frequency of the card.
00745 
00746             >>> from iwlibs import Wireless
00747             >>> wifi = Wireless('eth1')
00748             >>> wifi.getFrequency()
00749             '2.417 GHz'
00750 
00751         """
00752         status, result = self.iwstruct.iw_get_ext(self.ifname,
00753                                                   wifi_flags.SIOCGIWFREQ)
00754         return Iwfreq(result)
00755 
00756     def getKey(self, key=0):
00757         """ Get an encryption key.
00758 
00759             key 0 is current key, otherwise, retrieve specific key (1-4)
00760 
00761             As a normal user, you will get an 'Operation not permitted'
00762             error:
00763 
00764             >>> from iwlibs import Wireless
00765             >>> wifi_conf = WirelessConfig('eth1')
00766             >>> isinstance(wifi_conf.getKey(), Iwpoint)
00767             True
00768 
00769         """
00770         # use an IW_ENCODING_TOKEN_MAX-cell array of NULLs
00771         #   as space for ioctl to write encryption info
00772         iwpoint = Iwpoint('\x00'*wifi_flags.IW_ENCODING_TOKEN_MAX, key)
00773         status, result = self.iwstruct.iw_get_ext(self.ifname,
00774                                              wifi_flags.SIOCGIWENCODE,
00775                                              data=iwpoint.packed_data)
00776         iwpoint.update(result)
00777         return iwpoint
00778 
00779     def getEssid(self):
00780         """ Returns the current ESSID information.
00781 
00782             >>> from iwlibs import Wireless
00783             >>> wifi = Wireless('eth1')
00784             >>> wifi.getEssid()
00785             'romanofski'
00786 
00787         """
00788         # use an IW_ESSID_MAX_SIZE-cell array of NULLs
00789         #   as space for ioctl to write ESSID
00790         iwpoint = Iwpoint('\x00'*wifi_flags.IW_ESSID_MAX_SIZE)
00791         status, result = self.iwstruct.iw_get_ext(self.ifname,
00792                                              wifi_flags.SIOCGIWESSID,
00793                                              data=iwpoint.packed_data)
00794         raw_essid = iwpoint.buff.tostring()
00795         return raw_essid.strip('\x00')
00796 
00797     def getMode(self):
00798         """ Returns currently set operation mode.
00799 
00800             >>> from iwlibs import Wireless
00801             >>> wifi = Wireless('eth1')
00802             >>> wifi.getMode()
00803             'Managed'
00804 
00805         """
00806         status, result = self.iwstruct.iw_get_ext(self.ifname,
00807                                              wifi_flags.SIOCGIWMODE)
00808         return self.iwstruct.unpack('I', result[:4])[0]
00809 
00810 
00811 class WirelessInfo(WirelessConfig):
00812     """ Low level access to wireless extensions on a device.  This class
00813         is the exhaustive list of information for a card.
00814 
00815         WirelessInfo implements the wireless_info struct in iwlib.h.
00816         This class should be used by those needing lower-level access
00817         than Wireless provides.
00818 
00819     """
00820 
00821     def __init__(self, ifname):
00822         self.sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
00823         self.ifname = ifname
00824         self.iwstruct = Iwstruct()
00825 
00826         self.nickname = ""
00827         # Stats
00828         self.stats = Iwstats
00829         self.range = Iwrange
00830         # Auth params for WPA/802.1x/802.11i
00831         self.auth_key_mgmt = 0
00832         self.has_auth_key_mgmt = 0
00833         self.auth_cipher_pairwise = 0
00834         self.has_auth_cipher_pairwise = 0
00835         self.auth_cipher_group = 0
00836         self.has_auth_cipher_group = 0
00837         WirelessConfig.__init__(self, ifname)
00838 
00839     def getSensitivity(self):
00840         """ Returns sensitivity information.
00841 
00842             man iwconfig:
00843                 "This is the lowest signal level for which the hardware
00844                 attempt packet reception, signals weaker than this are
00845                 ignored. This is used to avoid receiving background noise,
00846                 so you should set it according to the average noise
00847                 level. Positive values are assumed to be the raw value used
00848                 by the hardware or a percentage, negative values are
00849                 assumed to be dBm."
00850 
00851             >>> from iwlibs import Wireless
00852             >>> wifi = Wireless('eth1')
00853             >>> wifi.getSensitivity()
00854             'off'
00855 
00856         """
00857         return Iwparam(self.ifname, wifi_flags.SIOCGIWSENS)
00858 
00859     def getAPaddr(self):
00860         """ Returns the access point MAC address.
00861 
00862             >>> from iwlibs import Wireless, getNICnames
00863             >>> ifnames = getNICnames()
00864             >>> ifnames
00865             ['eth1', 'wifi0']
00866             >>> wifi = Wireless(ifnames[0])
00867             >>> wifi.getAPaddr()
00868             '00:0D:88:8E:4E:93'
00869 
00870             Test with non-wifi card:
00871             >>> wifi = Wireless('eth0')
00872             >>> wifi.getAPaddr()
00873             (95, 'Operation not supported')
00874 
00875             Test with non-existant card:
00876             >>> wifi = Wireless('eth2')
00877             >>> wifi.getAPaddr()
00878             (19, 'No such device')
00879 
00880         """
00881         buff, datastr = self.iwstruct.pack_wrq(32)
00882         status, result = self.iwstruct.iw_get_ext(self.ifname,
00883                                                   wifi_flags.SIOCGIWAP,
00884                                                   data=datastr)
00885         # Extracts MAC address from packed data and returns it as a str.
00886         mac_addr = struct.unpack('xxBBBBBB', result[:8])
00887         return "%02X:%02X:%02X:%02X:%02X:%02X" % mac_addr
00888 
00889     def getBitrate(self):
00890         """ Returns the device's currently set bit rate.
00891 
00892             >>> from iwlibs import Wireless
00893             >>> wifi = Wireless('eth1')
00894             >>> wifi.getBitrate()
00895             '11 Mb/s'
00896 
00897         """
00898         return Iwparam(self.ifname, wifi_flags.SIOCGIWRATE)
00899 
00900     def getBitrates(self):
00901         """ Returns the device's number and list of available bit rates.
00902 
00903             The bit rates in the list are long integer type.
00904 
00905         """
00906         iwrange = Iwrange(self.ifname)
00907         return (iwrange.num_bitrates, iwrange.bitrates)
00908 
00909     def getRTS(self):
00910         """ Returns the RTS threshold.
00911 
00912             >>> from iwlibs import Wireless
00913             >>> wifi = Wireless('eth1')
00914             >>> wifi.getRTS()
00915             'off'
00916 
00917         """
00918         return Iwparam(self.ifname, wifi_flags.SIOCGIWRTS)
00919 
00920     def getFragmentation(self):
00921         """ Returns the fragmentation threshold.
00922 
00923             >>> from iwlibs import Wireless
00924             >>> wifi = Wireless('eth1')
00925             >>> wifi.getFragmentation()
00926             'off'
00927 
00928         """
00929         return Iwparam(self.ifname, wifi_flags.SIOCGIWFRAG)
00930 
00931     def getPower(self):
00932         """ Returns the power management settings.
00933 
00934             #>>> from iwlibs import Wireless
00935             #>>> wifi = Wireless('eth1')
00936             #>>> wifi.getPowermanagement()
00937             #'off'
00938 
00939         """
00940         return Iwparam(self.ifname, wifi_flags.SIOCGIWPOWER)
00941 
00942     def getTXPower(self):
00943         """ Returns the transmit power in dBm.
00944 
00945             >>> from iwlibs import Wireless
00946             >>> wifi = Wireless('eth1')
00947             >>> wifi.getTXPower()
00948             '17 dBm'
00949 
00950         """
00951         return Iwparam(self.ifname, wifi_flags.SIOCGIWTXPOW)
00952 
00953     def getRetry(self):
00954         """ Returns the retry/lifetime limit.
00955 
00956             man iwconfig:
00957                 "Most cards have MAC retransmissions, and some allow to set
00958                 the behaviour of the retry mechanism."
00959 
00960             >>> from iwlibs import Wireless
00961             >>> wifi = Wireless('eth1')
00962             >>> wifi.getRetrylimit()
00963             16
00964 
00965         """
00966         return Iwparam(self.ifname, wifi_flags.SIOCGIWRETRY)
00967 
00968 
00969 class Iwstruct(object):
00970     """ The basic class to handle iwstruct data. """
00971 
00972     def __init__(self):
00973         self.idx = 0
00974         self.sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
00975 
00976     def parse_data(self, fmt, data):
00977         """ Unpacks raw C data. """
00978         size = struct.calcsize(fmt)
00979         idx = self.idx
00980 
00981         datastr = data[idx:idx + size]
00982         self.idx = idx+size
00983         value = struct.unpack(fmt, datastr)
00984 
00985         # take care of a tuple like (int, )
00986         if len(value) == 1:
00987             return value[0]
00988         else:
00989             return value
00990 
00991     def pack(self, fmt, *args):
00992         """ Calls struct.pack and returns the result. """
00993         return struct.pack(fmt, *args)
00994 
00995     def pack_wrq(self, buffsize):
00996         """ Packs wireless request data for sending it to the kernel. """
00997         # Prepare a buffer
00998         # We need the address of our buffer and the size for it. The
00999         # ioctl itself looks for the pointer to the address in our
01000         # memory and the size of it.
01001         # Don't change the order how the structure is packed!!!
01002         buff = array.array('c', '\0'*buffsize)
01003         caddr_t, length = buff.buffer_info()
01004         datastr = struct.pack('Pi', caddr_t, length)
01005         return buff, datastr
01006 
01007     def pack_test(self, string, buffsize):
01008         """ Packs wireless request data for sending it to the kernel. """
01009         buffsize = buffsize - len(string)
01010         buff = array.array('c', string+'\0'*buffsize)
01011         caddr_t, length = buff.buffer_info()
01012         s = struct.pack('PHH', caddr_t, length, 1)
01013         return buff, s
01014 
01015     def unpack(self, fmt, packed_data):
01016         """ Unpacks data with given format. """
01017         return struct.unpack(fmt, packed_data)
01018 
01019     def _fcntl(self, request, args):
01020         return fcntl.ioctl(self.sockfd.fileno(), request, args)
01021 
01022     def iw_get_ext(self, ifname, request, data=None):
01023         """ Read information from ifname. """
01024         buff = wifi_flags.IFNAMSIZE-len(ifname)
01025         ifreq = array.array('c', ifname + '\0'*buff)
01026         # put some additional data behind the interface name
01027         if data is not None:
01028             ifreq.extend(data)
01029         else:
01030             # extend to 32 bytes for ioctl payload
01031             ifreq.extend('\0'*16)
01032 
01033         result = self._fcntl(request, ifreq)
01034         return (result, ifreq[wifi_flags.IFNAMSIZE:])
01035 
01036     def iw_set_ext(self, ifname, operation, data=None):
01037         """ Set options on ifname. """
01038         return self.iw_get_ext(ifname, operation, data)
01039 
01040     #def getMAC(self, packed_data):
01041         #""" Extracts MAC address from packed data and returns it as a str. """
01042         #mac_addr = struct.unpack('xxBBBBBB', packed_data[:8])
01043         #return "%02X:%02X:%02X:%02X:%02X:%02X" % mac_addr
01044 
01045 
01046 class Iwparam(object):
01047     """ Class to hold iwparam data. """
01048 
01049     def __init__(self, ifname, ioctl):
01050         # (i) value, (b) fixed, (b) disabled, (H) flags
01051         self.fmt = "ibbH"
01052         self.ifname = ifname
01053         self.ioctl = ioctl
01054         self.value = 0
01055         self.fixed = 0
01056         self.disabled = 0
01057         self.flags = 0
01058         self.update()
01059 
01060     def update(self):
01061         """ Updates Iwstruct object by a system call to the kernel
01062            and updates internal attributes.
01063 
01064         """
01065         iwstruct = Iwstruct()
01066         status, result = iwstruct.iw_get_ext(self.ifname, self.ioctl)
01067         self._parse(result)
01068 
01069     def _parse(self, data):
01070         """ Unpacks iwparam data. """
01071         iwstruct = Iwstruct()
01072         self.value, self.fixed, self.disabled, self.flags = \
01073             iwstruct.parse_data(self.fmt, data)
01074 
01075 class Iwfreq(object):
01076     """ Class to hold iwfreq data. """
01077 
01078     def __init__(self, data=None):
01079         # (i) mantissa, (h) exponent, (b) list index, (b) flags
01080         self.fmt = "ihbb"
01081         self.m = 0
01082         self.e = 0
01083         self.index = 0
01084         self.flags = 0
01085         if data:
01086             if isinstance(data, TupleType):
01087                 self.m, self.e, self.index, self.flags = data
01088             else:
01089                 self.parse(data)
01090 
01091     def parse(self, data):
01092         """ Unpacks iw_freq. """
01093         size = struct.calcsize(self.fmt)
01094         self.m, self.e, self.index, self.flags = struct.unpack(self.fmt, data[:size])
01095 
01096     def getFrequency(self):
01097         """ Returns frequency or channel, depending on the driver. """
01098         if self.e == 0:
01099             return self.m
01100         else:
01101             return self.m*10**self.e
01102 
01103     def setFrequency(self, value):
01104         """ Sets mantissa and exponent from given frequency (or channel). """
01105         if value % GIGA == 0:
01106             self.e = 9
01107         if value % MEGA == 0:
01108             self.e = 6
01109         if value % KILO == 0:
01110             self.e = 3
01111         else:
01112             self.e = 0
01113         self.m = value / 10**self.e
01114 
01115 
01116 class Iwstats(object):
01117     """ Class to hold iwstat data. """
01118 
01119     def __init__(self, ifname):
01120         # (2B) status, 4B iw_quality, 6i iw_discarded
01121         self.fmt = "2B4B6i"
01122         self.status = 0
01123         self.qual = Iwquality()
01124         self.discard = {}
01125         self.missed_beacon = 0
01126         self.ifname = ifname
01127         self.errorflag = 0
01128         self.error = ""
01129         self.update()
01130 
01131     def update(self):
01132         """ Updates Iwstats object by a system call to the kernel
01133             and updates internal attributes.
01134 
01135         """
01136         iwstruct = Iwstruct()
01137         buff, s = iwstruct.pack_wrq(32)
01138         i, result = iwstruct.iw_get_ext(self.ifname,
01139                                         wifi_flags.SIOCGIWSTATS,
01140                                         data=s)
01141         if i > 0:
01142             self.error = result
01143             self.errorflag = i
01144         self._parse(buff.tostring())
01145 
01146     def _parse(self, data):
01147         """ Unpacks iwstruct data. """
01148         iwstruct = Iwstruct()
01149         iwqual = Iwquality()
01150         iwstats_data = iwstruct.parse_data(self.fmt, data)
01151 
01152         self.status = iwstats_data[0:2]
01153         self.qual.quality, self.qual.siglevel, self.qual.nlevel, \
01154             self.qual.updated = iwstats_data[2:6]
01155         nwid, code, frag, retries, iwflags = iwstats_data[6:11]
01156         self.missed_beacon = iwstats_data[11:12][0]
01157         self.discard = makedict(nwid=nwid, code=code,
01158             fragment=frag, retries=retries, misc=iwflags)
01159 
01160 
01161 class Iwquality(object):
01162     """ Class to hold iwquality data. """
01163 
01164     def __init__(self):
01165         self.quality = 0
01166         self.siglevel = 0
01167         self.nlevel = 0
01168         self.updated = 0
01169         self.fmt = "4B"
01170 
01171     def parse(self, data):
01172         """ Unpacks iwquality data. """
01173         iwstruct = Iwstruct()
01174         qual, siglevel, nlevel, iwflags = iwstruct.parse_data(self.fmt, data)
01175 
01176         # compute signal and noise level
01177         self.siglevel = siglevel
01178         self.nlevel = nlevel
01179 
01180         # asign the other values
01181         self.quality = qual
01182         self.updated = iwflags
01183 
01184     def setValues(self, vallist):
01185         """ Assigns values given by a list to our attributes. """
01186         attributes = ["quality", "siglevel", "nlevel", "updated"]
01187         assert len(vallist) == 4
01188 
01189         for i in range(len(vallist)):
01190             setattr(self, attributes[i], vallist[i])
01191 
01192     def getSignallevel(self):
01193         """ Returns signal level. """
01194         return self.siglevel
01195 
01196     def setSignallevel(self, siglevel):
01197         """ Sets signal level. """
01198         self.siglevel = siglevel
01199     signallevel = property(getSignallevel, setSignallevel)
01200 
01201     def getNoiselevel(self):
01202         """ Returns noise level. """
01203         return self.nlevel
01204 
01205     def setNoiselevel(self, val):
01206         # currently not implemented
01207         # XXX
01208         self.nlevel = val
01209     noiselevel = property(getNoiselevel, setNoiselevel)
01210 
01211 
01212 class Iwpoint(object):
01213     """ Class to hold iw_point data. """
01214 
01215     def __init__(self, data=None, flags=0):
01216         if data is None:
01217             raise ValueError, "data must be passed to Iwpoint"
01218         # P pointer to data, H length, H flags
01219         self.fmt = 'PHH'
01220         self.flags = flags
01221         self.buff = array.array('c', data)
01222         self.caddr_t, self.length = self.buff.buffer_info()
01223         self.packed_data = struct.pack(self.fmt, self.caddr_t,
01224                                        self.length, self.flags)
01225 
01226     def update(self, packed_data):
01227         """ Updates the object attributes. """
01228         self.packed_data = packed_data
01229         self.caddr_t, self.length, self.flags = struct.unpack(self.fmt,
01230                                                               self.packed_data)
01231 
01232 
01233 class Iwrange(object):
01234     """ Holds iwrange struct. """
01235 
01236     def __init__(self, ifname):
01237         self.fmt = "IIIHB6Ii4B4BB" + wifi_flags.IW_MAX_BITRATES*"i" + \
01238                    "2i2i2i2i3H" + wifi_flags.IW_MAX_ENCODING_SIZES*"H" + \
01239                    "2BBHB" + wifi_flags.IW_MAX_TXPOWER*"i" + \
01240                    "2B3H2i2iHB" + wifi_flags.IW_MAX_FREQUENCIES*"ihBB" + \
01241                    "IiiHiI"
01242 
01243         self.ifname = ifname
01244         self.errorflag = 0
01245         self.error = ""
01246 
01247         # informative stuff
01248         self.throughput = 0
01249 
01250         # nwid (or domain id)
01251         self.min_nwid = self.max_nwid = 0
01252 
01253         # frequency for backward compatibility
01254         self.old_num_channels = self.old_num_frequency = self.old_freq = 0
01255 
01256         # signal level threshold
01257         self.sensitivity = 0
01258 
01259         # link quality
01260         self.max_qual = Iwquality()
01261         self.avg_qual = Iwquality()
01262 
01263         # rates
01264         self.num_bitrates = 0
01265         self.bitrates = []
01266 
01267         # rts threshold
01268         self.min_rts = self.max_rts = 0
01269 
01270         # fragmention threshold
01271         self.min_frag = self.max_frag = 0
01272 
01273         # power managment
01274         self.min_pmp = self.max_pmp = 0
01275         self.min_pmt = self.max_pmt = 0
01276         self.pmp_flags = self.pmt_flags = self.pm_capa = 0
01277 
01278         # encoder stuff
01279         self.encoding_size = 0
01280         self.num_encoding_sizes = self.max_encoding_tokens = 0
01281         self.encoding_login_index = 0
01282 
01283         # transmit power
01284         self.txpower_capa = self.num_txpower = self.txpower = 0
01285 
01286         # wireless extension version info
01287         self.we_vers_compiled = self.we_vers_src = 0
01288 
01289         # retry limits and lifetime
01290         self.retry_capa = self.retry_flags = self.r_time_flags = 0
01291         self.min_retry = self.max_retry = 0
01292         self.min_r_time = self.max_r_time = 0
01293 
01294         # frequency
01295         self.num_channels = self.num_frequency = 0
01296         self.frequencies = []
01297 
01298         # capabilities and power management
01299         self.enc_capa = 0
01300         self.min_pms = self.max_pms = self.pms_flags = 0
01301         self.modul_capa = 0
01302         self.bitrate_capa = 0
01303 
01304         self.update()
01305 
01306     def update(self):
01307         """ Updates Iwrange object by a system call to the kernel
01308             and updates internal attributes.
01309 
01310         """
01311         iwstruct = Iwstruct()
01312         buff, s = iwstruct.pack_wrq(640)
01313         status, result = iwstruct.iw_get_ext(self.ifname,
01314                                         wifi_flags.SIOCGIWRANGE,
01315                                         data=s)
01316         data = buff.tostring()
01317         self._parse(data)
01318 
01319     def _parse(self, data):
01320         iwstruct = Iwstruct()
01321         result = iwstruct.parse_data(self.fmt, data)
01322 
01323         # XXX there is maybe a much more elegant way to do this
01324         self.throughput, self.min_nwid, self.max_nwid = result[0:3]
01325         self.old_num_channels, self.old_num_frequency = result[3:5]
01326         self.old_freq = result[5:11]
01327         self.sensitivity = result[11]
01328         self.max_qual.setValues(result[12:16])
01329         self.avg_qual.setValues(result[16:20])
01330         self.num_bitrates = result[20]
01331         raw_bitrates = result[21:21+self.num_bitrates]
01332         for rate in raw_bitrates:
01333             if rate is not None:
01334                 self.bitrates.append(rate)
01335 
01336         self.min_rts, self.max_rts = result[53:55]
01337         self.min_frag, self.max_frag = result[55:57]
01338         self.min_pmp, self.max_pmp = result[57:59]
01339         self.min_pmt, self.max_pmt = result[59:61]
01340         self.pmp_flags, self.pmt_flags, self.pm_capa = result[61:64]
01341         self.encoding_size = result[64:72]
01342         self.num_encoding_sizes, self.max_encoding_tokens = result[72:74]
01343         self.encoding_login_index = result[74]
01344         self.txpower_capa, self.num_txpower = result[75:77]
01345         self.txpower = result[77:85]
01346         self.we_vers_compiled, self.we_vers_src = result[85:87]
01347         self.retry_capa, self.retry_flags, self.r_time_flags = result[87:90]
01348         self.min_retry, self.max_retry = result[90:92]
01349         self.min_r_time, self.max_r_time = result[92:94]
01350         self.num_channels = result[94]
01351         self.num_frequency = result[95]
01352 
01353         freq = result[96:224]
01354         i = self.num_frequency
01355         for x in range(0, len(freq), 4):
01356             iwfreq = Iwfreq(freq[x:x+4])
01357             fq = iwfreq.getFrequency()
01358             if fq is not None:
01359                 self.frequencies.append(fq)
01360             i -= 1
01361             if i <= 0:
01362                 break
01363         self.enc_capa = result[224]
01364         self.min_pms = result[225]
01365         self.max_pms = result[226]
01366         self.pms_flags = result[227]
01367         self.modul_capa = result[228]
01368         self.bitrate_capa = result[229]
01369 
01370 
01371 class Iwscan(object):
01372     """ Class to handle AP scanning. """
01373 
01374     def __init__(self, ifname, fullscan=True):
01375         """ Completes a scan for available access points,
01376             and returns them in Iwscanresult format.
01377 
01378            fullscan: If False, data is read from a cache of the last scan
01379                      If True, a scan is conducted, and then the data is read
01380 
01381         """
01382         self.ifname = ifname
01383         self.range = Iwrange(ifname)
01384         self.stream = None
01385         self.aplist = None
01386         self.index = -1
01387 
01388         if fullscan:
01389             # Triggers the scan
01390             iwstruct = Iwstruct()
01391             datastr = iwstruct.pack("Pii", 0, 0, 0)
01392             status, result = iwstruct.iw_set_ext(self.ifname,
01393                                                 wifi_flags.SIOCSIWSCAN,
01394                                                 datastr)
01395             self.getScan()
01396 
01397     def __iter__(self):
01398         return self
01399 
01400     def __len__(self):
01401         return len(self.aplist)
01402 
01403     def next(self):
01404         self.index = self.index + 1
01405         if self.index > len(self.aplist) - 1:
01406             raise StopIteration
01407         return self.aplist[self.index]
01408 
01409     def getScan(self):
01410         """ Retrieves results, stored from the most recent scan.
01411 
01412         """
01413         iwstruct = Iwstruct()
01414         bufflen = wifi_flags.IW_SCAN_MAX_DATA
01415 
01416         # Make repeated requests for scan with various recovery schemes
01417         while (True):
01418             buff, datastr = iwstruct.pack_wrq(bufflen)
01419             try:
01420                 status, result = iwstruct.iw_get_ext(self.ifname,
01421                                                 wifi_flags.SIOCGIWSCAN,
01422                                                 data=datastr)
01423             except IOError, (error_number, error_string):
01424                 if error_number == errno.E2BIG:
01425                     # Keep resizing the buffer until it's
01426                     #   large enough to hold the scan
01427                     pbuff, newlen = iwstruct.unpack('Pi', datastr)
01428                     if bufflen < newlen:
01429                         # the driver told us how big to make the buffer
01430                         bufflen = newlen
01431                     else:
01432                         # try doubling the buffer size
01433                         bufflen = bufflen * 2
01434                 elif error_number == errno.EAGAIN:
01435                     # Permission was NOT denied,
01436                     #   therefore we must WAIT to get results
01437                     time.sleep(0.1)
01438                 else:
01439                     raise
01440             except:
01441                 raise
01442             else:
01443                 break
01444 
01445         # unpack the buffer pointer and length
01446         pbuff, reslen = iwstruct.unpack('Pi', datastr)
01447         if reslen > 0:
01448             # Initialize the stream, and turn it into an enumerator
01449             self.aplist = self._parse(buff.tostring())
01450 
01451     def _parse(self, data):
01452         """ Parse the event stream, and return a list of Iwscanresult
01453             objects.
01454 
01455         """
01456         iwstruct = Iwstruct()
01457         scanresult = None
01458         aplist = []
01459 
01460         # Run through the stream until it is too short to contain a command
01461         while (len(data) >= wifi_flags.IW_EV_LCP_PK_LEN):
01462             # Unpack the header
01463             length, cmd = iwstruct.unpack('HH',
01464                               data[:wifi_flags.IW_EV_LCP_PK_LEN])
01465             # If the event length is too short to contain valid data,
01466             # then break, because we're probably at the end of the cell's data
01467             if length < wifi_flags.IW_EV_LCP_PK_LEN:
01468                 break;
01469             # Put the events into their respective result data
01470             if cmd == wifi_flags.SIOCGIWAP:
01471                 if scanresult:
01472                     aplist.append(scanresult)
01473                 scanresult = Iwscanresult(
01474                         data[wifi_flags.IW_EV_LCP_PK_LEN:length],
01475                         self.range)
01476             elif scanresult is None:
01477                 raise RuntimeError("Attempting to add an event without AP data.")
01478             else:
01479                 scanresult.addEvent(cmd,
01480                         data[wifi_flags.IW_EV_LCP_PK_LEN:length])
01481             # We're finished with the previous event
01482             data = data[length:]
01483 
01484         # Don't forget the final result
01485         if scanresult:
01486             if scanresult.bssid != "00:00:00:00:00:00":
01487                 aplist.append(scanresult)
01488             else:
01489                 raise RuntimeError, 'Attempting to add an AP without a bssid'
01490         return aplist
01491 
01492 
01493 class Iwscanresult(object):
01494     """ An object to contain all the events associated with a single
01495         scanned AP.
01496 
01497     """
01498 
01499     def __init__(self, data, iwrange):
01500         """ Initialize the scan result with the access point data. """
01501         self.range = iwrange
01502         self.bssid = "%02X:%02X:%02X:%02X:%02X:%02X" % (
01503                         struct.unpack('BBBBBB', data[2:8]))
01504         self.essid = None
01505         self.mode = None
01506         self.rate = []
01507         self.quality = Iwquality()
01508         self.frequency = None
01509         self.encode = None
01510         self.custom = []
01511         self.protocol = None
01512 
01513     def addEvent(self, cmd, data):
01514         """ Attempts to add the data from an event to a scanresult.
01515             Only certain data is accepted, in which case the result is True
01516             If the event data is invalid, None is returned
01517             If the data is valid but unused, False is returned
01518 
01519         """
01520         if ((cmd in range(wifi_flags.SIOCIWFIRST,
01521                           wifi_flags.SIOCIWLAST+1)) or
01522             (cmd in range(wifi_flags.IWEVFIRST,
01523                           wifi_flags.IWEVLAST+1))):
01524             if cmd == wifi_flags.SIOCGIWNWID:
01525                 pass
01526             elif cmd == wifi_flags.SIOCGIWFREQ:
01527                 self.frequency = Iwfreq(data)
01528             elif cmd == wifi_flags.SIOCGIWMODE:
01529                 raw_mode = struct.unpack('I', data[:4])[0]
01530                 self.mode = wifi_flags.modes[raw_mode]
01531             elif cmd == wifi_flags.SIOCGIWNAME:
01532                 self.protocol = data[:len(data)-2]
01533             elif cmd == wifi_flags.SIOCGIWESSID:
01534                 self.essid = data[4:]
01535             elif cmd == wifi_flags.SIOCGIWENCODE:
01536                 data = struct.unpack("B"*len(data), data)
01537                 self.encode = Iwpoint("")
01538                 self.encode.update(struct.pack('PHH',
01539                     (int(data[0])<<16)+int(data[1]), data[2]<<8, data[3]<<8))
01540                 if (self.encode.caddr_t is None):
01541                     self.encode.flags = \
01542                         self.encode.flags | wifi_flags.IW_ENCODE_NOKEY
01543             elif cmd == wifi_flags.SIOCGIWRATE:
01544                 freqsize = struct.calcsize("ihbb")
01545                 rates = []
01546                 while len(data) >= freqsize:
01547                     m, e, dummy, pad = struct.unpack("ihbb", data[:freqsize])
01548                     if e == 0:
01549                         rates.append(m)
01550                     else:
01551                         rates.append(m*10**e)
01552                     data = data[freqsize:]
01553                 self.rate.append(rates)
01554             elif cmd == wifi_flags.SIOCGIWMODUL:
01555                 pass
01556             elif cmd == wifi_flags.IWEVQUAL:
01557                 self.quality.parse(data)
01558             elif cmd == wifi_flags.IWEVGENIE:
01559                 pass
01560             elif cmd == wifi_flags.IWEVCUSTOM:
01561                 self.custom.append(data[1:])
01562             else:
01563                 raise ValueError("Unknown IW event command received. This " + \
01564                                  "command cannot be used to add information " + \
01565                                  "to the WiFi cell's profile.")
01566         else:
01567             raise ValueError("Invalid IW event command received.  \
01568                               This command is not allowed.")
01569 
01570     def display(self):
01571         print "ESSID:", self.essid
01572         print "Access point:", self.bssid
01573         print "Mode:", self.mode
01574         if len(self.rate) > 0:
01575             print "Highest Bitrate:", self.rate[len(self.rate)-1]
01576         print "Quality: Quality ", self.quality.quality,
01577         print "Signal ", self.quality.getSignallevel(),
01578         print " Noise ", self.quality.getNoiselevel()
01579         print "Encryption:", map(lambda x: hex(ord(x)), self.encode)
01580         # XXX
01581         # print "Frequency:", self.frequency.getFrequency(), "(Channel", self.frequency.getChannel(self.range), ")"
01582         for custom in self.custom:
01583             print "Custom:", custom
01584         print ""
01585 


rocon_python_wifi
Author(s): Róman Joost, Sean Robinson
autogenerated on Fri May 2 2014 10:35:45