1# Python class for controlling hostapd 2# Copyright (c) 2013-2019, 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 7import os 8import re 9import time 10import logging 11import binascii 12import struct 13import tempfile 14import wpaspy 15import remotehost 16import utils 17import subprocess 18 19logger = logging.getLogger() 20hapd_ctrl = '/var/run/hostapd' 21hapd_global = '/var/run/hostapd-global' 22 23def mac2tuple(mac): 24 return struct.unpack('6B', binascii.unhexlify(mac.replace(':', ''))) 25 26class HostapdGlobal: 27 def __init__(self, apdev=None, global_ctrl_override=None): 28 try: 29 hostname = apdev['hostname'] 30 port = apdev['port'] 31 except: 32 hostname = None 33 port = 8878 34 self.host = remotehost.Host(hostname) 35 self.hostname = hostname 36 self.port = port 37 if hostname is None: 38 global_ctrl = hapd_global 39 if global_ctrl_override: 40 global_ctrl = global_ctrl_override 41 self.ctrl = wpaspy.Ctrl(global_ctrl) 42 self.mon = wpaspy.Ctrl(global_ctrl) 43 self.dbg = "" 44 else: 45 self.ctrl = wpaspy.Ctrl(hostname, port) 46 self.mon = wpaspy.Ctrl(hostname, port) 47 self.dbg = hostname + "/" + str(port) 48 self.mon.attach() 49 50 def cmd_execute(self, cmd_array, shell=False): 51 if self.hostname is None: 52 if shell: 53 cmd = ' '.join(cmd_array) 54 else: 55 cmd = cmd_array 56 proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT, 57 stdout=subprocess.PIPE, shell=shell) 58 out = proc.communicate()[0] 59 ret = proc.returncode 60 return ret, out.decode() 61 else: 62 return self.host.execute(cmd_array) 63 64 def request(self, cmd, timeout=10): 65 logger.debug(self.dbg + ": CTRL(global): " + cmd) 66 return self.ctrl.request(cmd, timeout) 67 68 def wait_event(self, events, timeout): 69 start = os.times()[4] 70 while True: 71 while self.mon.pending(): 72 ev = self.mon.recv() 73 logger.debug(self.dbg + "(global): " + ev) 74 for event in events: 75 if event in ev: 76 return ev 77 now = os.times()[4] 78 remaining = start + timeout - now 79 if remaining <= 0: 80 break 81 if not self.mon.pending(timeout=remaining): 82 break 83 return None 84 85 def add(self, ifname, driver=None): 86 cmd = "ADD " + ifname + " " + hapd_ctrl 87 if driver: 88 cmd += " " + driver 89 res = self.request(cmd) 90 if "OK" not in res: 91 raise Exception("Could not add hostapd interface " + ifname) 92 93 def add_iface(self, ifname, confname): 94 res = self.request("ADD " + ifname + " config=" + confname) 95 if "OK" not in res: 96 raise Exception("Could not add hostapd interface") 97 98 def add_bss(self, phy, confname, ignore_error=False): 99 res = self.request("ADD bss_config=" + phy + ":" + confname) 100 if "OK" not in res: 101 if not ignore_error: 102 raise Exception("Could not add hostapd BSS") 103 104 def remove(self, ifname): 105 self.request("REMOVE " + ifname, timeout=30) 106 107 def relog(self): 108 self.request("RELOG") 109 110 def flush(self): 111 self.request("FLUSH") 112 113 def get_ctrl_iface_port(self, ifname): 114 if self.hostname is None: 115 return None 116 117 res = self.request("INTERFACES ctrl") 118 lines = res.splitlines() 119 found = False 120 for line in lines: 121 words = line.split() 122 if words[0] == ifname: 123 found = True 124 break 125 if not found: 126 raise Exception("Could not find UDP port for " + ifname) 127 res = line.find("ctrl_iface=udp:") 128 if res == -1: 129 raise Exception("Wrong ctrl_interface format") 130 words = line.split(":") 131 return int(words[1]) 132 133 def terminate(self): 134 self.mon.detach() 135 self.mon.close() 136 self.mon = None 137 self.ctrl.terminate() 138 self.ctrl = None 139 140 def send_file(self, src, dst): 141 self.host.send_file(src, dst) 142 143class Hostapd: 144 def __init__(self, ifname, bssidx=0, hostname=None, port=8877): 145 self.hostname = hostname 146 self.host = remotehost.Host(hostname, ifname) 147 self.ifname = ifname 148 if hostname is None: 149 self.ctrl = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname)) 150 self.mon = wpaspy.Ctrl(os.path.join(hapd_ctrl, ifname)) 151 self.dbg = ifname 152 else: 153 self.ctrl = wpaspy.Ctrl(hostname, port) 154 self.mon = wpaspy.Ctrl(hostname, port) 155 self.dbg = hostname + "/" + ifname 156 self.mon.attach() 157 self.bssid = None 158 self.bssidx = bssidx 159 160 def cmd_execute(self, cmd_array, shell=False): 161 if self.hostname is None: 162 if shell: 163 cmd = ' '.join(cmd_array) 164 else: 165 cmd = cmd_array 166 proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT, 167 stdout=subprocess.PIPE, shell=shell) 168 out = proc.communicate()[0] 169 ret = proc.returncode 170 return ret, out.decode() 171 else: 172 return self.host.execute(cmd_array) 173 174 def close_ctrl(self): 175 if self.mon is not None: 176 self.mon.detach() 177 self.mon.close() 178 self.mon = None 179 self.ctrl.close() 180 self.ctrl = None 181 182 def own_addr(self): 183 if self.bssid is None: 184 self.bssid = self.get_status_field('bssid[%d]' % self.bssidx) 185 return self.bssid 186 187 def get_addr(self, group=False): 188 return self.own_addr() 189 190 def request(self, cmd): 191 logger.debug(self.dbg + ": CTRL: " + cmd) 192 return self.ctrl.request(cmd) 193 194 def ping(self): 195 return "PONG" in self.request("PING") 196 197 def set(self, field, value): 198 if "OK" not in self.request("SET " + field + " " + value): 199 if "TKIP" in value and (field == "wpa_pairwise" or \ 200 field == "rsn_pairwise"): 201 raise utils.HwsimSkip("Cipher TKIP not supported") 202 raise Exception("Failed to set hostapd parameter " + field) 203 204 def set_defaults(self): 205 self.set("driver", "nl80211") 206 self.set("hw_mode", "g") 207 self.set("channel", "1") 208 self.set("ieee80211n", "1") 209 self.set("logger_stdout", "-1") 210 self.set("logger_stdout_level", "0") 211 212 def set_open(self, ssid): 213 self.set_defaults() 214 self.set("ssid", ssid) 215 216 def set_wpa2_psk(self, ssid, passphrase): 217 self.set_defaults() 218 self.set("ssid", ssid) 219 self.set("wpa_passphrase", passphrase) 220 self.set("wpa", "2") 221 self.set("wpa_key_mgmt", "WPA-PSK") 222 self.set("rsn_pairwise", "CCMP") 223 224 def set_wpa_psk(self, ssid, passphrase): 225 self.set_defaults() 226 self.set("ssid", ssid) 227 self.set("wpa_passphrase", passphrase) 228 self.set("wpa", "1") 229 self.set("wpa_key_mgmt", "WPA-PSK") 230 self.set("wpa_pairwise", "TKIP") 231 232 def set_wpa_psk_mixed(self, ssid, passphrase): 233 self.set_defaults() 234 self.set("ssid", ssid) 235 self.set("wpa_passphrase", passphrase) 236 self.set("wpa", "3") 237 self.set("wpa_key_mgmt", "WPA-PSK") 238 self.set("wpa_pairwise", "TKIP") 239 self.set("rsn_pairwise", "CCMP") 240 241 def set_wep(self, ssid, key): 242 self.set_defaults() 243 self.set("ssid", ssid) 244 self.set("wep_key0", key) 245 246 def enable(self): 247 if "OK" not in self.request("ENABLE"): 248 raise Exception("Failed to enable hostapd interface " + self.ifname) 249 250 def disable(self): 251 if "OK" not in self.request("DISABLE"): 252 raise Exception("Failed to disable hostapd interface " + self.ifname) 253 254 def dump_monitor(self): 255 while self.mon.pending(): 256 ev = self.mon.recv() 257 logger.debug(self.dbg + ": " + ev) 258 259 def wait_event(self, events, timeout): 260 if not isinstance(events, list): 261 raise Exception("Hostapd.wait_event() called with incorrect events argument type") 262 start = os.times()[4] 263 while True: 264 while self.mon.pending(): 265 ev = self.mon.recv() 266 logger.debug(self.dbg + ": " + ev) 267 for event in events: 268 if event in ev: 269 return ev 270 now = os.times()[4] 271 remaining = start + timeout - now 272 if remaining <= 0: 273 break 274 if not self.mon.pending(timeout=remaining): 275 break 276 return None 277 278 def wait_sta(self, addr=None, timeout=2): 279 ev = self.wait_event(["AP-STA-CONNECT"], timeout=timeout) 280 if ev is None: 281 raise Exception("AP did not report STA connection") 282 if addr and addr not in ev: 283 raise Exception("Unexpected STA address in connection event: " + ev) 284 285 def wait_ptkinitdone(self, addr, timeout=2): 286 while timeout > 0: 287 sta = self.get_sta(addr) 288 if 'hostapdWPAPTKState' not in sta: 289 raise Exception("GET_STA did not return hostapdWPAPTKState") 290 state = sta['hostapdWPAPTKState'] 291 if state == "11": 292 return 293 time.sleep(0.1) 294 timeout -= 0.1 295 raise Exception("Timeout while waiting for PTKINITDONE") 296 297 def get_status(self): 298 res = self.request("STATUS") 299 lines = res.splitlines() 300 vals = dict() 301 for l in lines: 302 [name, value] = l.split('=', 1) 303 vals[name] = value 304 return vals 305 306 def get_status_field(self, field): 307 vals = self.get_status() 308 if field in vals: 309 return vals[field] 310 return None 311 312 def get_driver_status(self): 313 res = self.request("STATUS-DRIVER") 314 lines = res.splitlines() 315 vals = dict() 316 for l in lines: 317 [name, value] = l.split('=', 1) 318 vals[name] = value 319 return vals 320 321 def get_driver_status_field(self, field): 322 vals = self.get_driver_status() 323 if field in vals: 324 return vals[field] 325 return None 326 327 def get_config(self): 328 res = self.request("GET_CONFIG") 329 lines = res.splitlines() 330 vals = dict() 331 for l in lines: 332 [name, value] = l.split('=', 1) 333 vals[name] = value 334 return vals 335 336 def mgmt_rx(self, timeout=5): 337 ev = self.wait_event(["MGMT-RX"], timeout=timeout) 338 if ev is None: 339 return None 340 msg = {} 341 frame = binascii.unhexlify(ev.split(' ')[1]) 342 msg['frame'] = frame 343 344 hdr = struct.unpack('<HH6B6B6BH', frame[0:24]) 345 msg['fc'] = hdr[0] 346 msg['subtype'] = (hdr[0] >> 4) & 0xf 347 hdr = hdr[1:] 348 msg['duration'] = hdr[0] 349 hdr = hdr[1:] 350 msg['da'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6] 351 hdr = hdr[6:] 352 msg['sa'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6] 353 hdr = hdr[6:] 354 msg['bssid'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6] 355 hdr = hdr[6:] 356 msg['seq_ctrl'] = hdr[0] 357 msg['payload'] = frame[24:] 358 359 return msg 360 361 def mgmt_tx(self, msg): 362 t = (msg['fc'], 0) + mac2tuple(msg['da']) + mac2tuple(msg['sa']) + mac2tuple(msg['bssid']) + (0,) 363 hdr = struct.pack('<HH6B6B6BH', *t) 364 res = self.request("MGMT_TX " + binascii.hexlify(hdr + msg['payload']).decode()) 365 if "OK" not in res: 366 raise Exception("MGMT_TX command to hostapd failed") 367 368 def get_sta(self, addr, info=None, next=False): 369 cmd = "STA-NEXT " if next else "STA " 370 if addr is None: 371 res = self.request("STA-FIRST") 372 elif info: 373 res = self.request(cmd + addr + " " + info) 374 else: 375 res = self.request(cmd + addr) 376 lines = res.splitlines() 377 vals = dict() 378 first = True 379 for l in lines: 380 if first and '=' not in l: 381 vals['addr'] = l 382 first = False 383 else: 384 [name, value] = l.split('=', 1) 385 vals[name] = value 386 return vals 387 388 def get_mib(self, param=None): 389 if param: 390 res = self.request("MIB " + param) 391 else: 392 res = self.request("MIB") 393 lines = res.splitlines() 394 vals = dict() 395 for l in lines: 396 name_val = l.split('=', 1) 397 if len(name_val) > 1: 398 vals[name_val[0]] = name_val[1] 399 return vals 400 401 def get_pmksa(self, addr): 402 res = self.request("PMKSA") 403 lines = res.splitlines() 404 for l in lines: 405 if addr not in l: 406 continue 407 vals = dict() 408 [index, aa, pmkid, expiration, opportunistic] = l.split(' ') 409 vals['index'] = index 410 vals['pmkid'] = pmkid 411 vals['expiration'] = expiration 412 vals['opportunistic'] = opportunistic 413 return vals 414 return None 415 416 def dpp_qr_code(self, uri): 417 res = self.request("DPP_QR_CODE " + uri) 418 if "FAIL" in res: 419 raise Exception("Failed to parse QR Code URI") 420 return int(res) 421 422 def dpp_nfc_uri(self, uri): 423 res = self.request("DPP_NFC_URI " + uri) 424 if "FAIL" in res: 425 raise Exception("Failed to parse NFC URI") 426 return int(res) 427 428 def dpp_bootstrap_gen(self, type="qrcode", chan=None, mac=None, info=None, 429 curve=None, key=None): 430 cmd = "DPP_BOOTSTRAP_GEN type=" + type 431 if chan: 432 cmd += " chan=" + chan 433 if mac: 434 if mac is True: 435 mac = self.own_addr() 436 cmd += " mac=" + mac.replace(':', '') 437 if info: 438 cmd += " info=" + info 439 if curve: 440 cmd += " curve=" + curve 441 if key: 442 cmd += " key=" + key 443 res = self.request(cmd) 444 if "FAIL" in res: 445 raise Exception("Failed to generate bootstrapping info") 446 return int(res) 447 448 def dpp_bootstrap_set(self, id, conf=None, configurator=None, ssid=None, 449 extra=None): 450 cmd = "DPP_BOOTSTRAP_SET %d" % id 451 if ssid: 452 cmd += " ssid=" + binascii.hexlify(ssid.encode()).decode() 453 if extra: 454 cmd += " " + extra 455 if conf: 456 cmd += " conf=" + conf 457 if configurator is not None: 458 cmd += " configurator=%d" % configurator 459 if "OK" not in self.request(cmd): 460 raise Exception("Failed to set bootstrapping parameters") 461 462 def dpp_listen(self, freq, netrole=None, qr=None, role=None): 463 cmd = "DPP_LISTEN " + str(freq) 464 if netrole: 465 cmd += " netrole=" + netrole 466 if qr: 467 cmd += " qr=" + qr 468 if role: 469 cmd += " role=" + role 470 if "OK" not in self.request(cmd): 471 raise Exception("Failed to start listen operation") 472 473 def dpp_auth_init(self, peer=None, uri=None, conf=None, configurator=None, 474 extra=None, own=None, role=None, neg_freq=None, 475 ssid=None, passphrase=None, expect_fail=False, 476 conn_status=False, nfc_uri=None): 477 cmd = "DPP_AUTH_INIT" 478 if peer is None: 479 if nfc_uri: 480 peer = self.dpp_nfc_uri(nfc_uri) 481 else: 482 peer = self.dpp_qr_code(uri) 483 cmd += " peer=%d" % peer 484 if own is not None: 485 cmd += " own=%d" % own 486 if role: 487 cmd += " role=" + role 488 if extra: 489 cmd += " " + extra 490 if conf: 491 cmd += " conf=" + conf 492 if configurator is not None: 493 cmd += " configurator=%d" % configurator 494 if neg_freq: 495 cmd += " neg_freq=%d" % neg_freq 496 if ssid: 497 cmd += " ssid=" + binascii.hexlify(ssid.encode()).decode() 498 if passphrase: 499 cmd += " pass=" + binascii.hexlify(passphrase.encode()).decode() 500 if conn_status: 501 cmd += " conn_status=1" 502 res = self.request(cmd) 503 if expect_fail: 504 if "FAIL" not in res: 505 raise Exception("DPP authentication started unexpectedly") 506 return 507 if "OK" not in res: 508 raise Exception("Failed to initiate DPP Authentication") 509 510 def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None, 511 extra=None, use_id=None, ver=None): 512 if use_id is None: 513 id1 = self.dpp_bootstrap_gen(type="pkex", key=key, curve=curve) 514 else: 515 id1 = use_id 516 cmd = "own=%d " % id1 517 if identifier: 518 cmd += "identifier=%s " % identifier 519 cmd += "init=1 " 520 if ver is not None: 521 cmd += "ver=" + str(ver) + " " 522 if role: 523 cmd += "role=%s " % role 524 if extra: 525 cmd += extra + " " 526 cmd += "code=%s" % code 527 res = self.request("DPP_PKEX_ADD " + cmd) 528 if "FAIL" in res: 529 raise Exception("Failed to set PKEX data (initiator)") 530 return id1 531 532 def dpp_pkex_resp(self, freq, identifier, code, key=None, curve=None, 533 listen_role=None): 534 id0 = self.dpp_bootstrap_gen(type="pkex", key=key, curve=curve) 535 cmd = "own=%d " % id0 536 if identifier: 537 cmd += "identifier=%s " % identifier 538 cmd += "code=%s" % code 539 res = self.request("DPP_PKEX_ADD " + cmd) 540 if "FAIL" in res: 541 raise Exception("Failed to set PKEX data (responder)") 542 self.dpp_listen(freq, role=listen_role) 543 544 def dpp_configurator_add(self, curve=None, key=None, 545 net_access_key_curve=None): 546 cmd = "DPP_CONFIGURATOR_ADD" 547 if curve: 548 cmd += " curve=" + curve 549 if net_access_key_curve: 550 cmd += " net_access_key_curve=" + curve 551 if key: 552 cmd += " key=" + key 553 res = self.request(cmd) 554 if "FAIL" in res: 555 raise Exception("Failed to add configurator") 556 return int(res) 557 558 def dpp_configurator_remove(self, conf_id): 559 res = self.request("DPP_CONFIGURATOR_REMOVE %d" % conf_id) 560 if "OK" not in res: 561 raise Exception("DPP_CONFIGURATOR_REMOVE failed") 562 563 def note(self, txt): 564 self.request("NOTE " + txt) 565 566 def send_file(self, src, dst): 567 self.host.send_file(src, dst) 568 569 def get_ptksa(self, bssid, cipher): 570 res = self.request("PTKSA_CACHE_LIST") 571 lines = res.splitlines() 572 for l in lines: 573 if bssid not in l or cipher not in l: 574 continue 575 vals = dict() 576 [index, addr, cipher, expiration, tk, kdk] = l.split(' ', 5) 577 vals['index'] = index 578 vals['addr'] = addr 579 vals['cipher'] = cipher 580 vals['expiration'] = expiration 581 vals['tk'] = tk 582 vals['kdk'] = kdk 583 return vals 584 return None 585 586def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30, 587 global_ctrl_override=None, driver=False): 588 if isinstance(apdev, dict): 589 ifname = apdev['ifname'] 590 try: 591 hostname = apdev['hostname'] 592 port = apdev['port'] 593 logger.info("Starting AP " + hostname + "/" + port + " " + ifname) 594 except: 595 logger.info("Starting AP " + ifname) 596 hostname = None 597 port = 8878 598 else: 599 ifname = apdev 600 logger.info("Starting AP " + ifname + " (old add_ap argument type)") 601 hostname = None 602 port = 8878 603 hapd_global = HostapdGlobal(apdev, 604 global_ctrl_override=global_ctrl_override) 605 hapd_global.remove(ifname) 606 hapd_global.add(ifname, driver=driver) 607 port = hapd_global.get_ctrl_iface_port(ifname) 608 hapd = Hostapd(ifname, hostname=hostname, port=port) 609 if not hapd.ping(): 610 raise Exception("Could not ping hostapd") 611 hapd.set_defaults() 612 fields = ["ssid", "wpa_passphrase", "nas_identifier", "wpa_key_mgmt", 613 "wpa", "wpa_deny_ptk0_rekey", 614 "wpa_pairwise", "rsn_pairwise", "auth_server_addr", 615 "acct_server_addr", "osu_server_uri"] 616 for field in fields: 617 if field in params: 618 hapd.set(field, params[field]) 619 for f, v in list(params.items()): 620 if f in fields: 621 continue 622 if isinstance(v, list): 623 for val in v: 624 hapd.set(f, val) 625 else: 626 hapd.set(f, v) 627 if no_enable: 628 return hapd 629 hapd.enable() 630 if wait_enabled: 631 ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=timeout) 632 if ev is None: 633 raise Exception("AP startup timed out") 634 if "AP-ENABLED" not in ev: 635 raise Exception("AP startup failed") 636 return hapd 637 638def add_bss(apdev, ifname, confname, ignore_error=False): 639 phy = utils.get_phy(apdev) 640 try: 641 hostname = apdev['hostname'] 642 port = apdev['port'] 643 logger.info("Starting BSS " + hostname + "/" + port + " phy=" + phy + " ifname=" + ifname) 644 except: 645 logger.info("Starting BSS phy=" + phy + " ifname=" + ifname) 646 hostname = None 647 port = 8878 648 hapd_global = HostapdGlobal(apdev) 649 confname = cfg_file(apdev, confname, ifname) 650 hapd_global.send_file(confname, confname) 651 hapd_global.add_bss(phy, confname, ignore_error) 652 port = hapd_global.get_ctrl_iface_port(ifname) 653 hapd = Hostapd(ifname, hostname=hostname, port=port) 654 if not hapd.ping(): 655 raise Exception("Could not ping hostapd") 656 return hapd 657 658def add_iface(apdev, confname): 659 ifname = apdev['ifname'] 660 try: 661 hostname = apdev['hostname'] 662 port = apdev['port'] 663 logger.info("Starting interface " + hostname + "/" + port + " " + ifname) 664 except: 665 logger.info("Starting interface " + ifname) 666 hostname = None 667 port = 8878 668 hapd_global = HostapdGlobal(apdev) 669 confname = cfg_file(apdev, confname, ifname) 670 hapd_global.send_file(confname, confname) 671 hapd_global.add_iface(ifname, confname) 672 port = hapd_global.get_ctrl_iface_port(ifname) 673 hapd = Hostapd(ifname, hostname=hostname, port=port) 674 if not hapd.ping(): 675 raise Exception("Could not ping hostapd") 676 return hapd 677 678def remove_bss(apdev, ifname=None): 679 if ifname == None: 680 ifname = apdev['ifname'] 681 try: 682 hostname = apdev['hostname'] 683 port = apdev['port'] 684 logger.info("Removing BSS " + hostname + "/" + port + " " + ifname) 685 except: 686 logger.info("Removing BSS " + ifname) 687 hapd_global = HostapdGlobal(apdev) 688 hapd_global.remove(ifname) 689 690def terminate(apdev): 691 try: 692 hostname = apdev['hostname'] 693 port = apdev['port'] 694 logger.info("Terminating hostapd " + hostname + "/" + port) 695 except: 696 logger.info("Terminating hostapd") 697 hapd_global = HostapdGlobal(apdev) 698 hapd_global.terminate() 699 700def wpa2_params(ssid=None, passphrase=None, wpa_key_mgmt="WPA-PSK", 701 ieee80211w=None): 702 params = {"wpa": "2", 703 "wpa_key_mgmt": wpa_key_mgmt, 704 "rsn_pairwise": "CCMP"} 705 if ssid: 706 params["ssid"] = ssid 707 if passphrase: 708 params["wpa_passphrase"] = passphrase 709 if ieee80211w is not None: 710 params["ieee80211w"] = ieee80211w 711 return params 712 713def wpa_params(ssid=None, passphrase=None): 714 params = {"wpa": "1", 715 "wpa_key_mgmt": "WPA-PSK", 716 "wpa_pairwise": "TKIP"} 717 if ssid: 718 params["ssid"] = ssid 719 if passphrase: 720 params["wpa_passphrase"] = passphrase 721 return params 722 723def wpa_mixed_params(ssid=None, passphrase=None): 724 params = {"wpa": "3", 725 "wpa_key_mgmt": "WPA-PSK", 726 "wpa_pairwise": "TKIP", 727 "rsn_pairwise": "CCMP"} 728 if ssid: 729 params["ssid"] = ssid 730 if passphrase: 731 params["wpa_passphrase"] = passphrase 732 return params 733 734def radius_params(): 735 params = {"auth_server_addr": "127.0.0.1", 736 "auth_server_port": "1812", 737 "auth_server_shared_secret": "radius", 738 "nas_identifier": "nas.w1.fi"} 739 return params 740 741def wpa_eap_params(ssid=None): 742 params = radius_params() 743 params["wpa"] = "1" 744 params["wpa_key_mgmt"] = "WPA-EAP" 745 params["wpa_pairwise"] = "TKIP" 746 params["ieee8021x"] = "1" 747 if ssid: 748 params["ssid"] = ssid 749 return params 750 751def wpa2_eap_params(ssid=None): 752 params = radius_params() 753 params["wpa"] = "2" 754 params["wpa_key_mgmt"] = "WPA-EAP" 755 params["rsn_pairwise"] = "CCMP" 756 params["ieee8021x"] = "1" 757 if ssid: 758 params["ssid"] = ssid 759 return params 760 761def b_only_params(channel="1", ssid=None, country=None): 762 params = {"hw_mode": "b", 763 "channel": channel} 764 if ssid: 765 params["ssid"] = ssid 766 if country: 767 params["country_code"] = country 768 return params 769 770def g_only_params(channel="1", ssid=None, country=None): 771 params = {"hw_mode": "g", 772 "channel": channel} 773 if ssid: 774 params["ssid"] = ssid 775 if country: 776 params["country_code"] = country 777 return params 778 779def a_only_params(channel="36", ssid=None, country=None): 780 params = {"hw_mode": "a", 781 "channel": channel} 782 if ssid: 783 params["ssid"] = ssid 784 if country: 785 params["country_code"] = country 786 return params 787 788def ht20_params(channel="1", ssid=None, country=None): 789 params = {"ieee80211n": "1", 790 "channel": channel, 791 "hw_mode": "g"} 792 if int(channel) > 14: 793 params["hw_mode"] = "a" 794 if ssid: 795 params["ssid"] = ssid 796 if country: 797 params["country_code"] = country 798 return params 799 800def ht40_plus_params(channel="1", ssid=None, country=None): 801 params = ht20_params(channel, ssid, country) 802 params['ht_capab'] = "[HT40+]" 803 return params 804 805def ht40_minus_params(channel="1", ssid=None, country=None): 806 params = ht20_params(channel, ssid, country) 807 params['ht_capab'] = "[HT40-]" 808 return params 809 810def cmd_execute(apdev, cmd, shell=False): 811 hapd_global = HostapdGlobal(apdev) 812 return hapd_global.cmd_execute(cmd, shell=shell) 813 814def send_file(apdev, src, dst): 815 hapd_global = HostapdGlobal(apdev) 816 return hapd_global.send_file(src, dst) 817 818def acl_file(dev, apdev, conf): 819 fd, filename = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') 820 f = os.fdopen(fd, 'w') 821 822 if conf == 'hostapd.macaddr': 823 mac0 = dev[0].get_status_field("address") 824 f.write(mac0 + '\n') 825 f.write("02:00:00:00:00:12\n") 826 f.write("02:00:00:00:00:34\n") 827 f.write("-02:00:00:00:00:12\n") 828 f.write("-02:00:00:00:00:34\n") 829 f.write("01:01:01:01:01:01\n") 830 f.write("03:01:01:01:01:03\n") 831 elif conf == 'hostapd.accept': 832 mac0 = dev[0].get_status_field("address") 833 mac1 = dev[1].get_status_field("address") 834 f.write(mac0 + " 1\n") 835 f.write(mac1 + " 2\n") 836 elif conf == 'hostapd.accept2': 837 mac0 = dev[0].get_status_field("address") 838 mac1 = dev[1].get_status_field("address") 839 mac2 = dev[2].get_status_field("address") 840 f.write(mac0 + " 1\n") 841 f.write(mac1 + " 2\n") 842 f.write(mac2 + " 3\n") 843 else: 844 f.close() 845 os.unlink(filename) 846 return conf 847 848 return filename 849 850def bssid_inc(apdev, inc=1): 851 parts = apdev['bssid'].split(':') 852 parts[5] = '%02x' % (int(parts[5], 16) + int(inc)) 853 bssid = '%s:%s:%s:%s:%s:%s' % (parts[0], parts[1], parts[2], 854 parts[3], parts[4], parts[5]) 855 return bssid 856 857def cfg_file(apdev, conf, ifname=None): 858 match = re.search(r'^bss-.+', conf) 859 if match: 860 # put cfg file in /tmp directory 861 fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') 862 f = os.fdopen(fd, 'w') 863 idx = ''.join(filter(str.isdigit, conf.split('-')[-1])) 864 if ifname is None: 865 ifname = apdev['ifname'] 866 if idx != '1': 867 ifname = ifname + '-' + idx 868 869 f.write("driver=nl80211\n") 870 f.write("ctrl_interface=/var/run/hostapd\n") 871 f.write("hw_mode=g\n") 872 f.write("channel=1\n") 873 f.write("ieee80211n=1\n") 874 if conf.startswith('bss-ht40-'): 875 f.write("ht_capab=[HT40+]\n") 876 f.write("interface=%s\n" % ifname) 877 878 f.write("ssid=bss-%s\n" % idx) 879 if conf == 'bss-2-dup.conf': 880 bssid = apdev['bssid'] 881 else: 882 bssid = bssid_inc(apdev, int(idx) - 1) 883 f.write("bssid=%s\n" % bssid) 884 885 return fname 886 887 return conf 888