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
Example #2
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)