wpasupplicant.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. # Python class for controlling wpa_supplicant
  2. # Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
  3. #
  4. # This software may be distributed under the terms of the BSD license.
  5. # See README for more details.
  6. import os
  7. import time
  8. import logging
  9. import re
  10. import subprocess
  11. import wpaspy
  12. logger = logging.getLogger()
  13. wpas_ctrl = '/var/run/wpa_supplicant'
  14. class WpaSupplicant:
  15. def __init__(self, ifname=None, global_iface=None):
  16. self.group_ifname = None
  17. if ifname:
  18. self.set_ifname(ifname)
  19. else:
  20. self.ifname = None
  21. self.global_iface = global_iface
  22. if global_iface:
  23. self.global_ctrl = wpaspy.Ctrl(global_iface)
  24. self.global_mon = wpaspy.Ctrl(global_iface)
  25. self.global_mon.attach()
  26. def set_ifname(self, ifname):
  27. self.ifname = ifname
  28. self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
  29. self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
  30. self.mon.attach()
  31. def remove_ifname(self):
  32. if self.ifname:
  33. self.mon.detach()
  34. self.mon = None
  35. self.ctrl = None
  36. self.ifname = None
  37. def interface_add(self, ifname, driver="nl80211", drv_params=None):
  38. try:
  39. groups = subprocess.check_output(["id"])
  40. group = "admin" if "(admin)" in groups else "adm"
  41. except Exception, e:
  42. group = "admin"
  43. cmd = "INTERFACE_ADD " + ifname + "\t\t" + driver + "\tDIR=/var/run/wpa_supplicant GROUP=" + group
  44. if drv_params:
  45. cmd = cmd + '\t' + drv_params
  46. if "FAIL" in self.global_request(cmd):
  47. raise Exception("Failed to add a dynamic wpa_supplicant interface")
  48. self.set_ifname(ifname)
  49. def interface_remove(self, ifname):
  50. self.remove_ifname()
  51. self.global_request("INTERFACE_REMOVE " + ifname)
  52. def request(self, cmd):
  53. logger.debug(self.ifname + ": CTRL: " + cmd)
  54. return self.ctrl.request(cmd)
  55. def global_request(self, cmd):
  56. if self.global_iface is None:
  57. self.request(cmd)
  58. else:
  59. ifname = self.ifname or self.global_iface
  60. logger.debug(ifname + ": CTRL: " + cmd)
  61. return self.global_ctrl.request(cmd)
  62. def group_request(self, cmd):
  63. if self.group_ifname and self.group_ifname != self.ifname:
  64. logger.debug(self.group_ifname + ": CTRL: " + cmd)
  65. gctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
  66. return gctrl.request(cmd)
  67. return self.request(cmd)
  68. def ping(self):
  69. return "PONG" in self.request("PING")
  70. def reset(self):
  71. res = self.request("FLUSH")
  72. if not "OK" in res:
  73. logger.info("FLUSH to " + self.ifname + " failed: " + res)
  74. self.request("SET external_sim 0")
  75. self.request("SET hessid 00:00:00:00:00:00")
  76. self.request("SET access_network_type 15")
  77. self.request("SET p2p_add_cli_chan 0")
  78. self.request("SET p2p_no_go_freq ")
  79. self.request("SET p2p_pref_chan ")
  80. self.request("SET p2p_no_group_iface 1")
  81. self.request("SET p2p_go_intent 7")
  82. self.group_ifname = None
  83. self.dump_monitor()
  84. iter = 0
  85. while iter < 60:
  86. state = self.get_driver_status_field("scan_state")
  87. if "SCAN_STARTED" in state or "SCAN_REQUESTED" in state:
  88. logger.info(self.ifname + ": Waiting for scan operation to complete before continuing")
  89. time.sleep(1)
  90. else:
  91. break
  92. iter = iter + 1
  93. if iter == 60:
  94. logger.error(self.ifname + ": Driver scan state did not clear")
  95. print "Trying to clear cfg80211/mac80211 scan state"
  96. try:
  97. cmd = ["sudo", "ifconfig", self.ifname, "down"]
  98. subprocess.call(cmd)
  99. except subprocess.CalledProcessError, e:
  100. logger.info("ifconfig failed: " + str(e.returncode))
  101. logger.info(e.output)
  102. try:
  103. cmd = ["sudo", "ifconfig", self.ifname, "up"]
  104. subprocess.call(cmd)
  105. except subprocess.CalledProcessError, e:
  106. logger.info("ifconfig failed: " + str(e.returncode))
  107. logger.info(e.output)
  108. if iter > 0:
  109. # The ongoing scan could have discovered BSSes or P2P peers
  110. logger.info("Run FLUSH again since scan was in progress")
  111. self.request("FLUSH")
  112. self.dump_monitor()
  113. if not self.ping():
  114. logger.info("No PING response from " + self.ifname + " after reset")
  115. def add_network(self):
  116. id = self.request("ADD_NETWORK")
  117. if "FAIL" in id:
  118. raise Exception("ADD_NETWORK failed")
  119. return int(id)
  120. def remove_network(self, id):
  121. id = self.request("REMOVE_NETWORK " + str(id))
  122. if "FAIL" in id:
  123. raise Exception("REMOVE_NETWORK failed")
  124. return None
  125. def get_network(self, id, field):
  126. res = self.request("GET_NETWORK " + str(id) + " " + field)
  127. if res == "FAIL\n":
  128. return None
  129. return res
  130. def set_network(self, id, field, value):
  131. res = self.request("SET_NETWORK " + str(id) + " " + field + " " + value)
  132. if "FAIL" in res:
  133. raise Exception("SET_NETWORK failed")
  134. return None
  135. def set_network_quoted(self, id, field, value):
  136. res = self.request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
  137. if "FAIL" in res:
  138. raise Exception("SET_NETWORK failed")
  139. return None
  140. def list_networks(self):
  141. res = self.request("LIST_NETWORKS")
  142. lines = res.splitlines()
  143. networks = []
  144. for l in lines:
  145. if "network id" in l:
  146. continue
  147. [id,ssid,bssid,flags] = l.split('\t')
  148. network = {}
  149. network['id'] = id
  150. network['ssid'] = ssid
  151. network['bssid'] = bssid
  152. network['flags'] = flags
  153. networks.append(network)
  154. return networks
  155. def hs20_enable(self):
  156. self.request("SET interworking 1")
  157. self.request("SET hs20 1")
  158. def add_cred(self):
  159. id = self.request("ADD_CRED")
  160. if "FAIL" in id:
  161. raise Exception("ADD_CRED failed")
  162. return int(id)
  163. def remove_cred(self, id):
  164. id = self.request("REMOVE_CRED " + str(id))
  165. if "FAIL" in id:
  166. raise Exception("REMOVE_CRED failed")
  167. return None
  168. def set_cred(self, id, field, value):
  169. res = self.request("SET_CRED " + str(id) + " " + field + " " + value)
  170. if "FAIL" in res:
  171. raise Exception("SET_CRED failed")
  172. return None
  173. def set_cred_quoted(self, id, field, value):
  174. res = self.request("SET_CRED " + str(id) + " " + field + ' "' + value + '"')
  175. if "FAIL" in res:
  176. raise Exception("SET_CRED failed")
  177. return None
  178. def add_cred_values(self, params):
  179. id = self.add_cred()
  180. quoted = [ "realm", "username", "password", "domain", "imsi",
  181. "excluded_ssid", "milenage", "ca_cert", "client_cert",
  182. "private_key" ]
  183. for field in quoted:
  184. if field in params:
  185. self.set_cred_quoted(id, field, params[field])
  186. not_quoted = [ "eap", "roaming_consortium",
  187. "required_roaming_consortium" ]
  188. for field in not_quoted:
  189. if field in params:
  190. self.set_cred(id, field, params[field])
  191. return id;
  192. def select_network(self, id):
  193. id = self.request("SELECT_NETWORK " + str(id))
  194. if "FAIL" in id:
  195. raise Exception("SELECT_NETWORK failed")
  196. return None
  197. def connect_network(self, id, timeout=10):
  198. self.dump_monitor()
  199. self.select_network(id)
  200. ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=timeout)
  201. if ev is None:
  202. raise Exception("Association with the AP timed out")
  203. self.dump_monitor()
  204. def get_status(self):
  205. res = self.request("STATUS")
  206. lines = res.splitlines()
  207. vals = dict()
  208. for l in lines:
  209. try:
  210. [name,value] = l.split('=', 1)
  211. vals[name] = value
  212. except ValueError, e:
  213. logger.info(self.ifname + ": Ignore unexpected STATUS line: " + l)
  214. return vals
  215. def get_status_field(self, field):
  216. vals = self.get_status()
  217. if field in vals:
  218. return vals[field]
  219. return None
  220. def get_group_status(self):
  221. res = self.group_request("STATUS")
  222. lines = res.splitlines()
  223. vals = dict()
  224. for l in lines:
  225. [name,value] = l.split('=', 1)
  226. vals[name] = value
  227. return vals
  228. def get_group_status_field(self, field):
  229. vals = self.get_group_status()
  230. if field in vals:
  231. return vals[field]
  232. return None
  233. def get_driver_status(self):
  234. res = self.request("STATUS-DRIVER")
  235. lines = res.splitlines()
  236. vals = dict()
  237. for l in lines:
  238. [name,value] = l.split('=', 1)
  239. vals[name] = value
  240. return vals
  241. def get_driver_status_field(self, field):
  242. vals = self.get_driver_status()
  243. if field in vals:
  244. return vals[field]
  245. return None
  246. def p2p_dev_addr(self):
  247. return self.get_status_field("p2p_device_address")
  248. def p2p_interface_addr(self):
  249. return self.get_group_status_field("address")
  250. def p2p_listen(self):
  251. return self.global_request("P2P_LISTEN")
  252. def p2p_find(self, social=False, dev_id=None, dev_type=None):
  253. cmd = "P2P_FIND"
  254. if social:
  255. cmd = cmd + " type=social"
  256. if dev_id:
  257. cmd = cmd + " dev_id=" + dev_id
  258. if dev_type:
  259. cmd = cmd + " dev_type=" + dev_type
  260. return self.global_request(cmd)
  261. def p2p_stop_find(self):
  262. return self.global_request("P2P_STOP_FIND")
  263. def wps_read_pin(self):
  264. #TODO: make this random
  265. self.pin = "12345670"
  266. return self.pin
  267. def peer_known(self, peer, full=True):
  268. res = self.global_request("P2P_PEER " + peer)
  269. if peer.lower() not in res.lower():
  270. return False
  271. if not full:
  272. return True
  273. return "[PROBE_REQ_ONLY]" not in res
  274. def discover_peer(self, peer, full=True, timeout=15, social=True, force_find=False):
  275. logger.info(self.ifname + ": Trying to discover peer " + peer)
  276. if not force_find and self.peer_known(peer, full):
  277. return True
  278. self.p2p_find(social)
  279. count = 0
  280. while count < timeout:
  281. time.sleep(1)
  282. count = count + 1
  283. if self.peer_known(peer, full):
  284. return True
  285. return False
  286. def get_peer(self, peer):
  287. res = self.global_request("P2P_PEER " + peer)
  288. if peer.lower() not in res.lower():
  289. raise Exception("Peer information not available")
  290. lines = res.splitlines()
  291. vals = dict()
  292. for l in lines:
  293. if '=' in l:
  294. [name,value] = l.split('=', 1)
  295. vals[name] = value
  296. return vals
  297. def group_form_result(self, ev, expect_failure=False, go_neg_res=None):
  298. if expect_failure:
  299. if "P2P-GROUP-STARTED" in ev:
  300. raise Exception("Group formation succeeded when expecting failure")
  301. exp = r'<.>(P2P-GO-NEG-FAILURE) status=([0-9]*)'
  302. s = re.split(exp, ev)
  303. if len(s) < 3:
  304. return None
  305. res = {}
  306. res['result'] = 'go-neg-failed'
  307. res['status'] = int(s[2])
  308. return res
  309. if "P2P-GROUP-STARTED" not in ev:
  310. raise Exception("No P2P-GROUP-STARTED event seen")
  311. exp = r'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*) ip_addr=([0-9.]*) ip_mask=([0-9.]*) go_ip_addr=([0-9.]*)'
  312. s = re.split(exp, ev)
  313. if len(s) < 11:
  314. exp = r'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*)'
  315. s = re.split(exp, ev)
  316. if len(s) < 8:
  317. raise Exception("Could not parse P2P-GROUP-STARTED")
  318. res = {}
  319. res['result'] = 'success'
  320. res['ifname'] = s[2]
  321. self.group_ifname = s[2]
  322. res['role'] = s[3]
  323. res['ssid'] = s[4]
  324. res['freq'] = s[5]
  325. if "[PERSISTENT]" in ev:
  326. res['persistent'] = True
  327. else:
  328. res['persistent'] = False
  329. p = re.match(r'psk=([0-9a-f]*)', s[6])
  330. if p:
  331. res['psk'] = p.group(1)
  332. p = re.match(r'passphrase="(.*)"', s[6])
  333. if p:
  334. res['passphrase'] = p.group(1)
  335. res['go_dev_addr'] = s[7]
  336. if len(s) > 8 and len(s[8]) > 0:
  337. res['ip_addr'] = s[8]
  338. if len(s) > 9:
  339. res['ip_mask'] = s[9]
  340. if len(s) > 10:
  341. res['go_ip_addr'] = s[10]
  342. if go_neg_res:
  343. exp = r'<.>(P2P-GO-NEG-SUCCESS) role=(GO|client) freq=([0-9]*)'
  344. s = re.split(exp, go_neg_res)
  345. if len(s) < 4:
  346. raise Exception("Could not parse P2P-GO-NEG-SUCCESS")
  347. res['go_neg_role'] = s[2]
  348. res['go_neg_freq'] = s[3]
  349. return res
  350. def p2p_go_neg_auth(self, peer, pin, method, go_intent=None, persistent=False, freq=None):
  351. if not self.discover_peer(peer):
  352. raise Exception("Peer " + peer + " not found")
  353. self.dump_monitor()
  354. cmd = "P2P_CONNECT " + peer + " " + pin + " " + method + " auth"
  355. if go_intent:
  356. cmd = cmd + ' go_intent=' + str(go_intent)
  357. if freq:
  358. cmd = cmd + ' freq=' + str(freq)
  359. if persistent:
  360. cmd = cmd + " persistent"
  361. if "OK" in self.global_request(cmd):
  362. return None
  363. raise Exception("P2P_CONNECT (auth) failed")
  364. def p2p_go_neg_auth_result(self, timeout=1, expect_failure=False):
  365. go_neg_res = None
  366. ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
  367. "P2P-GO-NEG-FAILURE"], timeout);
  368. if ev is None:
  369. if expect_failure:
  370. return None
  371. raise Exception("Group formation timed out")
  372. if "P2P-GO-NEG-SUCCESS" in ev:
  373. go_neg_res = ev
  374. ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout);
  375. if ev is None:
  376. if expect_failure:
  377. return None
  378. raise Exception("Group formation timed out")
  379. self.dump_monitor()
  380. return self.group_form_result(ev, expect_failure, go_neg_res)
  381. def p2p_go_neg_init(self, peer, pin, method, timeout=0, go_intent=None, expect_failure=False, persistent=False, freq=None):
  382. if not self.discover_peer(peer):
  383. raise Exception("Peer " + peer + " not found")
  384. self.dump_monitor()
  385. if pin:
  386. cmd = "P2P_CONNECT " + peer + " " + pin + " " + method
  387. else:
  388. cmd = "P2P_CONNECT " + peer + " " + method
  389. if go_intent:
  390. cmd = cmd + ' go_intent=' + str(go_intent)
  391. if freq:
  392. cmd = cmd + ' freq=' + str(freq)
  393. if persistent:
  394. cmd = cmd + " persistent"
  395. if "OK" in self.global_request(cmd):
  396. if timeout == 0:
  397. self.dump_monitor()
  398. return None
  399. go_neg_res = None
  400. ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
  401. "P2P-GO-NEG-FAILURE"], timeout)
  402. if ev is None:
  403. if expect_failure:
  404. return None
  405. raise Exception("Group formation timed out")
  406. if "P2P-GO-NEG-SUCCESS" in ev:
  407. go_neg_res = ev
  408. ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
  409. if ev is None:
  410. if expect_failure:
  411. return None
  412. raise Exception("Group formation timed out")
  413. self.dump_monitor()
  414. return self.group_form_result(ev, expect_failure, go_neg_res)
  415. raise Exception("P2P_CONNECT failed")
  416. def wait_event(self, events, timeout=10):
  417. start = os.times()[4]
  418. while True:
  419. while self.mon.pending():
  420. ev = self.mon.recv()
  421. logger.debug(self.ifname + ": " + ev)
  422. for event in events:
  423. if event in ev:
  424. return ev
  425. now = os.times()[4]
  426. remaining = start + timeout - now
  427. if remaining <= 0:
  428. break
  429. if not self.mon.pending(timeout=remaining):
  430. break
  431. return None
  432. def wait_global_event(self, events, timeout):
  433. if self.global_iface is None:
  434. self.wait_event(events, timeout)
  435. else:
  436. start = os.times()[4]
  437. while True:
  438. while self.global_mon.pending():
  439. ev = self.global_mon.recv()
  440. logger.debug(self.ifname + "(global): " + ev)
  441. for event in events:
  442. if event in ev:
  443. return ev
  444. now = os.times()[4]
  445. remaining = start + timeout - now
  446. if remaining <= 0:
  447. break
  448. if not self.global_mon.pending(timeout=remaining):
  449. break
  450. return None
  451. def wait_go_ending_session(self):
  452. ev = self.wait_event(["P2P-GROUP-REMOVED"], timeout=3)
  453. if ev is None:
  454. raise Exception("Group removal event timed out")
  455. if "reason=GO_ENDING_SESSION" not in ev:
  456. raise Exception("Unexpected group removal reason")
  457. def dump_monitor(self):
  458. while self.mon.pending():
  459. ev = self.mon.recv()
  460. logger.debug(self.ifname + ": " + ev)
  461. while self.global_mon.pending():
  462. ev = self.global_mon.recv()
  463. logger.debug(self.ifname + "(global): " + ev)
  464. def remove_group(self, ifname=None):
  465. if ifname is None:
  466. ifname = self.group_ifname if self.group_ifname else self.ifname
  467. if "OK" not in self.global_request("P2P_GROUP_REMOVE " + ifname):
  468. raise Exception("Group could not be removed")
  469. self.group_ifname = None
  470. def p2p_start_go(self, persistent=None, freq=None):
  471. self.dump_monitor()
  472. cmd = "P2P_GROUP_ADD"
  473. if persistent is None:
  474. pass
  475. elif persistent is True:
  476. cmd = cmd + " persistent"
  477. else:
  478. cmd = cmd + " persistent=" + str(persistent)
  479. if freq:
  480. cmd = cmd + " freq=" + str(freq)
  481. if "OK" in self.global_request(cmd):
  482. ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
  483. if ev is None:
  484. raise Exception("GO start up timed out")
  485. self.dump_monitor()
  486. return self.group_form_result(ev)
  487. raise Exception("P2P_GROUP_ADD failed")
  488. def p2p_go_authorize_client(self, pin):
  489. cmd = "WPS_PIN any " + pin
  490. if "FAIL" in self.group_request(cmd):
  491. raise Exception("Failed to authorize client connection on GO")
  492. return None
  493. def p2p_go_authorize_client_pbc(self):
  494. cmd = "WPS_PBC"
  495. if "FAIL" in self.group_request(cmd):
  496. raise Exception("Failed to authorize client connection on GO")
  497. return None
  498. def p2p_connect_group(self, go_addr, pin, timeout=0, social=False):
  499. self.dump_monitor()
  500. if not self.discover_peer(go_addr, social=social):
  501. raise Exception("GO " + go_addr + " not found")
  502. self.dump_monitor()
  503. cmd = "P2P_CONNECT " + go_addr + " " + pin + " join"
  504. if "OK" in self.global_request(cmd):
  505. if timeout == 0:
  506. self.dump_monitor()
  507. return None
  508. ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
  509. if ev is None:
  510. raise Exception("Joining the group timed out")
  511. self.dump_monitor()
  512. return self.group_form_result(ev)
  513. raise Exception("P2P_CONNECT(join) failed")
  514. def tdls_setup(self, peer):
  515. cmd = "TDLS_SETUP " + peer
  516. if "FAIL" in self.group_request(cmd):
  517. raise Exception("Failed to request TDLS setup")
  518. return None
  519. def tdls_teardown(self, peer):
  520. cmd = "TDLS_TEARDOWN " + peer
  521. if "FAIL" in self.group_request(cmd):
  522. raise Exception("Failed to request TDLS teardown")
  523. return None
  524. def connect(self, ssid=None, ssid2=None, **kwargs):
  525. logger.info("Connect STA " + self.ifname + " to AP")
  526. id = self.add_network()
  527. if ssid:
  528. self.set_network_quoted(id, "ssid", ssid)
  529. elif ssid2:
  530. self.set_network(id, "ssid", ssid2)
  531. quoted = [ "psk", "identity", "anonymous_identity", "password",
  532. "ca_cert", "client_cert", "private_key",
  533. "private_key_passwd", "ca_cert2", "client_cert2",
  534. "private_key2", "phase1", "phase2", "domain_suffix_match",
  535. "altsubject_match", "subject_match", "pac_file", "dh_file" ]
  536. for field in quoted:
  537. if field in kwargs and kwargs[field]:
  538. self.set_network_quoted(id, field, kwargs[field])
  539. not_quoted = [ "proto", "key_mgmt", "ieee80211w", "pairwise",
  540. "group", "wep_key0", "scan_freq", "eap",
  541. "eapol_flags", "fragment_size", "scan_ssid", "auth_alg" ]
  542. for field in not_quoted:
  543. if field in kwargs and kwargs[field]:
  544. self.set_network(id, field, kwargs[field])
  545. if "raw_psk" in kwargs and kwargs['raw_psk']:
  546. self.set_network(id, "psk", kwargs['raw_psk'])
  547. if "password_hex" in kwargs and kwargs['password_hex']:
  548. self.set_network(id, "password", kwargs['password_hex'])
  549. if "peerkey" in kwargs and kwargs['peerkey']:
  550. self.set_network(id, "peerkey", "1")
  551. if "okc" in kwargs and kwargs['okc']:
  552. self.set_network(id, "proactive_key_caching", "1")
  553. if "ocsp" in kwargs and kwargs['ocsp']:
  554. self.set_network(id, "ocsp", str(kwargs['ocsp']))
  555. if "only_add_network" in kwargs and kwargs['only_add_network']:
  556. return id
  557. if "wait_connect" not in kwargs or kwargs['wait_connect']:
  558. if "eap" in kwargs:
  559. self.connect_network(id, timeout=20)
  560. else:
  561. self.connect_network(id)
  562. else:
  563. self.dump_monitor()
  564. self.select_network(id)
  565. return id
  566. def scan(self, type=None, freq=None, no_wait=False):
  567. if type:
  568. cmd = "SCAN TYPE=" + type
  569. else:
  570. cmd = "SCAN"
  571. if freq:
  572. cmd = cmd + " freq=" + freq
  573. if not no_wait:
  574. self.dump_monitor()
  575. if not "OK" in self.request(cmd):
  576. raise Exception("Failed to trigger scan")
  577. if no_wait:
  578. return
  579. ev = self.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
  580. if ev is None:
  581. raise Exception("Scan timed out")
  582. def roam(self, bssid):
  583. self.dump_monitor()
  584. self.request("ROAM " + bssid)
  585. ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
  586. if ev is None:
  587. raise Exception("Roaming with the AP timed out")
  588. self.dump_monitor()
  589. def roam_over_ds(self, bssid):
  590. self.dump_monitor()
  591. self.request("FT_DS " + bssid)
  592. ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
  593. if ev is None:
  594. raise Exception("Roaming with the AP timed out")
  595. self.dump_monitor()
  596. def wps_reg(self, bssid, pin, new_ssid=None, key_mgmt=None, cipher=None,
  597. new_passphrase=None, no_wait=False):
  598. self.dump_monitor()
  599. if new_ssid:
  600. self.request("WPS_REG " + bssid + " " + pin + " " +
  601. new_ssid.encode("hex") + " " + key_mgmt + " " +
  602. cipher + " " + new_passphrase.encode("hex"))
  603. if no_wait:
  604. return
  605. ev = self.wait_event(["WPS-SUCCESS"], timeout=15)
  606. else:
  607. self.request("WPS_REG " + bssid + " " + pin)
  608. if no_wait:
  609. return
  610. ev = self.wait_event(["WPS-CRED-RECEIVED"], timeout=15)
  611. if ev is None:
  612. raise Exception("WPS cred timed out")
  613. ev = self.wait_event(["WPS-FAIL"], timeout=15)
  614. if ev is None:
  615. raise Exception("WPS timed out")
  616. ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
  617. if ev is None:
  618. raise Exception("Association with the AP timed out")
  619. def relog(self):
  620. self.request("RELOG")
  621. def wait_completed(self, timeout=10):
  622. for i in range(0, timeout * 2):
  623. if self.get_status_field("wpa_state") == "COMPLETED":
  624. return
  625. time.sleep(0.5)
  626. raise Exception("Timeout while waiting for COMPLETED state")
  627. def get_capability(self, field):
  628. res = self.request("GET_CAPABILITY " + field)
  629. if "FAIL" in res:
  630. return None
  631. return res.split(' ')
  632. def get_bss(self, bssid):
  633. res = self.request("BSS " + bssid)
  634. lines = res.splitlines()
  635. vals = dict()
  636. for l in lines:
  637. [name,value] = l.split('=', 1)
  638. vals[name] = value
  639. return vals
  640. def get_pmksa(self, bssid):
  641. res = self.request("PMKSA")
  642. lines = res.splitlines()
  643. for l in lines:
  644. if bssid not in l:
  645. continue
  646. vals = dict()
  647. [index,aa,pmkid,expiration,opportunistic] = l.split(' ')
  648. vals['index'] = index
  649. vals['pmkid'] = pmkid
  650. vals['expiration'] = expiration
  651. vals['opportunistic'] = opportunistic
  652. return vals
  653. return None
  654. def get_sta(self, addr, info=None, next=False):
  655. cmd = "STA-NEXT " if next else "STA "
  656. if addr is None:
  657. res = self.request("STA-FIRST")
  658. elif info:
  659. res = self.request(cmd + addr + " " + info)
  660. else:
  661. res = self.request(cmd + addr)
  662. lines = res.splitlines()
  663. vals = dict()
  664. first = True
  665. for l in lines:
  666. if first:
  667. vals['addr'] = l
  668. first = False
  669. else:
  670. [name,value] = l.split('=', 1)
  671. vals[name] = value
  672. return vals