1# Monitor support
2# Copyright (c) 2016, Tieto Corporation
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7import time
8from remotehost import Host
9import config
10import rutils
11import re
12import traceback
13import logging
14logger = logging.getLogger()
15import hostapd
16
17# standalone monitor with multi iface support
18def create(devices, setup_params, refs, duts, monitors):
19    mons = []
20    mhosts = []
21    hosts = duts + refs
22
23    # choose only standalone monitors
24    for monitor in monitors:
25        if monitor not in hosts and monitor != "all":
26            mons.append(monitor)
27
28    for mon in mons:
29        word = mon.split(":")
30        dev = config.get_device(devices, word[0])
31        if dev is None:
32            continue
33
34        host = Host(host=dev['hostname'],
35                    ifname=dev['ifname'],
36                    port=dev['port'],
37                    name=dev['name'])
38
39        for iface_param in word[1:]:
40            params = iface_param.split(",")
41            if len(params) > 3:
42                monitor_param = { "freq" : rutils.c2f(params[0]),
43                                  "bw" : params[1],
44                                  "center_freq1" : rutils.c2f(params[2]),
45                                  "center_freq2" : rutils.c2f(params[3]) }
46                host.monitor_params.append(monitor_param)
47
48        try:
49            host.execute(["iw", "reg", "set", setup_params['country']])
50            rutils.setup_hw_host(host, setup_params, True)
51        except:
52            pass
53        mhosts.append(host)
54
55    return mhosts
56
57def destroy(devices, hosts):
58    for host in hosts:
59        stop(host)
60        for monitor in host.monitors:
61            host.execute(["ifconfig", monitor, "down"])
62        host.monitor_params = []
63
64def setup(host, monitor_params=None):
65    if host is None:
66        return
67
68    if monitor_params == None:
69        monitor_params = host.monitor_params
70
71    ifaces = re.split('; | |, ', host.ifname)
72    count = 0
73    for param in monitor_params:
74        try:
75            iface = ifaces[count]
76        except:
77            logger.debug(traceback.format_exc())
78            break
79        host.execute(["ifconfig", iface, " down"])
80        host.execute(["rfkill", "unblock", "wifi"])
81        host.execute(["iw", iface, "set type monitor"])
82        host.execute(["ifconfig", iface, "up"])
83        status, buf = host.execute(["iw", iface, "set", "freq", param['freq'],
84                                    param['bw'], param['center_freq1'],
85                                    param['center_freq2']])
86        if status != 0:
87            logger.debug("Could not setup monitor interface: " + buf)
88            continue
89        host.monitors.append(iface)
90        count = count + 1
91
92def run(host, setup_params):
93    monitor_res = []
94    log_monitor = ""
95    if host is None:
96        return None
97    if len(host.monitors) == 0:
98        return None
99    try:
100        log_dir = setup_params['log_dir']
101        tc_name = setup_params['tc_name']
102    except:
103        return None
104
105    tshark = "tshark"
106    for monitor in host.monitors:
107        host.execute(["ifconfig", monitor, "up"])
108        tshark = tshark + " -i " + monitor
109        log_monitor = log_monitor + "_" + monitor
110
111    log = log_dir + tc_name + "_" + host.name + log_monitor + ".pcap"
112    host.add_log(log)
113    thread = host.thread_run([tshark, "-w", log], monitor_res)
114    host.thread = thread
115
116
117def stop(host):
118    if host is None:
119        return
120    if len(host.monitors) == 0:
121        return
122    if host.thread is None:
123        return
124
125    host.thread_stop(host.thread)
126    host.thread = None
127
128# Add monitor to existing interface
129def add(host, monitors):
130    if host is None:
131        return
132
133    for monitor in monitors:
134        if monitor != "all" and monitor != host.name:
135            continue
136        mon = "mon_" + host.ifname
137        status, buf = host.execute(["iw", host.ifname, "interface", "add", mon,
138                                    "type", "monitor"])
139        if status == 0:
140            host.monitors.append(mon)
141            host.execute(["ifconfig", mon, "up"])
142        else:
143            logger.debug("Could not add monitor for " + host.name)
144
145def remove(host):
146    stop(host)
147    for monitor in host.monitors:
148        host.execute(["iw", monitor, "del"])
149        host.monitors.remove(monitor)
150
151
152# get monitor params from hostapd/wpa_supplicant
153def get_monitor_params(wpa, is_p2p=False):
154    if is_p2p:
155        get_status_field_f = wpa.get_group_status_field
156    else:
157        get_status_field_f = wpa.get_status_field
158    freq = get_status_field_f("freq")
159    bw = "20"
160    center_freq1 = ""
161    center_freq2 = ""
162
163    vht_oper_chwidth = get_status_field_f("vht_oper_chwidth")
164    secondary_channel = get_status_field_f("secondary_channel")
165    vht_oper_centr_freq_seg0_idx = get_status_field_f("vht_oper_centr_freq_seg0_idx")
166    vht_oper_centr_freq_seg1_idx = get_status_field_f("vht_oper_centr_freq_seg1_idx")
167    if vht_oper_chwidth == "0" or vht_oper_chwidth is None:
168        if secondary_channel == "1":
169            bw = "40"
170            center_freq1 = str(int(freq) + 10)
171        elif secondary_channel == "-1":
172            center_freq1 = str(int(freq) - 10)
173        else:
174            pass
175    elif vht_oper_chwidth == "1":
176        bw = "80"
177        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
178    elif vht_oper_chwidth == "2":
179        bw = "160"
180        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
181    elif vht_oper_chwidth == "3":
182        bw = "80+80"
183        center_freq1 = str(int(vht_oper_centr_freq_seg0_idx) * 5 + 5000)
184        center_freq2 = str(int(vht_oper_centr_freq_seg1_idx) * 5 + 5000)
185    else:
186        pass
187
188    monitor_params = {"freq" : freq,
189                      "bw" : bw,
190                      "center_freq1" : center_freq1,
191                      "center_freq2" : center_freq2}
192
193    return monitor_params
194