def connect(self, conf_path, interface, status_check=True): """ Starts a thread that connects to the Wii U. Status: FAILED_START: wpa_supplicant_drc did not initialize SCANNING: wpa_supplicant_drc is scanning CONNECTED: wpa_supplicant_drc is connected to an AP CONNECTING: wpa_supplicant_drc is authenticating TERMINATED: wpa_supplicant_drc was found by the T-1000 Cyberdyne Systems Model 101 NOT_FOUND: wpa_supplicant_drc could not find a Wii U AP UNKNOWN: wpa_supplicant_drc is in a state that is unhandled - it will be logged :return: None """ LoggerWpa.debug("Connect called") self.running = True self.unblock_wlan() self.kill_wpa() command = [ "wpa_supplicant_drc", "-Dnl80211", "-i", interface, "-c", conf_path ] if LoggerWpa.get_level() == LoggerWpa.FINER: command.append("-d") elif LoggerWpa.get_level() == LoggerWpa.VERBOSE: command.append("-dd") LoggerWpa.debug("Starting wpa supplicant") self.wpa_supplicant_process = subprocess.Popen( command, stdout=open(constants.PATH_LOG_WPA, "w"), stderr=subprocess.STDOUT) LoggerWpa.debug("Started wpa supplicant") if status_check: LoggerWpa.debug("Starting status check thread") self.status_check_thread = Thread(target=self.check_status, name="WPA Status Check Thread") self.status_check_thread.start()
def save_connect_conf(bssid): """ Modify the temp get_psk configuration to be a connect configurraton and save it to ~/.drc-sim/connect_to_wii_u.conf. :param bssid: Wii U BSSID :return: None """ LoggerWpa.debug("Saving connection config") # add additional connect information to config conf = open(constants.PATH_CONF_CONNECT_TMP, "r") lines = conf.readlines() conf.close() for line in lines: if "update_config=1" in line: lines.insert(lines.index(line) + 1, "ap_scan=1\n") break for line in lines: if "network={" in line: lines.insert(lines.index(line) + 1, "\tscan_ssid=1\n") lines.insert(lines.index(line) + 2, "\tbssid=" + bssid + "\n") break save_conf = open(constants.PATH_CONF_CONNECT, "w") save_conf.writelines(lines) save_conf.close() LoggerWpa.info("Authenticated with the Wii U")
def check_status(self): """ Thread that checks WPA status every second Updates :return: None """ while self.running: wpa_status = self.wpa_cli("status") scan_results = self.wpa_cli("scan_results") not_started_message = "Failed to connect to non-global ctrl_ifname" LoggerWpa.finer("Scan Results: %s", scan_results) LoggerWpa.finer("Status: %s", wpa_status) # process is dead or wpa_supplicant has not started if self.wpa_supplicant_process.poll( ) or not_started_message in scan_results: LoggerWpa.finer("%d seconds until start timeout", 30 - self.time_start) # wait for wpa_supplicant to initialize if self.time_start >= 5: status = self.FAILED_START else: status = self.status self.time_start += 1 # scanning elif not self.scan_contains_wii_u( scan_results) or "wpa_state=SCANNING" in wpa_status: LoggerWpa.finer("%d seconds until scan timeout", ConfigGeneral.scan_timeout - self.time_scan) # disconnect if self.time_scan == -1: status = self.DISCONNECTED # timeout scan elif self.time_scan >= ConfigGeneral.scan_timeout: status = self.NOT_FOUND else: status = self.SCANNING self.time_scan += 1 elif "wpa_state=COMPLETED" in wpa_status: status = self.CONNECTED self.time_scan = -1 # forces a disconnect - might need to be handled better elif "wpa_state=AUTHENTICATING" in wpa_status or "wpa_state=ASSOCIATING" in wpa_status: status = self.CONNECTING elif "wpa_state=DISCONNECTED" in wpa_status: status = self.DISCONNECTED if self.time_scan != -1: status = self.FAILED_START else: LoggerWpa.extra("WPA status: %s", wpa_status) status = self.UNKNOWN self.set_status(status) time.sleep(1)
def stop(self): """ Stops any background thread that is running :return: None """ if not self.running: LoggerWpa.debug("Ignored stop request: already stopped") return self.running = False if self.psk_thread_cli and self.psk_thread_cli.isalive(): LoggerWpa.debug("Stopping psk pexpect spawn") self.psk_thread_cli.sendline("quit") self.psk_thread_cli.close(True) LoggerWpa.debug("Stopping wpa process") if self.wpa_supplicant_process and self.wpa_supplicant_process.poll( ) is None: self.wpa_supplicant_process.terminate() self.kill_wpa() # reset self.clear_status_change_listeners() self.time_start = 0 self.time_scan = 0 LoggerWpa.debug("Wpa stopped")
def get_psk_thread(self, code): """ Thread that attempts to authenticate with a Wii U. Updates status :param code: WPS PIN :return: None """ try: LoggerWpa.debug("CLI expect starting") self.psk_thread_cli = pexpect.spawn( "wpa_cli_drc -p /var/run/wpa_supplicant_drc") LoggerWpa.debug("CLI expect Waiting for init") self.psk_thread_cli.expect("Interactive mode") # Scan for Wii U SSIDs scan_tries = 5 wii_u_bssids = [] self.set_status(self.SCANNING) while self.running and scan_tries > 0: self.psk_thread_cli.sendline("scan") LoggerWpa.debug( "CLI expect waiting for scan results available event") scan_wait_tries = 60 while self.running: try: self.psk_thread_cli.expect( "<3>CTRL-EVENT-SCAN-RESULTS", timeout=1) break except pexpect.TIMEOUT: scan_wait_tries -= 1 if scan_wait_tries <= 0: raise pexpect.TIMEOUT("Scan timeout") self.psk_thread_cli.sendline("scan_results") LoggerWpa.debug("CLI expect waiting for scan results") self.psk_thread_cli.expect( "bssid / frequency / signal level / flags / ssid") for line in range(0, 100): # up to 100 APs try: self.psk_thread_cli.expect(self.mac_addr_regex.pattern, timeout=1) except pexpect.TIMEOUT: break scan_results = self.psk_thread_cli.before.decode() LoggerWpa.finer("CLI expect - scan results: %s", scan_results) for line in scan_results.splitlines(): if self.wiiu_ap_regex.match(line): wii_u_bssids.append(line.split()[0]) if len(wii_u_bssids) == 0: scan_tries -= 1 else: scan_tries = 0 # Check for found Wii U ssids if len(wii_u_bssids) == 0: LoggerWpa.debug("No Wii U SSIDs found") self.set_status(self.NOT_FOUND) return # attempt to pair with any wii u bssid self.set_status(self.CONNECTING) for bssid in wii_u_bssids: self.psk_thread_cli.sendline("wps_pin %s %s" % (bssid, code + "5678")) LoggerWpa.debug( "CLI expect waiting for wps_pin input confirmation") self.psk_thread_cli.expect(code + "5678") LoggerWpa.debug("CLI expect waiting for authentication") try: connect_wait_tries = 60 while self.running: try: self.psk_thread_cli.expect("<3>WPS-CRED-RECEIVED", timeout=1) break except pexpect.TIMEOUT: connect_wait_tries -= 1 if connect_wait_tries <= 0: raise pexpect.TIMEOUT("Connect Timeout") # save conf LoggerWpa.debug("PSK obtained") # Save to temp config before reading from it self.psk_thread_cli.sendline("save_config") self.psk_thread_cli.expect("OK", timeout=5) self.save_connect_conf(bssid) self.set_status(self.DISCONNECTED) return except pexpect.TIMEOUT: LoggerWpa.debug("CLI expect BSSID auth failed") self.psk_thread_cli.sendline("reconnect") self.psk_thread_cli.expect("OK") # Timed out except pexpect.TIMEOUT as e: LoggerWpa.debug("PSK get attempt ended with an error.") LoggerWpa.exception(e) self.set_status(self.FAILED_START) # Unexpected EOF except pexpect.EOF as e: if self.running: # Thread was not killed LoggerWpa.exception(e) return # Failed to authenticate LoggerWpa.debug("Could not authenticate with any SSIDs") self.set_status(self.TERMINATED)