def stop_olsrd(self): """ Stops OLSR and configures the wifi interface for a reconnection to the AP. """ os.kill(self.olsrd_pid, signal.SIGTERM) log.info("*** {}: Killed given olsrd process (PID: {})".format( self.interface, self.olsrd_pid)) stdout, stderr = cmd_iw_dev(self.interface, "ibss", "leave") log.info("*** {}: IBSS leave completed".format(self.interface)) stdout, stderr = cmd_iw_dev(self.interface, "set", "type", "managed") log.info("*** {}: Set type to managed".format(self.interface)) self.olsrd_pid = 0
def run(self): log.info("*** {}: Scanner started. Searching for {} with interval {}". format(self.interface, self.ssid, self.interval)) while True: sleep(self.interval) log.info("*** {}: Scanning for {}".format(self.interface, self.ssid)) self.log_event('scan_trigger') if self.ssid: stdout, stderr = cmd_iw_dev(self.interface, "scan", "ssid", self.ssid) else: stdout, stderr = cmd_iw_dev(self.interface, "scan")
def __init__(self, interface: str, scaninterface: str, scan_interval: float, reconnect_threshold: float, disconnect_threshold: float, pingto: str, out_path: str, ap_ssid: str, ap_bssid: str, ap_ip: str, signal_window: int, start_time: float, qdisc: dict, no_olsr: bool = False): self.interface = interface self.station = interface.split('-')[0] self.scan_interface = scaninterface self.scan_interval = scan_interval self.reconnect_threshold = reconnect_threshold self.disconnect_threshold = disconnect_threshold self.connected_to_ap = True self.pingto = pingto self.out_path = out_path self.signal_file = out_path + interface + '_signal.csv' self.ap_ssid = ap_ssid self.ap_bssid = ap_bssid self.ap_ip = ap_ip self.signal_window = signal_window self.start_time = start_time self.qdisc = qdisc self.qdisc.update({'throttled': False}) self.no_olsr = no_olsr self.olsrd_pid = 0 self.link_signal_deque = deque(maxlen=signal_window) self.scan_signal_deque = deque(maxlen=signal_window) self.scanner = Scanner(scaninterface, scan_interval, out_path, self.station, start_time, ap_ssid) log.info("*** {}: Interface: {}, Scan-interface: {}".format( interface.split('-')[0], interface, scaninterface)) stdout, stderr = cmd_iw_dev(interface, "link") while b'Connected to ' + ap_bssid.encode() not in stdout: stdout, stderr = cmd_iw_dev(interface, "link") stdout, stderr = Popen(["ping", "-c1", ap_ip], stdout=PIPE, stderr=PIPE).communicate() if self.pingto: Popen(["ping", "-c1", pingto]).communicate()
def prepare_olsrd(self, interface: str): """ Configures the given interface for ad-hoc mode and joins IBSS. """ ibss = { 'ssid': 'adhocNet', 'freq': '2432', 'ht_cap': 'HT40+', 'bssid': '02:CA:FF:EE:BA:01' } stdout, stderr = cmd_iw_dev(interface, "set", "type", "ibss") log.info("*** {}: Set type to ibss".format(interface)) stdout, stderr = cmd_ip_link_set(interface, "up") log.info("*** {}: Set ip link up".format(interface)) stdout, stderr = cmd_iw_dev(interface, "ibss", "join", ibss['ssid'], ibss['freq'], ibss['ht_cap'], ibss['bssid']) log.info("*** {}: Join ibss adhocNet".format(interface))
def reconnect_to_access_point(self): """ Connects to the AP if the SSID is in range. Returns 0 after successful reconnect. """ if self.qdisc['reconnect'] > 0: update_qdisc(self.interface, self.qdisc['reconnect'], self.qdisc['throttle_unit']) self.qdisc.update({'throttled': True}) if self.olsrd_pid > 0: log.info("*** {}: OLSR runnning: Killing olsrd process (PID: {})". format(self.interface, self.olsrd_pid)) self.stop_olsrd() stdout, stderr = cmd_iw_dev(self.interface, "connect", self.ap_ssid) stdout, stderr = cmd_iw_dev(self.interface, "link") while b'Connected to ' + self.ap_bssid.encode() not in stdout: stdout, stderr = cmd_iw_dev(self.interface, "link") log.info("*** {}: Connected interface to {}".format( self.interface, self.ap_ssid)) if self.qdisc['reconnect'] > 0: update_qdisc(self.interface, self.qdisc['standard'], self.qdisc['std_unit']) self.qdisc.update({'throttled': False})
def get_scan_dump_signal(self): stdout, stderr = cmd_iw_dev(self.scan_interface, "scan", "dump") scan_data = stdout.decode() if "BSS " + self.ap_bssid in scan_data and "SSID: " + self.ap_ssid in scan_data: scan_signal = self.signal_strength_from_scan_dump(scan_data) scan_data = { 'time': datetime.now().timestamp() - self.start_time, 'signal': scan_signal, 'SSID': self.ap_ssid, 'rx_bitrate': 0, 'tx_bitrate': 0 } return scan_data return None
def get_link_signal_quality(self): """ Fetches the signal strength on a given wifi interface as long as it is connected to an AP with a matching ssid. Returns the signal data if the connection is present. Returns None if the AP is not connected. """ stdout, stderr = cmd_iw_dev(self.interface, "link") data = stdout.decode() if 'Connected to ' + self.ap_bssid in data and 'SSID: ' + self.ap_ssid in data: data = [ x for x in list(filter(None, data.split('\n\t')[1:])) if x.strip() ] data = dict(map(lambda s: s.split(':'), data)) signal_data = { k.replace(' ', '_'): (data[k].strip() if k in data else 'NaN') for k in ['SSID', 'signal', 'rx bitrate', 'tx bitrate'] } signal_data.update( {'time': datetime.now().timestamp() - self.start_time}) return signal_data return None
def main(args): """ This program monitors the signal strength of the connected wifi access point (AP). When the signal is lost the program activates OLSR on the wifi interface. While OLSR is activated the program continuously scans for the APs SSID to reappear in range. When the APs SSID is again in range the program deactivates OLSR and reconnects to the AP. """ cmd_iw_dev(args.interface, "connect", args.apssid) if args.scaninterface: scaninterface = args.scaninterface else: scaninterface = args.interface path = os.path.dirname(os.path.abspath(__file__)) statistics_dir = path + '/data/statistics/' + args.outputpath + '/' if not os.path.isdir(statistics_dir): os.makedirs(statistics_dir) if args.qdiscdisconnect > 0 and args.qdiscreconnect > 0: rate, unit = 1, 'mbit' print("*** Setting up qdisc with HTB rate {} {}".format(rate, unit)) init_qdisc(args.interface, rate, unit) log.info("*** {}: Qdisc set up with HTB rate {} {}".format( args.interface, rate, unit)) qdisc = 'on' qdisc_rates = { 'standard': 1, 'std_unit': 'mbit', 'disconnect': args.qdiscdisconnect, 'reconnect': args.qdiscreconnect, 'throttle_unit': 'bit', 'throttled': False } else: qdisc = 'off' qdisc_rates = {'disconnect': 0, 'reconnect': 0, 'unit': 'bit'} if args.noolsr: olsr = 'off' else: olsr = 'on' parameters = { 'start_time': args.starttime, 'OLSR': olsr, 'interface': args.interface, 'qdisc': { 'mode': qdisc, 'rates': qdisc_rates }, 'AP': { 'ssid': args.apssid, 'bssid': args.apbssid, 'ip': args.apip }, 'scan': { 'interface': scaninterface, 'interval': args.scaninterval, 'moving_avg_window': args.signalwindow, 'reconnect_threshold': args.reconnectthreshold, 'disconnect_threshold': args.disconnectthreshold } } with open( statistics_dir + args.interface.split('-')[0] + '_start-params.json', 'w') as file: json.dump(parameters, file, indent=4) controller = FlexibleSdnOlsrController( args.interface, scaninterface, args.scaninterval, args.reconnectthreshold, args.disconnectthreshold, args.pingto, statistics_dir, args.apssid, args.apbssid, args.apip, args.signalwindow, args.starttime, qdisc_rates, args.noolsr) controller.run_controller()
def run_controller(self): print("ssid, time (s), signal (dBm), signal_avg (dBm)") while True: time.sleep(1) ap_link_signal = self.get_link_signal_quality() if ap_link_signal: signal = float(ap_link_signal['signal'].rstrip(' dBm')) self.link_signal_deque.append(signal) ap_link_signal.update({ 'signal': signal, 'signal_avg': sum(self.link_signal_deque) / len(self.link_signal_deque) }) if ap_link_signal['signal_avg'] >= self.disconnect_threshold: print("{}, {}, {}, {:.2f}".format( ap_link_signal['SSID'], ap_link_signal['time'], ap_link_signal['signal'], ap_link_signal['signal_avg'])) self.write_signal_to_file(ap_link_signal) # if self.qdisc['disconnect'] > 0: # if ap_link_signal['signal_avg'] <= self.disconnect_threshold + 2 and not self.qdisc['throttled']: # update_qdisc(self.interface, self.qdisc['disconnect'], self.qdisc['throttle_unit']) # self.qdisc.update({'throttled': True}) # elif ap_link_signal['signal_avg'] > self.disconnect_threshold + 2 and self.qdisc['throttled']: # update_qdisc(self.interface, self.qdisc['standard'], self.qdisc['std_unit']) # self.qdisc.update({'throttled': False}) continue if not self.scanner.is_alive(): if ap_link_signal: print( "*** AP signal too weak (last signal: {} / {})".format( ap_link_signal['signal'], self.disconnect_threshold)) else: print("*** AP connection lost") print("*** Starting background scan") self.scanner.start() self.log_event('scanner_start', 1) scan_signal = self.get_scan_dump_signal() if scan_signal and 'signal' in scan_signal: self.scan_signal_deque.append(scan_signal['signal']) scan_signal.update({ 'signal_avg': sum(self.scan_signal_deque) / len(self.scan_signal_deque) }) log.info("*** {}: Scan detected {} in range (signal: {} / {})". format(self.scan_interface, self.ap_ssid, scan_signal['signal'], self.reconnect_threshold)) self.write_signal_to_file(scan_signal) print("{}, {}, {}, {:.2f}".format(scan_signal['SSID'], scan_signal['time'], scan_signal['signal'], scan_signal['signal_avg'])) if scan_signal['signal'] >= self.reconnect_threshold: self.log_event('reconnect', 1) self.reconnect_to_access_point() self.connected_to_ap = True self.log_event('reconnect', 2) if self.scanner.is_alive(): print("*** Stopping background scan") self.scanner.terminate() self.log_event('scanner_stop', 1) self.scanner = Scanner(self.scan_interface, self.scan_interval, self.out_path, self.station, self.start_time, self.ap_ssid) time.sleep(0.5) print("*** Reconnected to AP.") print("*** OLSRd PID: ", self.olsrd_pid) stdout, stderr = Popen(["ping", "-c1", self.ap_ip], stdout=PIPE, stderr=PIPE).communicate() continue if self.olsrd_pid == 0 and not self.no_olsr: print("*** Starting OLSRd") self.log_event('disconnect', 1) self.switch_to_olsr() self.connected_to_ap = False self.log_event('disconnect', 2) if self.pingto: spthread = threading.Thread(target=sleep_and_ping, kwargs={ 'sleep_interval': 1.0, 'ip': self.pingto }, daemon=True) spthread.start() elif self.no_olsr and self.connected_to_ap: self.log_event('disconnect', 1) cmd_iw_dev(self.interface, 'disconnect') self.connected_to_ap = False self.log_event('disconnect', 2)