1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 import xml.parsers.expat
29 from base import device, utils
33 NS = "http://www.hp.com/schemas/imaging/cnc/dcsl/2006/05/WifiConfig"
34 PREAMBLE = """<?xml version="1.0" encoding="utf-8"?>
35 <WiFiConfig xmlns="%s">
38 def _readWriteWifiConfig(dev, request):
40 log.error("Invalid request")
41 return 'executionfailed', {}
43 log.debug("Sending request on wifi config channel...")
47 bytes_written = dev.writeWifiConfig(request)
48 log.debug("Wrote %d bytes." % bytes_written)
50 data = cStringIO.StringIO()
51 log.debug("Reading response on wifi config channel...")
52 bytesread = dev.readWifiConfig(device.MAX_BUFFER, stream=data, timeout=30)
54 # if response data is > 8192 bytes, make sure we have read it all...
57 bytesread = dev.readWifiConfig(device.MAX_BUFFER, stream=data, timeout=1)
58 if not bytesread or i > MAX_RETRIES:
61 data = data.getvalue()
65 # Convert any char references
66 data = utils.unescape(data)
69 data = unicode(data, 'utf-8')
73 # C4380 returns invalid XML for DeviceCapabilitiesResponse
74 # Eliminate any invalid characters
75 data = data.replace(u"Devicecapabilities", u"DeviceCapabilities").replace('\x00', '')
78 log.debug("Read %d bytes." % len(data))
82 return 'executionfailed', {}
87 params = utils.XMLToDictParser().parseXML(data)
88 except xml.parsers.expat.ExpatError, e:
89 log.error("XML parser failed: %s" % e)
90 match = re.search(r"""line\s*(\d+).*?column\s*(\d+)""", str(e), re.I)
92 log.error(data[int(match.group(2)):])
93 return 'executionfailed', {}
97 errorreturn = 'executionfailed'
99 if p.lower().endswith('errorreturn'):
100 errorreturn = params[p].lower()
103 params['errorreturn'] = errorreturn
105 return errorreturn, params
107 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
110 def getDeviceCapabilities(dev):
112 request = PREAMBLE + """<GetDeviceCapabilitiesRequest>
113 </GetDeviceCapabilitiesRequest>
116 errorreturn, params = _readWriteWifiConfig(dev, request)
120 ret['errorreturn'] = errorreturn
121 if errorreturn != 'ok':
122 log.error("GetDeviceCapabilities returned an error: %s" % errorreturn)
125 param_keys = ['wificonfig-getdevicecapabilitiesresponse-devicecapabilities-numberofsupportedwifiaccessories',
126 'wificonfig-getdevicecapabilitiesresponse-interfaceversion-minorreleasenumber',
127 'wificonfig-getdevicecapabilitiesresponse-interfaceversion-majorreleasenumber',
132 ret[p.split('-')[-1]] = params[p]
134 log.debug("Missing response key: %s" % p)
139 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
142 def getAdaptorList(dev):
144 request = PREAMBLE + """<GetAdaptorListRequest>
145 </GetAdaptorListRequest>
148 errorreturn, params = _readWriteWifiConfig(dev, request)
150 return {'adaptorlistlength': 0}
152 ret['errorreturn'] = errorreturn
153 if errorreturn != 'ok':
154 log.error("GetAdaptorList returned an error: %s" % errorreturn)
158 adaptor_list_length = int(params['wificonfig-getadaptorlistresponse-adaptorlistlength'])
159 except (ValueError, KeyError):
160 adaptor_list_length = 0
162 ret['adaptorlistlength'] = adaptor_list_length
164 if adaptor_list_length == 0:
165 log.error("GetAdaptorList returned 0 adaptors")
167 elif adaptor_list_length == 1:
169 ret['adaptorid-0'] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorid']
170 ret['adaptorname-0'] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorname']
171 ret['adaptorpresence-0'] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorpresence']
172 ret['adaptorstate-0'] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorstate']
173 ret['adaptortype-0'] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptortype']
175 log.debug("Missing response key: %s" % e)
177 for a in xrange(adaptor_list_length):
179 ret['adaptorid-%d' % a] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorid-%d' % a]
180 ret['adaptorname-%d' % a] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorname-%d' % a]
181 ret['adaptorpresence-%d' % a] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorpresence-%d' % a]
182 ret['adaptorstate-%d' % a] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptorstate-%d' % a]
183 ret['adaptortype-%d' % a] = params['wificonfig-getadaptorlistresponse-adaptorlist-adaptorinfo-adaptortype-%d' % a]
185 log.debug("Missing response key: %s" % e)
189 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
191 def getWifiAdaptorID(dev):
192 # ret: adaptor_id, name, state, presence
193 ret = getAdaptorList(dev)
196 num_adaptors = ret['adaptorlistlength']
200 for n in xrange(num_adaptors):
202 name = ret['adaptortype-%d' % n]
206 if name.lower() in ('wifiembedded', 'wifiaccessory'):
207 params = ['adaptorid', 'adaptorname', 'adaptorstate', 'adaptorpresence']
212 x = ret[''.join([p, '-', str(n)])]
223 return -1, 'Unknown', 'Unknown', 'Unknown'
225 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
228 def setAdaptorPower(dev, adapterName, adaptor_id=0, power_state='PowerOn'):
230 request = PREAMBLE + """<SetAdaptorPowerRequest>
231 <AdaptorID>%s</AdaptorID>
232 <PowerState>%s</PowerState>
233 </SetAdaptorPowerRequest>
234 </WiFiConfig>""" % (adaptor_id, power_state.encode('utf-8'))
236 errorreturn, params = _readWriteWifiConfig(dev, request)
240 ret['errorreturn'] = errorreturn
241 if errorreturn != 'ok':
242 log.error("SetAdaptorPower returned an error: %s" % errorreturn)
247 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
250 def performScan(dev, adapterName, ssid=None):
251 ret, i, scan_state = {}, 0, "NewScan"
254 if ssid is None: # Undirected
255 request = PREAMBLE + """<UndirectedScanRequest>
256 <ScanState>%s</ScanState>
257 </UndirectedScanRequest>
258 </WiFiConfig>""" % scan_state
260 typ = 'UndirectedScan'
261 rsp = 'undirectedscanresponse'
264 request = PREAMBLE + """<DirectedScanRequest>
266 <ScanState>%s</ScanState>
267 </DirectedScanRequest>
268 </WiFiConfig>""" % (ssid.encode('utf-8'), scan_state)
271 rsp = 'directedscanresponse'
273 errorreturn, params = _readWriteWifiConfig(dev, request)
275 return {'numberofscanentries': 0}
277 ret['errorreturn'] = errorreturn
278 if errorreturn != 'ok':
279 log.error("%s returned an error: %s" % (typ, errorreturn))
283 number_of_scan_entries = int(params['wificonfig-%s-numberofscanentries' % rsp])
284 except (ValueError, KeyError):
285 number_of_scan_entries = 0
287 ret['numberofscanentries'] = number_of_scan_entries
289 if number_of_scan_entries == 0:
290 if scan_state.lower() == 'scancomplete':
291 log.debug("%s returned 0 entries. Scan complete." % typ)
293 log.debug("%s returned 0 entries. Resuming scan..." % typ)
295 elif number_of_scan_entries == 1:
297 ssid = params['wificonfig-%s-scanlist-scanentry-ssid' % rsp]
299 ret['ssid-0'] = u'(unknown)'
302 ret['bssid-0'] = params['wificonfig-%s-scanlist-scanentry-bssid' % rsp]
303 ret['channel-0'] = params['wificonfig-%s-scanlist-scanentry-channel' % rsp]
304 ret['communicationmode-0'] = params['wificonfig-%s-scanlist-scanentry-communicationmode' % rsp]
305 ret['dbm-0'] = params['wificonfig-%s-scanlist-scanentry-dbm' % rsp]
306 ret['encryptiontype-0'] = params['wificonfig-%s-scanlist-scanentry-encryptiontype' % rsp]
307 ret['rank-0'] = params['wificonfig-%s-scanlist-scanentry-rank' % rsp]
308 ret['signalstrength-0'] = params['wificonfig-%s-scanlist-scanentry-signalstrength' % rsp]
310 log.debug("Missing response key: %s" % e)
313 for a in xrange(number_of_scan_entries):
316 ssid = params['wificonfig-%s-scanlist-scanentry-ssid-%d' % (rsp, j)]
318 ret['ssid-%d' % j] = u'(unknown)'
320 ret['ssid-%d' % j] = ssid
321 ret['bssid-%d' % j] = params['wificonfig-%s-scanlist-scanentry-bssid-%d' % (rsp, j)]
322 ret['channel-%d' % j] = params['wificonfig-%s-scanlist-scanentry-channel-%d' % (rsp, j)]
323 ret['communicationmode-%d' % j] = params['wificonfig-%s-scanlist-scanentry-communicationmode-%d' % (rsp, j)]
324 ret['dbm-%d' % j] = params['wificonfig-%s-scanlist-scanentry-dbm-%d' % (rsp, j)]
325 ret['encryptiontype-%d' % j] = params['wificonfig-%s-scanlist-scanentry-encryptiontype-%d' % (rsp, j)]
326 ret['rank-%d' % j] = params['wificonfig-%s-scanlist-scanentry-rank-%d' % (rsp, j)]
327 ret['signalstrength-%d' % j] = params['wificonfig-%s-scanlist-scanentry-signalstrength-%d' % (rsp, j)]
329 log.debug("Missing response key: %s" % e)
332 scan_state = ret['scanstate'] = params['wificonfig-%s-scanstate' % rsp] # MoreEntriesAvailable, ScanComplete
333 ret['signalstrengthmax'] = params['wificonfig-%s-scansettings-signalstrengthmax' % rsp]
334 ret['signalstrengthmin'] = params['wificonfig-%s-scansettings-signalstrengthmin' % rsp]
336 log.debug("Missing response key: %s" % e)
338 if scan_state.lower() == 'scancomplete':
341 scan_state = "ResumeScan"
342 i += number_of_scan_entries
351 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
354 def associate(dev, adapterName,ssid, communication_mode, encryption_type, key):
356 request = PREAMBLE + """<AssociateRequest>
358 <CommunicationMode>%s</CommunicationMode>
359 <EncryptionType>%s</EncryptionType>
360 <EncryptedParameters>%s</EncryptedParameters>
363 </WiFiConfig>""" % (ssid.encode('utf-8'), communication_mode.encode('utf-8'),
364 encryption_type.encode('utf-8'), u"False".encode('utf-8'),
367 errorreturn, params = _readWriteWifiConfig(dev, request)
371 ret['errorreturn'] = errorreturn
372 if errorreturn != 'ok':
373 log.error("Associate returned an error: %s" % errorreturn)
378 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
381 def getVSACodes(dev,adapterName):
383 request = PREAMBLE + """<GetVSACodesRequest>
384 </GetVSACodesRequest>
387 errorreturn, params = _readWriteWifiConfig(dev, request)
391 if errorreturn != 'ok':
392 log.error("GetVSACodes returned an error: %s" % errorreturn)
396 rule = params['wificonfig-getvsacodesresponse-vsacodelist-vsacode-rulenumber']
397 severity = params['wificonfig-getvsacodesresponse-vsacodelist-vsacode-severity']
402 rule = params['wificonfig-getvsacodesresponse-vsacodelist-vsacode-rulenumber-%d' % n]
406 severity = params['wificonfig-getvsacodesresponse-vsacodelist-vsacode-severity-%d' % n]
408 ret.append((rule, severity))
411 ret.append((rule, severity))
415 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
417 def __getIPConfiguration(dev, adaptor_id=0):
419 request = PREAMBLE + """<GetIPConfigurationRequest>
420 <AdaptorID>%d</AdaptorID>
421 </GetIPConfigurationRequest>
422 </WiFiConfig>""" % adaptor_id
424 errorreturn, params = _readWriteWifiConfig(dev, request)
428 ret['errorreturn'] = errorreturn
429 if errorreturn != 'ok':
430 log.error("GetIPConfiguration returned an error: %s" % errorreturn)
433 param_keys = ['wificonfig-getipconfigurationresponse-ipconfiguration-addressmode',
434 'wificonfig-getipconfigurationresponse-ipconfiguration-alternatednsaddress',
435 'wificonfig-getipconfigurationresponse-ipconfiguration-gatewayaddress',
436 'wificonfig-getipconfigurationresponse-ipconfiguration-ipaddress',
437 'wificonfig-getipconfigurationresponse-ipconfiguration-primarydnsaddress',
438 'wificonfig-getipconfigurationresponse-ipconfiguration-subnetmask',
439 'wificonfig-getipconfigurationresponse-networkconfiguration-hostname',
444 ret[p.split('-')[-1]] = params[p]
446 log.debug("Missing response key: %s" % p)
452 def getIPConfiguration(dev, adapterName, adaptor_id=0):
453 ip, hostname, addressmode, subnetmask, gateway, pridns, sec_dns = \
454 '0.0.0.0', 'Unknown', 'Unknown', '0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0'
455 ret = __getIPConfiguration(dev, adaptor_id)
457 if ret and ret['errorreturn'].lower() == 'ok':
459 ip = ret['ipaddress']
460 hostname = ret['hostname']
461 addressmode = ret['addressmode']
462 subnetmask = ret['subnetmask']
463 gateway = ret['gatewayaddress']
464 pridns = ret['primarydnsaddress']
465 sec_dns = ret['alternatednsaddress']
467 log.debug("Missing response key: %s" % str(e))
469 return ip, hostname, addressmode, subnetmask, gateway, pridns, sec_dns
471 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
473 def __getSignalStrength(dev, adaptor_id=0):
475 request = PREAMBLE + """<GetSignalStrengthRequest>
476 <AdaptorID>%d</AdaptorID>
477 </GetSignalStrengthRequest>
478 </WiFiConfig>""" % adaptor_id
480 errorreturn, params = _readWriteWifiConfig(dev, request)
484 ret['errorreturn'] = errorreturn
485 if errorreturn != 'ok':
486 log.error("GetSignalStrength returned an error: %s" % errorreturn)
489 param_keys = ['wificonfig-getsignalstrengthresponse-signalstrength-dbm',
490 'wificonfig-getsignalstrengthresponse-signalstrength-signalstrengthmax',
491 'wificonfig-getsignalstrengthresponse-signalstrength-signalstrengthmin',
492 'wificonfig-getsignalstrengthresponse-signalstrength-signalstrengthvalue',
497 ret[p.split('-')[-1]] = params[p]
499 log.debug("Missing response key: %s" % p)
505 def getSignalStrength(dev, adapterName, ssid, adaptor_id=0):
506 ss_max, ss_min, ss_val, ss_dbm = 5, 0, 0, -200
507 ret = __getSignalStrength(dev, adaptor_id)
509 if ret and ret['errorreturn'].lower() == 'ok':
511 ss_max = ret['signalstrengthmax']
512 ss_min = ret['signalstrengthmin']
513 ss_val = ret['signalstrengthvalue']
516 log.debug("Missing response key: %s" % str(e))
518 return ss_max, ss_min, ss_val, ss_dbm
521 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
523 def __getCryptoSuite(dev):
525 request = PREAMBLE + """<GetCryptoSuiteRequest>
526 </GetCryptoSuiteRequest>
529 errorreturn, params = _readWriteWifiConfig(dev, request)
533 ret['errorreturn'] = errorreturn
534 if errorreturn != 'ok':
535 log.error("GetSignalStrength returned an error: %s" % errorreturn)
540 param_keys = ['wificonfig-getcryptosuiteresponse-cryposuite-crypoalgorithm',
541 'wificonfig-getcryptosuiteresponse-cryposuite-crypomode',
542 'wificonfig-getcryptosuiteresponse-cryposuite-secretid',]
546 ret[p.split('-')[-1]] = params[p]
548 log.debug("Missing response key: %s" % p)
554 def getCryptoSuite(dev, adapterName):
555 alg, mode, secretid = '', '', ''
556 ret = __getCryptoSuite(dev)
558 if ret and ret['errorreturn'].lower() == 'ok':
560 alg = ret['crypoalgorithm']
561 mode = ret['crypomode']
562 secretid = ret['secretid']
564 log.debug("Missing response key: %s" % str(e))
566 return alg, mode, secretid
568 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
570 def getHostname(dev):
572 request = PREAMBLE + """<GetHostnameRequest>
573 </GetHostnameRequest>
576 errorreturn, params = _readWriteWifiConfig(dev, request)
580 if errorreturn != 'ok':
581 # log.error("GetHostname returned an error: %s" % errorreturn)
585 ret = params['wificonfig-gethostnameresponse-hostname']
587 log.debug("Missing response key: hostname")
591 # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
594 def getLocation(bssid, ss):
595 log.debug("Getting location for wifi AP: %s" % bssid)
596 request = """<?xml version='1.0'?>
597 <LocationRQ xmlns='http://skyhookwireless.com/wps/2005' version='2.6' street-address-lookup='full'>
598 <authentication version='2.0'>
600 <username>beta</username>
601 <realm>js.loki.com</realm>
606 <signal-strength>%d</signal-strength>
608 </LocationRQ>""" % (bssid.encode("utf-8"), ss)
610 import httplib, socket
612 request_len = len(request)
614 log.log_data(request)
617 conn = httplib.HTTPSConnection("api.skyhookwireless.com")
618 conn.putrequest("POST", "/wps2/location")
619 conn.putheader("Content-type", "text/xml")
620 conn.putheader("Content-Length", str(request_len))
623 except (socket.gaierror, socket.error):
624 log.debug("Host connection error")
627 response = conn.getresponse()
628 if response.status != 200:
629 log.debug("Connection to location server failed")
632 xml = response.read()
636 params = utils.XMLToDictParser().parseXML(xml)
637 except xml.parsers.expat.ExpatError:
640 if 'locationrs-error' in params:
641 log.debug("Location server returned failure")
644 ret['latitude'] = params.get('locationrs-location-latitude', 0)
645 ret['longitude'] = params.get('locationrs-location-longitude', 0)
646 street_number = params.get('locationrs-location-street-address-street-number', '')
647 street_name = params.get('locationrs-location-street-address-address-line', '')
648 city = params.get('locationrs-location-street-address-city', '')
649 country = params.get('locationrs-location-street-address-country-code', '')
651 address = "%s %s, %s, %s" % (street_number, street_name, city, country)
652 ret['address'] = address.strip()