1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6
7from autotest_lib.client.common_lib.cros.network import ap_constants
8from autotest_lib.client.common_lib.cros.network import ping_runner
9from autotest_lib.server.cros.ap_configurators import ap_spec
10
11
12class PduNotResponding(Exception):
13    """PDU exception class."""
14    def __init__(self, PDU):
15        self.PDU = PDU
16        logging.info('Caught PDU exception for %s', self.PDU)
17
18    def __str__(self):
19        return repr('Caught PDU exception for %s' % self.PDU)
20
21
22class APConfiguratorAbstract(object):
23    """Abstract Base class to find and control access points."""
24
25    def __init__(self):
26        super(APConfiguratorAbstract, self).__init__()
27        # Some APs will turn on their beacon, but the DHCP server is not
28        # running.  Each configurator can add this delay to have the test
29        # wait before attempting to connect.
30        self._dhcp_delay = 0
31
32
33    @property
34    def dhcp_delay(self):
35        """Returns the DHCP delay."""
36        return self._dhcp_delay
37
38
39    @property
40    def ssid(self):
41        """Returns the SSID."""
42        raise NotImplementedError('Missing subclass implementation')
43
44
45    @property
46    def name(self):
47        """Returns a string to describe the router."""
48        raise NotImplementedError('Missing subclass implementation')
49
50
51    @property
52    def configuration_success(self):
53        """Returns configuration status as defined in ap_constants"""
54        return self._configuration_success
55
56
57    @configuration_success.setter
58    def configuration_success(self, value):
59        """
60        Set the configuration status.
61
62        @param value: the status of AP configuration.
63
64        """
65        self._configuration_success = value
66
67
68    @property
69    def configurator_type(self):
70        """Returns the configurator type."""
71        return ap_spec.CONFIGURATOR_STATIC
72
73
74    @property
75    def short_name(self):
76        """Returns a short string to describe the router."""
77        raise NotImplementedError('Missing subclass implementation')
78
79
80    def check_pdu_status(self):
81        """Check if the PDU is up before making any request."""
82        ping_options = ping_runner.PingConfig(self.pdu, count=2,
83                                              ignore_status=True,
84                                              ignore_result=True)
85        runner = ping_runner.PingRunner()
86        logging.info('Pinging rpm %s', self.pdu)
87        ping_result = runner.ping(ping_options)
88        logging.info('ping result = %s', str(ping_result))
89        # If all ping packets failed then mark PDU down.
90        if ping_result.loss == 100:
91            self.configuration_success = ap_constants.PDU_FAIL
92            raise PduNotResponding(self.pdu)
93
94
95    def get_supported_bands(self):
96        """Returns a list of dictionaries describing the supported bands.
97
98        Example: returned is a dictionary of band and a list of channels. The
99                 band object returned must be one of those defined in the
100                 __init___ of this class.
101
102        supported_bands = [{'band' : self.band_2GHz,
103                            'channels' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]},
104                           {'band' : ap_spec.BAND_5GHZ,
105                            'channels' : [26, 40, 44, 48, 149, 153, 165]}]
106
107        Note: The derived class must implement this method.
108
109        @return a list of dictionaries as described above
110
111        """
112        raise NotImplementedError('Missing subclass implementation')
113
114
115    def get_supported_modes(self):
116        """
117        Returns a list of dictionaries describing the supported modes.
118
119        Example: returned is a dictionary of band and a list of modes. The band
120                 and modes objects returned must be one of those defined in the
121                 __init___ of this class.
122
123        supported_modes = [{'band' : ap_spec.BAND_2GHZ,
124                            'modes' : [mode_b, mode_b | mode_g]},
125                           {'band' : ap_spec.BAND_5GHZ,
126                            'modes' : [mode_a, mode_n, mode_a | mode_n]}]
127
128        Note: The derived class must implement this method.
129
130        @return a list of dictionaries as described above
131
132        """
133        raise NotImplementedError('Missing subclass implementation')
134
135
136    def is_visibility_supported(self):
137        """
138        Returns if AP supports setting the visibility (SSID broadcast).
139
140        @return True if supported; False otherwise.
141
142        """
143        return True
144
145
146    def is_band_and_channel_supported(self, band, channel):
147        """
148        Returns if a given band and channel are supported.
149
150        @param band: the band to check if supported
151        @param channel: the channel to check if supported
152
153        @return True if combination is supported; False otherwise.
154
155        """
156        raise NotImplementedError('Missing subclass implementation')
157
158
159    def is_security_mode_supported(self, security_mode):
160        """
161        Returns if a given security_type is supported.
162
163        Note: The derived class must implement this method.
164
165        @param security_mode: one of the following modes:
166                         self.security_disabled,
167                         self.security_wep,
168                         self.security_wpapsk,
169                         self.security_wpa2psk
170
171        @return True if the security mode is supported; False otherwise.
172
173        """
174        raise NotImplementedError('Missing subclass implementation')
175
176
177
178    def set_using_ap_spec(self, set_ap_spec, power_up=True):
179        """
180        Sets all configurator options.
181        Note: The derived class may override this method.
182
183        @param set_ap_spec: APSpec object
184        @param power_up: bool, enable power via rpm if applicable
185
186        """
187        logging.warning('%s.%s: Not Implemented',
188                self.__class__.__name__,
189                self.set_using_ap_spec.__name__)
190
191
192    def apply_settings(self):
193        """
194        Apply all settings to the access point.
195        Note: The derived class may override this method.
196
197        """
198        logging.warning('%s.%s: Not Implemented',
199                self.__class__.__name__,
200                self.apply_settings.__name__)
201
202
203    def get_association_parameters(self):
204        """
205        Returns xmlrpc_datatypes.AssociationParameters for this AP
206
207        Note: The derived class must implement this method.
208
209        @return xmlrpc_datatypes.AssociationParameters
210
211        """
212        raise NotImplementedError('Missing subclass implementation')
213
214
215    def debug_last_failure(self, outputdir):
216        """
217        Write debug information for last AP_CONFIG_FAIL
218
219        @param outputdir: a string directory path for debug files
220        """
221        pass
222
223
224    def debug_full_state(self, outputdir):
225        """
226        Write debug information for full AP state
227
228        @param outputdir: a string directory path for debug files
229        """
230        pass
231
232
233    def store_config_failure(self, trace):
234        """
235        Store configuration failure for latter logging
236
237        @param trace: a string traceback of config exception
238        """
239        pass
240