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


multi_interface_roam
Author(s): Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:15