diff options
-rw-r--r-- | op-mode-definitions/wireless.xml | 6 | ||||
-rwxr-xr-x | src/op_mode/show_wireless.py | 158 |
2 files changed, 161 insertions, 3 deletions
diff --git a/op-mode-definitions/wireless.xml b/op-mode-definitions/wireless.xml index 992d53ba4..c3c6dee59 100644 --- a/op-mode-definitions/wireless.xml +++ b/op-mode-definitions/wireless.xml @@ -57,7 +57,7 @@ <properties> <help>Show wireless interface configuration</help> </properties> - <command>echo TBD.</command> + <command>${vyos_op_scripts_dir}/show_wireless.py --brief</command> </leafNode> </children> </node> @@ -80,7 +80,7 @@ <properties> <help>Show summary of the specified wireless interface information</help> </properties> - <command>echo TBD.</command> + <command>sudo ${vyos_op_scripts_dir}/show_wireless.py --scan "$4"</command> <children> <leafNode name="detail"> <properties> @@ -94,7 +94,7 @@ <properties> <help>Show specified wireless interface information</help> </properties> - <command>echo "TBD."</command> + <command>${vyos_op_scripts_dir}/show_wireless.py --stations "$4"</command> </leafNode> <tagNode name="vif"> <properties> diff --git a/src/op_mode/show_wireless.py b/src/op_mode/show_wireless.py new file mode 100755 index 000000000..aff882559 --- /dev/null +++ b/src/op_mode/show_wireless.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import argparse +import re + +from sys import exit +from copy import deepcopy +from subprocess import Popen, PIPE, STDOUT + +from vyos.config import Config + +parser = argparse.ArgumentParser() +parser.add_argument("-s", "--scan", help="Scan for Wireless APs on given interface, e.g. 'wlan0'") +parser.add_argument("-b", "--brief", action="store_true", help="Show wireless configuration") +parser.add_argument("-c", "--stations", help="Show wireless clients connected on interface, e.g. 'wlan0'") + +def _cmd(command): + p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True) + tmp = p.communicate()[0].strip() + return tmp.decode() + +def show_brief(): + config = Config() + if len(config.list_effective_nodes('interfaces wireless')) == 0: + print("No Wireless interfaces configured") + exit(0) + + interfaces = [] + for intf in config.list_effective_nodes('interfaces wireless'): + config.set_level('interfaces wireless {}'.format(intf)) + data = { + 'name': intf, + 'type': '', + 'ssid': '', + 'channel': '' + } + data['type'] = config.return_effective_value('type') + data['ssid'] = config.return_effective_value('ssid') + data['channel'] = config.return_effective_value('channel') + + interfaces.append(data) + + return interfaces + +def ssid_scan(intf): + tmp = _cmd('/sbin/iw dev {} scan ap-force'.format(intf)) + networks = [] + data = { + 'ssid': '', + 'mac': '', + 'channel': '', + 'signal': '' + } + re_mac = re.compile(r'([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})') + for line in tmp.splitlines(): + if line.startswith('BSS '): + ssid = deepcopy(data) + ssid['mac'] = re.search(re_mac, line).group() + + elif line.lstrip().startswith('SSID: '): + # SSID can be " SSID: WLAN-57 6405", thus strip all leading whitespaces + ssid['ssid'] = line.lstrip().split(':')[-1].lstrip() + + elif line.lstrip().startswith('signal: '): + # Siganl can be " signal: -67.00 dBm", thus strip all leading whitespaces + ssid['signal'] = line.lstrip().split(':')[-1].split()[0] + + elif line.lstrip().startswith('DS Parameter set: channel'): + # Channel can be " DS Parameter set: channel 6" , thus + # strip all leading whitespaces + ssid['channel'] = line.lstrip().split(':')[-1].split()[-1] + networks.append(ssid) + continue + + return networks + +def show_clients(intf): + tmp = _cmd('/sbin/iw dev {} station dump'.format(intf)) + clients = [] + data = { + 'mac': '', + 'signal': '', + 'rx_bytes': '', + 'rx_packets': '', + 'tx_bytes': '', + 'tx_packets': '' + } + re_mac = re.compile(r'([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})') + for line in tmp.splitlines(): + if line.startswith('Station'): + client = deepcopy(data) + client['mac'] = re.search(re_mac, line).group() + + elif line.lstrip().startswith('signal avg:'): + client['signal'] = line.lstrip().split(':')[-1].lstrip().split()[0] + + elif line.lstrip().startswith('rx bytes:'): + client['rx_bytes'] = line.lstrip().split(':')[-1].lstrip() + + elif line.lstrip().startswith('rx packets:'): + client['rx_packets'] = line.lstrip().split(':')[-1].lstrip() + + elif line.lstrip().startswith('tx bytes:'): + client['tx_bytes'] = line.lstrip().split(':')[-1].lstrip() + + elif line.lstrip().startswith('tx packets:'): + client['tx_packets'] = line.lstrip().split(':')[-1].lstrip() + clients.append(client) + continue + + return clients + +if __name__ == '__main__': + args = parser.parse_args() + + if args.scan: + print("Address SSID Channel Signal (dbm)") + for network in ssid_scan(args.scan): + print("{:<17} {:<32} {:>3} {}".format(network['mac'], + network['ssid'], + network['channel'], + network['signal'])) + exit(0) + + elif args.brief: + print("Interface Type SSID Channel") + for intf in show_brief(): + print("{:<9} {:<12} {:<32} {:>3}".format(intf['name'], + intf['type'], + intf['ssid'], + intf['channel'])) + exit(0) + + elif args.stations: + print("Station Signal RX: bytes packets TX: bytes packets") + for client in show_clients(args.stations): + print("{:<17} {:>3} {:>15} {:>9} {:>15} {:>10} ".format(client['mac'], + client['signal'], client['rx_bytes'], client['rx_packets'], client['tx_bytes'], client['tx_packets'])) + + exit(0) + + else: + parser.print_help() + exit(1) |