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
5"""Class to control the DlinkAP router."""
6
7import os
8
9import dynamic_ap_configurator
10import ap_spec
11from selenium.common.exceptions import TimeoutException as \
12    SeleniumTimeoutException
13
14class DLinkAPConfigurator(
15        dynamic_ap_configurator.DynamicAPConfigurator):
16    """Derived class to control the DLink DAP-1522."""
17
18    def _open_landing_page(self):
19        self.get_url('%s/index.php' % self.admin_interface_url,
20                     page_title='D-Link Corporation')
21        page_name = os.path.basename(self.driver.current_url)
22        if page_name == 'login.php' or page_name == 'index.php':
23            try:
24                self.wait_for_object_by_xpath('//*[@name="login"]')
25            except SeleniumTimeoutException, e:
26                # Maybe we were re-routed to the configuration page
27                if (os.path.basename(self.driver.current_url) ==
28                    'bsc_wizard.php'):
29                    return
30                raise SeleniumTimeoutException('Unable to navigate to the '
31                                               'login or configuration page. '
32                                               'WebDriver exception:%s', str(e))
33            login_button = self.driver.find_element_by_xpath(
34                '//*[@name="login"]')
35            login_button.click()
36
37
38    def _open_configuration_page(self):
39        self._open_landing_page()
40        if os.path.basename(self.driver.current_url) != 'bsc_wizard.php':
41            raise SeleniumTimeoutException('Taken to an unknown page %s' %
42                os.path.basename(self.driver.current_url))
43
44        # Else we are being logged in automatically to the landing page
45        wlan = '//*[@name="wlan_wireless"]'
46        self.wait_for_object_by_xpath(wlan)
47        wlan_button = self.driver.find_element_by_xpath(wlan)
48        wlan_button.click()
49        # Wait for the main configuration page, look for the radio button
50        self.wait_for_object_by_id('enable')
51
52
53    def get_number_of_pages(self):
54        return 1
55
56
57    def get_supported_bands(self):
58        return [{'band': ap_spec.BAND_2GHZ,
59                 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]},
60                {'band': ap_spec.BAND_5GHZ,
61                 'channels': [26, 40, 44, 48, 149, 153, 157, 161, 165]}]
62
63
64    def get_supported_modes(self):
65        return [{'band': ap_spec.BAND_2GHZ,
66                 'modes': [ap_spec.MODE_B, ap_spec.MODE_G, ap_spec.MODE_N,
67                           ap_spec.MODE_B | ap_spec.MODE_G,
68                           ap_spec.MODE_G | ap_spec.MODE_N]},
69                {'band': ap_spec.BAND_5GHZ,
70                 'modes': [ap_spec.MODE_A, ap_spec.MODE_N,
71                           ap_spec.MODE_A | ap_spec.MODE_N]}]
72
73
74    def is_security_mode_supported(self, security_mode):
75        """
76        Returns if a given security_type is supported.
77
78        @param security_mode: one security modes defined in the APSpec
79
80        @return True if the security mode is supported; False otherwise.
81
82        """
83        return security_mode in (self.security_disabled,
84                                 self.security_wpapsk,
85                                 self.security_wep)
86
87
88    def navigate_to_page(self, page_number):
89        """
90        Navigates to the page corresponding to the given page number.
91
92        This method performs the translation between a page number and a url to
93        load. This is used internally by apply_settings.
94
95        @param page_number: page number of the page to load
96
97        """
98        # All settings are on the same page, so we always open the config page
99        self._open_configuration_page()
100
101
102    def save_page(self, page_number):
103        """
104        Saves the given page.
105
106        @param page_number: Page number of the page to save.
107
108        """
109        # All settings are on the same page, we can ignore page_number
110        button = self.driver.find_element_by_xpath('//input[@name="apply"]')
111        button.click()
112        # If we did not make changes we are sent to the continue screen.
113        continue_screen = True
114        button_xpath = '//input[@name="bt"]'
115        try:
116            self.wait_for_object_by_xpath(button_xpath)
117        except SeleniumTimeoutException, e:
118            continue_screen = False
119        if continue_screen:
120            button = self.driver.find_element_by_xpath(button_xpath)
121            button.click()
122        # We will be returned to the landing page when complete
123        self.wait_for_object_by_id('enable')
124
125
126    def set_mode(self, mode, band=None):
127        # Mode overrides the band.  So if a band change is made after a mode
128        # change it may make an incompatible pairing.
129        self.add_item_to_command_list(self._set_mode, (mode, band), 1, 800)
130
131
132    def _set_mode(self, mode, band=None):
133        # Create the mode to popup item mapping
134        mode_mapping = {ap_spec.MODE_B: '802.11b Only',
135            ap_spec.MODE_G: '802.11g Only',
136            ap_spec.MODE_N: '802.11n Only',
137            ap_spec.MODE_B | ap_spec.MODE_G: 'Mixed 802.11g and 802.11b',
138            ap_spec.MODE_N | ap_spec.MODE_G: 'Mixed 802.11n and 802.11g',
139            ap_spec.MODE_N | ap_spec.MODE_G | ap_spec.MODE_B:
140            'Mixed 802.11n, 802.11g, and 802.11b',
141            ap_spec.MODE_N | ap_spec.MODE_G | ap_spec.MODE_B:
142            'Mixed 802.11n, 802.11g, and 802.11b',
143            ap_spec.MODE_A: '802.11a Only',
144            ap_spec.MODE_N | ap_spec.MODE_A: 'Mixed 802.11n and 802.11a'}
145        band_value = ap_spec.BAND_2GHZ
146        if mode in mode_mapping.keys():
147            popup_value = mode_mapping[mode]
148            # If the mode contains 802.11a we use 5Ghz
149            if mode & ap_spec.MODE_A == ap_spec.MODE_A:
150                band_value = ap_spec.BAND_5GHZ
151            # If the mode is 802.11n mixed with 802.11a it must be 5Ghz
152            elif (mode & (ap_spec.MODE_N | ap_spec.MODE_A) ==
153                 (ap_spec.MODE_N | ap_spec.MODE_A)):
154                band_value = ap_spec.BAND_5GHZ
155            # If the mode is 802.11n mixed with other than 802.11a its 2Ghz
156            elif (mode & ap_spec.MODE_N == ap_spec.MODE_N and
157                  mode ^ ap_spec.MODE_N > 0):
158                band_value = ap_spec.BAND_2GHZ
159            # If the mode is 802.11n then default to 5Ghz unless there is a band
160            elif mode == ap_spec.MODE_N:
161                band_value = ap_spec.BAND_5GHZ
162            if band:
163                band_value = band
164        else:
165            raise SeleniumTimeoutException('The mode selected %s is not '
166                                           'supported by router %s.' %
167                                           (hex(mode), self.name))
168        # Set the band first
169        self._set_band(band_value)
170        popup_id = 'mode_80211_11g'
171        if band_value == ap_spec.BAND_5GHZ:
172            popup_id = 'mode_80211_11a'
173        self.select_item_from_popup_by_id(popup_value, popup_id)
174
175
176    def set_radio(self, enabled=True):
177        # If we are enabling we are activating all other UI components, do
178        # it first. Otherwise we are turning everything off so do it last.
179        if enabled:
180            weight = 1
181        else:
182            weight = 1000
183        self.add_item_to_command_list(self._set_radio, (enabled,), 1, weight)
184
185
186    def _set_radio(self, enabled=True):
187        # The radio checkbox for this router always has a value of 1. So we need
188        # to use other methods to determine if the radio is on or not. Check if
189        # the ssid textfield is disabled.
190        ssid = self.driver.find_element_by_xpath('//input[@name="ssid"]')
191        if ssid.get_attribute('disabled') == 'true':
192            radio_enabled = False
193        else:
194            radio_enabled = True
195        if radio_enabled == enabled:
196            # Nothing to do
197            return
198        self.set_check_box_selected_by_id('enable', selected=False,
199            wait_for_xpath='id("security_type_ap")')
200
201
202    def set_ssid(self, ssid):
203        # Can be done as long as it is enabled
204        self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
205
206
207    def _set_ssid(self, ssid):
208        self._set_radio(enabled=True)
209        self.set_content_of_text_field_by_id(ssid, 'ssid')
210        self._ssid = ssid
211
212
213    def set_channel(self, channel):
214        self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
215
216
217    def _set_channel(self, channel):
218        position = self._get_channel_popup_position(channel)
219        self._set_radio(enabled=True)
220        self.set_check_box_selected_by_id('autochann', selected=False)
221        self.select_item_from_popup_by_id(str(position), 'channel_g')
222
223
224    def get_band(self):
225        """
226        This is experimental
227        The radio buttons do more than run a script that adjusts the possible
228        channels. We will just check the channel to popup.
229        """
230        self.set_radioSetting(enabled=True)
231        xpath = ('id("channel_g")')
232        self._open_configuration_page()
233        self.wait_for_object_by_xpath(xpath)
234        element = self.driver.find_element_by_xpath(xpath)
235        if element.find_elements_by_tag_name('option')[0].text == '1':
236            return ap_spec.BAND_2GHZ
237        return ap_spec.BAND_5GHZ
238
239
240    def set_band(self, band):
241        if band != ap_spec.BAND_2GHZ or band != ap_spec.BAND_5GHZ:
242            raise RuntimeError('Invalid band sent %s' % band)
243        self.add_item_to_command_list(self._set_band, (band,), 1, 900)
244
245
246    def _set_band(self, band):
247        self._set_radio(enabled=True)
248        if band == ap_spec.BAND_2GHZ:
249            int_value = 0
250            wait_for_id = 'mode_80211_11g'
251        elif band == ap_spec.BAND_5GHZ:
252            int_value = 1
253            wait_for_id = 'mode_80211_11a'
254            xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" '
255                     'and @name="band"]' % int_value)
256            element = self.driver.find_element_by_xpath(xpath)
257            element.click()
258        self.wait_for_object_by_id(wait_for_id)
259
260
261    def set_security_disabled(self):
262        self.add_item_to_command_list(self._set_security_disabled, (), 1, 900)
263
264
265    def _set_security_disabled(self):
266        self._set_radio(enabled=True)
267        security_disabled = 'Disable Wireless Security (not recommended)'
268        self.select_item_from_popup_by_id(security_disabled, 'security_type_ap')
269
270
271    def set_security_wep(self, key_value, authentication):
272        self.add_item_to_command_list(self._set_security_wep,
273                                      (key_value, authentication), 1, 900)
274
275
276    def _set_security_wep(self, key_value, authentication):
277        self._set_radio(enabled=True)
278        self.select_item_from_popup_by_id('WEP', 'security_type_ap',
279                                          wait_for_xpath='id("auth_type")')
280        self.select_item_from_popup_by_id(authentication, 'auth_type',
281                                          wait_for_xpath='id("wep_key_value")')
282        self.set_content_of_text_field_by_id(key_value, 'wep_key_value')
283        self.set_content_of_text_field_by_id(key_value, 'verify_wep_key_value')
284
285
286    def set_security_wpapsk(self, shared_key, update_interval=1800):
287        self.add_item_to_command_list(self._set_security_wpapsk,
288                                      (shared_key, update_interval), 1, 900)
289
290
291    def _set_security_wpapsk(self, shared_key, update_interval=1800):
292        self._set_radio(enabled=True)
293        self.select_item_from_popup_by_id('WPA-Personal',
294                                          'security_type_ap',
295                                          wait_for_xpath='id("wpa_mode")')
296        self.select_item_from_popup_by_id('WPA Only', 'wpa_mode',
297            wait_for_xpath='id("grp_key_interval")')
298        self.set_content_of_text_field_by_id(str(update_interval),
299                                             'grp_key_interval')
300        self.set_content_of_text_field_by_id(shared_key, 'wpapsk1')
301
302
303    def set_visibility(self, visible=True):
304        self.add_item_to_command_list(self._set_visibility, (visible,), 1, 900)
305
306
307    def _set_visibility(self, visible=True):
308        self._set_radio(enabled=True)
309        # value=0 is visible; value=1 is invisible
310        int_value = int(not visible)
311        xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" '
312                 'and @name="visibility_status"]' % int_value)
313        self.click_button_by_xpath(xpath)
314