00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00081 ifnames.append(device.search(line).group()[:-1])
00082 except AttributeError:
00083 pass
00084
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
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
00110 wifi = Wireless(ifname)
00111 try:
00112 result = wifi.getAPaddr()
00113 except IOError, (errno, strerror):
00114
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
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
00245 raw_frequency = int(raw_frequency)
00246 try:
00247 return self.getChannelInfo()[1][raw_frequency-1]
00248 except IndexError:
00249
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
00314
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
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
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
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
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
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
00734
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
00771
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
00789
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
00828 self.stats = Iwstats
00829 self.range = Iwrange
00830
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
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
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
00998
00999
01000
01001
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
01027 if data is not None:
01028 ifreq.extend(data)
01029 else:
01030
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
01041
01042
01043
01044
01045
01046 class Iwparam(object):
01047 """ Class to hold iwparam data. """
01048
01049 def __init__(self, ifname, ioctl):
01050
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
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
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
01177 self.siglevel = siglevel
01178 self.nlevel = nlevel
01179
01180
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
01207
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
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
01248 self.throughput = 0
01249
01250
01251 self.min_nwid = self.max_nwid = 0
01252
01253
01254 self.old_num_channels = self.old_num_frequency = self.old_freq = 0
01255
01256
01257 self.sensitivity = 0
01258
01259
01260 self.max_qual = Iwquality()
01261 self.avg_qual = Iwquality()
01262
01263
01264 self.num_bitrates = 0
01265 self.bitrates = []
01266
01267
01268 self.min_rts = self.max_rts = 0
01269
01270
01271 self.min_frag = self.max_frag = 0
01272
01273
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
01279 self.encoding_size = 0
01280 self.num_encoding_sizes = self.max_encoding_tokens = 0
01281 self.encoding_login_index = 0
01282
01283
01284 self.txpower_capa = self.num_txpower = self.txpower = 0
01285
01286
01287 self.we_vers_compiled = self.we_vers_src = 0
01288
01289
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
01295 self.num_channels = self.num_frequency = 0
01296 self.frequencies = []
01297
01298
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
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
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
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
01426
01427 pbuff, newlen = iwstruct.unpack('Pi', datastr)
01428 if bufflen < newlen:
01429
01430 bufflen = newlen
01431 else:
01432
01433 bufflen = bufflen * 2
01434 elif error_number == errno.EAGAIN:
01435
01436
01437 time.sleep(0.1)
01438 else:
01439 raise
01440 except:
01441 raise
01442 else:
01443 break
01444
01445
01446 pbuff, reslen = iwstruct.unpack('Pi', datastr)
01447 if reslen > 0:
01448
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
01461 while (len(data) >= wifi_flags.IW_EV_LCP_PK_LEN):
01462
01463 length, cmd = iwstruct.unpack('HH',
01464 data[:wifi_flags.IW_EV_LCP_PK_LEN])
01465
01466
01467 if length < wifi_flags.IW_EV_LCP_PK_LEN:
01468 break;
01469
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
01482 data = data[length:]
01483
01484
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
01581
01582 for custom in self.custom:
01583 print "Custom:", custom
01584 print ""
01585