1#
2# tshark module - refactored from test_scan.py
3#
4# Copyright (c) 2014, Qualcomm Atheros, Inc.
5# Copyright (c) 2015, Intel Mobile Communications GmbH
6#
7# This software may be distributed under the terms of the BSD license.
8# See README for more details.
9
10import time
11import subprocess
12import logging
13logger = logging.getLogger()
14
15from utils import *
16
17class UnknownFieldsException(Exception):
18    def __init__(self, fields):
19        Exception.__init__(self, "unknown tshark fields %s" % ','.join(fields))
20        self.fields = fields
21
22_tshark_filter_arg = '-Y'
23
24def _run_tshark(filename, filter, display=None, wait=True):
25    global _tshark_filter_arg
26
27    if wait:
28        # wait a bit to make it more likely for wlantest sniffer to have
29        # captured and written the results into a file that we can process here
30        time.sleep(0.1)
31
32    try:
33        arg = ["tshark", "-r", filename,
34               _tshark_filter_arg, filter]
35        if display:
36            arg.append('-Tfields')
37            for d in display:
38                arg.append('-e')
39                arg.append(d)
40        else:
41            arg.append('-V')
42        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
43                               stderr=subprocess.PIPE)
44    except Exception as e:
45        logger.info("Could run run tshark check: " + str(e))
46        if "No such file or directory: 'tshark'" in str(e):
47            raise HwsimSkip("No tshark available")
48        cmd = None
49        return None
50
51    output = cmd.communicate()
52    out = output[0].decode(errors='ignore')
53    out1 = output[1].decode()
54    res = cmd.wait()
55    if res == 1:
56        errmsg = "Some fields aren't valid"
57        if errmsg in out1:
58            errors = out1.split('\n')
59            fields = []
60            collect = False
61            for f in errors:
62                if collect:
63                    f = f.strip()
64                    if f:
65                        fields.append(f)
66                    continue
67                if errmsg in f:
68                    collect = True
69                    continue
70            raise UnknownFieldsException(fields)
71        # remember this for efficiency
72        _tshark_filter_arg = '-R'
73        arg[3] = '-R'
74        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
75                               stderr=open('/dev/null', 'w'))
76        out = cmd.communicate()[0].decode()
77        cmd.wait()
78    if res == 2:
79        if "tshark: Neither" in out1 and "are field or protocol names" in out1:
80            errors = out1.split('\n')
81            fields = []
82            for f in errors:
83                if f.startswith("tshark: Neither "):
84                    f = f.split(' ')[2].strip('"')
85                    if f:
86                        fields.append(f)
87                    continue
88            raise UnknownFieldsException(fields)
89
90    if res != 0:
91        raise AssertionError('tshark reported an error: ' + out1)
92
93    return out
94
95def run_tshark(filename, filters, display=None, wait=True):
96    if display is None: display = []
97
98    if not isinstance(filters, list) and not isinstance(filters, tuple):
99        filters = [filters]
100
101    last_exception = None
102    for filter in filters:
103        try:
104            return _run_tshark(filename, filter.replace('wlan_mgt', 'wlan'),
105                               [x.replace('wlan_mgt', 'wlan') for x in display],
106                               wait)
107        except UnknownFieldsException as e:
108            all_wlan_mgt = True
109            for f in e.fields:
110                if not f.startswith('wlan_mgt.'):
111                    all_wlan_mgt = False
112                    break
113            if not all_wlan_mgt:
114                raise
115            return _run_tshark(filename, filter, display, wait)
116
117        except AssertionError as e:
118            # Catch the error (and try the next provided filter)
119            last_exception = e
120
121    raise last_exception
122
123def run_tshark_json(filename, filter):
124    arg = ["tshark", "-r", filename,
125           _tshark_filter_arg, filter]
126    arg.append('-Tjson')
127    arg.append('-x')
128    try:
129        cmd = subprocess.Popen(arg, stdout=subprocess.PIPE,
130                               stderr=subprocess.PIPE)
131    except Exception as e:
132        logger.info("Could run run tshark: " + str(e))
133        if "No such file or directory: 'tshark'" in str(e):
134            raise HwsimSkip("No tshark available")
135        return None
136    output = cmd.communicate()
137    out = output[0].decode()
138    res = cmd.wait()
139    return out
140