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