xref: /aosp_15_r20/external/autotest/client/cros/scripts/wifi (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/python3
2
3# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import os
8import sys
9
10# Prevent Autotest smarts from trying to switch us back to python2.
11os.environ['PY_VERSION'] = '3'
12
13import common
14from autotest_lib.client.cros.networking import wifi_proxy
15
16SERVICE_PROP_PARSERS = {
17    'EAP.AnonymousIdentity': str,
18    'EAP.CACertID': str,
19    'EAP.CACertNSS': str,
20    'EAP.CACertPEM': str,
21    'EAP.CertID': str,
22    'EAP.ClientCert': str,
23    'EAP.EAP': str,
24    'EAP.Identity': str,
25    'EAP.InnerEAP': str,
26    'EAP.KeyID': str,
27    'EAP.KeyMgmt': str,
28    'EAP.Password': str,
29    'EAP.PIN': str,
30    'EAP.SubjectMatch': str,
31    'EAP.UseSystemCAs': bool,
32    wifi_proxy.WifiProxy.SERVICE_PROPERTY_SECURITY_CLASS: str,
33    }
34
35
36def usage():
37    """ Prints a usage message and returns False. """
38    cmd = sys.argv[0]
39    print('Usage:')
40    print(cmd, 'connect <ssid> [passphrase] [security]')
41    print('    |security| defaults to "psk" when |passphrase|', end=' ')
42    print('is given without |security|')
43    print()
44    print(cmd, 'disconnect <ssid> [timeout seconds]')
45    print()
46    print(cmd, 'connect_with_props <ssid> <timeout seconds>')
47    print('    <SecurityClass=[none|psk|802_1x]> [Property=Value ...]')
48    print('    for Property in:')
49    print('\n'.join(['\t\t' + x for x in sorted(SERVICE_PROP_PARSERS.keys())]))
50    print()
51    print(cmd, 'configure <ssid> [passphrase] [security]')
52    print('    |security| defaults to "psk" when |passphrase|', end=' ')
53    print('is given without |security|')
54    return False
55
56
57def configure(ssid, security, passphrase):
58    wifi = wifi_proxy.WifiProxy.get_proxy()
59    security_parameters = {}
60    if passphrase is not None:
61        security_parameters[wifi.SERVICE_PROPERTY_PASSPHRASE] = passphrase
62    successful = wifi.configure_wifi_service(ssid, security,
63                                             security_parameters)
64    if successful:
65        print('Operation succeeded.')
66    else:
67        print('Operation failed.')
68    return successful
69
70
71def connect(ssid, security, credentials, save_credentials, timeout=15):
72    """Attempt to connect to a WiFi network.
73
74    Blocks until we connect successfully to a WiFi network described
75    by the given parameters or time out while attempting to do so.
76
77    @param ssid string Name of the network to connect to.
78    @param security string security type of the network to connect to.
79    @param credentials dict of service properties that includes credentials
80            like the passphrase for psk security.
81    @param save_credentials bool True if credentials should be saved.
82    @return True upon success, False otherwise.
83
84    """
85    wifi = wifi_proxy.WifiProxy.get_proxy()
86    result = wifi.connect_to_wifi_network(ssid,
87            security,
88            credentials,
89            save_credentials,
90            discovery_timeout_seconds=timeout,
91            association_timeout_seconds=timeout,
92            configuration_timeout_seconds=timeout)
93    (successful, discovery, association, configuration, reason) = result
94    if successful:
95        print('Operation succeeded.')
96    else:
97        print('Operation failed. (%s)' % reason)
98    print('Discovery time: %f.' % discovery)
99    print('Association time: %f.' % association)
100    print('Configuration time: %f.' % configuration)
101    return successful
102
103
104def disconnect(ssid, timeout=None):
105    """Disconnect from the specified network.
106
107    Disconnect from a network with name |ssid|.  Note that this
108    method will not fail if we're already disconnected.
109
110    @param ssid string Name of the network to disconnect from.
111    @param timeout float number of seconds to wait for transition
112            to idle state.
113    @return True upon seeing network is in idle state.
114
115    """
116    wifi = wifi_proxy.WifiProxy.get_proxy()
117    result = wifi.disconnect_from_wifi_network(ssid, timeout)
118    (successful, duration, reason) = result
119    if successful:
120        print('Operation succeeded.')
121    else:
122        print('Operation failed: %s.' % reason)
123    print('Disconnect time: %f.' % duration)
124    return successful
125
126
127def parse_security_class_from_credentials(credentials):
128    """Parses SERVICE_PROPERTY_SECURITY_CLASS from credentials.
129
130    @param credentials dict of service properties that includes credentials
131            like the passphrase for psk security.
132    @return SERVICE_PROPERTY_SECURITY_CLASS value from credentials,
133            or exit if no such key/value in credentials.
134
135    """
136    security = credentials.pop(
137            wifi_proxy.WifiProxy.SERVICE_PROPERTY_SECURITY_CLASS, None)
138    if security is None:
139        print("Error: security type not provided")
140        usage()
141        sys.exit(1)
142
143    if security not in ['none', 'wep', 'psk', '802_1x']:
144        print("Error: invalid security type %s" % security)
145        usage()
146        sys.exit(1)
147
148    return security
149
150
151def parse_service_property(property_string):
152    """Parses one commandline key=value string into a tuple.
153
154    @param property_string string to be parsed into (key,value).
155    @return parsed tuple of (key,value) or exit on parsing error.
156
157    """
158    property_name, raw_value = property_string.split('=', 1)
159
160    if not property_name in SERVICE_PROP_PARSERS:
161        print('%s is not a recognized service property' % property_name)
162        usage()
163        sys.exit(1)
164
165    try:
166        return property_name, SERVICE_PROP_PARSERS[property_name](raw_value)
167    except:
168        print('Failed parsing value from %s' % property_string)
169        usage()
170        sys.exit(1)
171
172
173def main(args):
174    """Main method for this script.
175
176    @param args list of arguments to the script, not including script name.
177    @return True on success, False otherwise.
178
179    """
180    if len(args) < 2:
181        return usage()
182    command = args[0]
183    ssid = args[1]
184    save_credentials = True
185
186    if command == 'configure':
187        security = 'none'
188        passphrase = None
189        if len(args) > 2:
190            security = 'psk'
191            passphrase = args[2]
192        if len(args) > 3:
193            security = args[3]
194        return configure(ssid, security, passphrase)
195
196    if command == 'connect':
197        security = 'none'
198        credentials = {}
199        save_credentials = True
200        if len(args) > 2:
201            credentials[wifi_proxy.WifiProxy.SERVICE_PROPERTY_PASSPHRASE] = \
202                    args[2]
203            security = 'psk'
204        if len(args) > 3:
205            security = args[3]
206        return connect(ssid, security, credentials, save_credentials)
207
208    if command == 'connect_with_props':
209        timeout = float(args[2])
210        credentials = {}
211        if len(args) > 3:
212            for i in range(3, len(args)):
213                credentials.update((parse_service_property(args[i]),))
214        security = parse_security_class_from_credentials(credentials)
215        return connect(ssid, security, credentials, save_credentials, timeout)
216
217    if command == 'disconnect':
218        timeout=None
219        if len(args) > 2:
220            timeout = float(args[2])
221        return disconnect(ssid, timeout)
222
223    return usage()
224
225
226if __name__ == '__main__':
227    if not main(sys.argv[1:]):
228      sys.exit(1)
229