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): 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 role: 521 cmd += "role=%s " % role 522 if extra: 523 cmd += extra + " " 524 cmd += "code=%s" % code 525 res = self.request("DPP_PKEX_ADD " + cmd) 526 if "FAIL" in res: 527 raise Exception("Failed to set PKEX data (initiator)") 528 return id1 529 530 def dpp_pkex_resp(self, freq, identifier, code, key=None, curve=None, 531 listen_role=None): 532 id0 = self.dpp_bootstrap_gen(type="pkex", key=key, curve=curve) 533 cmd = "own=%d " % id0 534 if identifier: 535 cmd += "identifier=%s " % identifier 536 cmd += "code=%s" % code 537 res = self.request("DPP_PKEX_ADD " + cmd) 538 if "FAIL" in res: 539 raise Exception("Failed to set PKEX data (responder)") 540 self.dpp_listen(freq, role=listen_role) 541 542 def dpp_configurator_add(self, curve=None, key=None): 543 cmd = "DPP_CONFIGURATOR_ADD" 544 if curve: 545 cmd += " curve=" + curve 546 if key: 547 cmd += " key=" + key 548 res = self.request(cmd) 549 if "FAIL" in res: 550 raise Exception("Failed to add configurator") 551 return int(res) 552 553 def dpp_configurator_remove(self, conf_id): 554 res = self.request("DPP_CONFIGURATOR_REMOVE %d" % conf_id) 555 if "OK" not in res: 556 raise Exception("DPP_CONFIGURATOR_REMOVE failed") 557 558 def note(self, txt): 559 self.request("NOTE " + txt) 560 561 def send_file(self, src, dst): 562 self.host.send_file(src, dst) 563 564 def get_ptksa(self, bssid, cipher): 565 res = self.request("PTKSA_CACHE_LIST") 566 lines = res.splitlines() 567 for l in lines: 568 if bssid not in l or cipher not in l: 569 continue 570 vals = dict() 571 [index, addr, cipher, expiration, tk, kdk] = l.split(' ', 5) 572 vals['index'] = index 573 vals['addr'] = addr 574 vals['cipher'] = cipher 575 vals['expiration'] = expiration 576 vals['tk'] = tk 577 vals['kdk'] = kdk 578 return vals 579 return None 580 581def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30, 582 global_ctrl_override=None, driver=False): 583 if isinstance(apdev, dict): 584 ifname = apdev['ifname'] 585 try: 586 hostname = apdev['hostname'] 587 port = apdev['port'] 588 logger.info("Starting AP " + hostname + "/" + port + " " + ifname) 589 except: 590 logger.info("Starting AP " + ifname) 591 hostname = None 592 port = 8878 593 else: 594 ifname = apdev 595 logger.info("Starting AP " + ifname + " (old add_ap argument type)") 596 hostname = None 597 port = 8878 598 hapd_global = HostapdGlobal(apdev, 599 global_ctrl_override=global_ctrl_override) 600 hapd_global.remove(ifname) 601 hapd_global.add(ifname, driver=driver) 602 port = hapd_global.get_ctrl_iface_port(ifname) 603 hapd = Hostapd(ifname, hostname=hostname, port=port) 604 if not hapd.ping(): 605 raise Exception("Could not ping hostapd") 606 hapd.set_defaults() 607 fields = ["ssid", "wpa_passphrase", "nas_identifier", "wpa_key_mgmt", 608 "wpa", "wpa_deny_ptk0_rekey", 609 "wpa_pairwise", "rsn_pairwise", "auth_server_addr", 610 "acct_server_addr", "osu_server_uri"] 611 for field in fields: 612 if field in params: 613 hapd.set(field, params[field]) 614 for f, v in list(params.items()): 615 if f in fields: 616 continue 617 if isinstance(v, list): 618 for val in v: 619 hapd.set(f, val) 620 else: 621 hapd.set(f, v) 622 if no_enable: 623 return hapd 624 hapd.enable() 625 if wait_enabled: 626 ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=timeout) 627 if ev is None: 628 raise Exception("AP startup timed out") 629 if "AP-ENABLED" not in ev: 630 raise Exception("AP startup failed") 631 return hapd 632 633def add_bss(apdev, ifname, confname, ignore_error=False): 634 phy = utils.get_phy(apdev) 635 try: 636 hostname = apdev['hostname'] 637 port = apdev['port'] 638 logger.info("Starting BSS " + hostname + "/" + port + " phy=" + phy + " ifname=" + ifname) 639 except: 640 logger.info("Starting BSS phy=" + phy + " ifname=" + ifname) 641 hostname = None 642 port = 8878 643 hapd_global = HostapdGlobal(apdev) 644 confname = cfg_file(apdev, confname, ifname) 645 hapd_global.send_file(confname, confname) 646 hapd_global.add_bss(phy, confname, ignore_error) 647 port = hapd_global.get_ctrl_iface_port(ifname) 648 hapd = Hostapd(ifname, hostname=hostname, port=port) 649 if not hapd.ping(): 650 raise Exception("Could not ping hostapd") 651 return hapd 652 653def add_iface(apdev, confname): 654 ifname = apdev['ifname'] 655 try: 656 hostname = apdev['hostname'] 657 port = apdev['port'] 658 logger.info("Starting interface " + hostname + "/" + port + " " + ifname) 659 except: 660 logger.info("Starting interface " + ifname) 661 hostname = None 662 port = 8878 663 hapd_global = HostapdGlobal(apdev) 664 confname = cfg_file(apdev, confname, ifname) 665 hapd_global.send_file(confname, confname) 666 hapd_global.add_iface(ifname, confname) 667 port = hapd_global.get_ctrl_iface_port(ifname) 668 hapd = Hostapd(ifname, hostname=hostname, port=port) 669 if not hapd.ping(): 670 raise Exception("Could not ping hostapd") 671 return hapd 672 673def remove_bss(apdev, ifname=None): 674 if ifname == None: 675 ifname = apdev['ifname'] 676 try: 677 hostname = apdev['hostname'] 678 port = apdev['port'] 679 logger.info("Removing BSS " + hostname + "/" + port + " " + ifname) 680 except: 681 logger.info("Removing BSS " + ifname) 682 hapd_global = HostapdGlobal(apdev) 683 hapd_global.remove(ifname) 684 685def terminate(apdev): 686 try: 687 hostname = apdev['hostname'] 688 port = apdev['port'] 689 logger.info("Terminating hostapd " + hostname + "/" + port) 690 except: 691 logger.info("Terminating hostapd") 692 hapd_global = HostapdGlobal(apdev) 693 hapd_global.terminate() 694 695def wpa2_params(ssid=None, passphrase=None, wpa_key_mgmt="WPA-PSK", 696 ieee80211w=None): 697 params = {"wpa": "2", 698 "wpa_key_mgmt": wpa_key_mgmt, 699 "rsn_pairwise": "CCMP"} 700 if ssid: 701 params["ssid"] = ssid 702 if passphrase: 703 params["wpa_passphrase"] = passphrase 704 if ieee80211w is not None: 705 params["ieee80211w"] = ieee80211w 706 return params 707 708def wpa_params(ssid=None, passphrase=None): 709 params = {"wpa": "1", 710 "wpa_key_mgmt": "WPA-PSK", 711 "wpa_pairwise": "TKIP"} 712 if ssid: 713 params["ssid"] = ssid 714 if passphrase: 715 params["wpa_passphrase"] = passphrase 716 return params 717 718def wpa_mixed_params(ssid=None, passphrase=None): 719 params = {"wpa": "3", 720 "wpa_key_mgmt": "WPA-PSK", 721 "wpa_pairwise": "TKIP", 722 "rsn_pairwise": "CCMP"} 723 if ssid: 724 params["ssid"] = ssid 725 if passphrase: 726 params["wpa_passphrase"] = passphrase 727 return params 728 729def radius_params(): 730 params = {"auth_server_addr": "127.0.0.1", 731 "auth_server_port": "1812", 732 "auth_server_shared_secret": "radius", 733 "nas_identifier": "nas.w1.fi"} 734 return params 735 736def wpa_eap_params(ssid=None): 737 params = radius_params() 738 params["wpa"] = "1" 739 params["wpa_key_mgmt"] = "WPA-EAP" 740 params["wpa_pairwise"] = "TKIP" 741 params["ieee8021x"] = "1" 742 if ssid: 743 params["ssid"] = ssid 744 return params 745 746def wpa2_eap_params(ssid=None): 747 params = radius_params() 748 params["wpa"] = "2" 749 params["wpa_key_mgmt"] = "WPA-EAP" 750 params["rsn_pairwise"] = "CCMP" 751 params["ieee8021x"] = "1" 752 if ssid: 753 params["ssid"] = ssid 754 return params 755 756def b_only_params(channel="1", ssid=None, country=None): 757 params = {"hw_mode": "b", 758 "channel": channel} 759 if ssid: 760 params["ssid"] = ssid 761 if country: 762 params["country_code"] = country 763 return params 764 765def g_only_params(channel="1", ssid=None, country=None): 766 params = {"hw_mode": "g", 767 "channel": channel} 768 if ssid: 769 params["ssid"] = ssid 770 if country: 771 params["country_code"] = country 772 return params 773 774def a_only_params(channel="36", ssid=None, country=None): 775 params = {"hw_mode": "a", 776 "channel": channel} 777 if ssid: 778 params["ssid"] = ssid 779 if country: 780 params["country_code"] = country 781 return params 782 783def ht20_params(channel="1", ssid=None, country=None): 784 params = {"ieee80211n": "1", 785 "channel": channel, 786 "hw_mode": "g"} 787 if int(channel) > 14: 788 params["hw_mode"] = "a" 789 if ssid: 790 params["ssid"] = ssid 791 if country: 792 params["country_code"] = country 793 return params 794 795def ht40_plus_params(channel="1", ssid=None, country=None): 796 params = ht20_params(channel, ssid, country) 797 params['ht_capab'] = "[HT40+]" 798 return params 799 800def ht40_minus_params(channel="1", ssid=None, country=None): 801 params = ht20_params(channel, ssid, country) 802 params['ht_capab'] = "[HT40-]" 803 return params 804 805def cmd_execute(apdev, cmd, shell=False): 806 hapd_global = HostapdGlobal(apdev) 807 return hapd_global.cmd_execute(cmd, shell=shell) 808 809def send_file(apdev, src, dst): 810 hapd_global = HostapdGlobal(apdev) 811 return hapd_global.send_file(src, dst) 812 813def acl_file(dev, apdev, conf): 814 fd, filename = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') 815 f = os.fdopen(fd, 'w') 816 817 if conf == 'hostapd.macaddr': 818 mac0 = dev[0].get_status_field("address") 819 f.write(mac0 + '\n') 820 f.write("02:00:00:00:00:12\n") 821 f.write("02:00:00:00:00:34\n") 822 f.write("-02:00:00:00:00:12\n") 823 f.write("-02:00:00:00:00:34\n") 824 f.write("01:01:01:01:01:01\n") 825 f.write("03:01:01:01:01:03\n") 826 elif conf == 'hostapd.accept': 827 mac0 = dev[0].get_status_field("address") 828 mac1 = dev[1].get_status_field("address") 829 f.write(mac0 + " 1\n") 830 f.write(mac1 + " 2\n") 831 elif conf == 'hostapd.accept2': 832 mac0 = dev[0].get_status_field("address") 833 mac1 = dev[1].get_status_field("address") 834 mac2 = dev[2].get_status_field("address") 835 f.write(mac0 + " 1\n") 836 f.write(mac1 + " 2\n") 837 f.write(mac2 + " 3\n") 838 else: 839 f.close() 840 os.unlink(filename) 841 return conf 842 843 return filename 844 845def bssid_inc(apdev, inc=1): 846 parts = apdev['bssid'].split(':') 847 parts[5] = '%02x' % (int(parts[5], 16) + int(inc)) 848 bssid = '%s:%s:%s:%s:%s:%s' % (parts[0], parts[1], parts[2], 849 parts[3], parts[4], parts[5]) 850 return bssid 851 852def cfg_file(apdev, conf, ifname=None): 853 match = re.search(r'^bss-.+', conf) 854 if match: 855 # put cfg file in /tmp directory 856 fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') 857 f = os.fdopen(fd, 'w') 858 idx = ''.join(filter(str.isdigit, conf.split('-')[-1])) 859 if ifname is None: 860 ifname = apdev['ifname'] 861 if idx != '1': 862 ifname = ifname + '-' + idx 863 864 f.write("driver=nl80211\n") 865 f.write("ctrl_interface=/var/run/hostapd\n") 866 f.write("hw_mode=g\n") 867 f.write("channel=1\n") 868 f.write("ieee80211n=1\n") 869 if conf.startswith('bss-ht40-'): 870 f.write("ht_capab=[HT40+]\n") 871 f.write("interface=%s\n" % ifname) 872 873 f.write("ssid=bss-%s\n" % idx) 874 if conf == 'bss-2-dup.conf': 875 bssid = apdev['bssid'] 876 else: 877 bssid = bssid_inc(apdev, int(idx) - 1) 878 f.write("bssid=%s\n" % bssid) 879 880 return fname 881 882 return conf 883