Home | History | Annotate | Download | only in ap_configurators
      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 Dlink Dir655 router."""
      6 
      7 import logging
      8 import time
      9 import urlparse
     10 
     11 import dynamic_ap_configurator
     12 import ap_spec
     13 from selenium.common.exceptions import TimeoutException as \
     14     SeleniumTimeoutException
     15 
     16 
     17 class DLinkDIR655APConfigurator(
     18         dynamic_ap_configurator.DynamicAPConfigurator):
     19     """Derived class to control the DLink DIR-655."""
     20     first_login = True
     21 
     22     def _alert_handler(self, alert):
     23         """Checks for any modal dialogs which popup to alert the user and
     24         either raises a RuntimeError or ignores the alert.
     25 
     26         Args:
     27           alert: The modal dialog's contents.
     28         """
     29         text = alert.text
     30         if 'Password Invalid' in text:
     31             alert.accept()
     32         elif 'Nothing has changed, save anyway?' in text:
     33             alert.accept()
     34         elif 'Mode to 802.11n only, while there is an SSID with WEP' in text:
     35             alert.accept()
     36             raise RuntimeError('Security modes are not compatible: %s' % text)
     37         elif 'The Radius Server 1 can not be zero.' in text:
     38             alert.accept()
     39             raise RuntimeError('Invalid configuration, alert message:\n%s'
     40                                % text)
     41         elif 'The length of the Passphrase must be at least' in text:
     42             alert.accept()
     43             raise RuntimeError('Invalid configuration, alert message:\n%s'
     44                                % text)
     45         elif 'Invalid password, please try again' in text:
     46             alert.accept()
     47             if self.first_login:
     48                 self.first_login = False
     49                 self.login_to_ap()
     50         else:
     51             alert.accept()
     52             raise RuntimeError('We have an unhandled alert: %s' % text)
     53 
     54 
     55     def get_number_of_pages(self):
     56         return 1
     57 
     58 
     59     def is_update_interval_supported(self):
     60         """
     61         Returns True if setting the PSK refresh interval is supported.
     62 
     63         @return True is supported; False otherwise
     64         """
     65         return True
     66 
     67 
     68     def get_supported_bands(self):
     69         return [{'band': ap_spec.BAND_2GHZ,
     70                  'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}]
     71 
     72 
     73     def get_supported_modes(self):
     74         return [{'band': ap_spec.BAND_2GHZ,
     75                  'modes': [ap_spec.MODE_B, ap_spec.MODE_G, ap_spec.MODE_N,
     76                            ap_spec.MODE_B | ap_spec.MODE_G,
     77                            ap_spec.MODE_G | ap_spec.MODE_N,
     78                            ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N]}]
     79 
     80 
     81     def is_security_mode_supported(self, security_mode):
     82         """
     83         Returns if a given security_type is supported.
     84 
     85         @param security_mode: one security modes defined in the APSpec
     86 
     87         @return True if the security mode is supported; False otherwise.
     88 
     89         """
     90         return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
     91                                  ap_spec.SECURITY_TYPE_WEP,
     92                                  ap_spec.SECURITY_TYPE_WPAPSK,
     93                                  ap_spec.SECURITY_TYPE_WPA2PSK)
     94 
     95 
     96     def navigate_to_page(self, page_number):
     97         """
     98         Navigates to the page corresponding to the given page number.
     99 
    100         This method performs the translation between a page number and a url to
    101         load. This is used internally by apply_settings.
    102 
    103         @param page_number: page number of the page to load
    104 
    105         """
    106         # All settings are on the same page, so we always open the config page
    107         page_url = urlparse.urljoin(self.admin_interface_url, 'wireless.asp')
    108         self.get_url(page_url, page_title='D-LINK CORPORATION')
    109         # We wait for the page to load and avoid the intermediate page
    110         found_id = self.wait_for_objects_by_id(['w_enable', 'log_pass'],
    111                                                wait_time=30)
    112         if 'log_pass' in found_id:
    113             self.login_to_ap()
    114         elif 'w_enable' not in found_id:
    115             raise Exception(
    116                     'Unable to navigate to login or configuration page.')
    117 
    118 
    119     def login_to_ap(self):
    120         """Logs into the AP."""
    121         self.set_content_of_text_field_by_id('password', 'log_pass')
    122         self.click_button_by_id('login', alert_handler=self._alert_handler)
    123         # This will send us to the landing page and not where we want to go.
    124         page_url = urlparse.urljoin(self.admin_interface_url, 'wireless.asp')
    125         self.get_url(page_url, page_title='D-LINK CORPORATION')
    126 
    127 
    128     def save_page(self, page_number):
    129         """
    130         Saves the given page.
    131 
    132         @param page_number: Page number of the page to save.
    133 
    134         """
    135         # All settings are on the same page, we can ignore page_number
    136         self.click_button_by_id('button', alert_handler=self._alert_handler)
    137         # Give the router a minute to update.
    138         for i in xrange(120):
    139             progress_value = self.wait_for_object_by_id('show_sec')
    140             html = self.driver.execute_script('return arguments[0].innerHTML',
    141                                               progress_value)
    142             time.sleep(0.5)
    143             if int(html) == 0:
    144                 break
    145         self.click_button_by_id('button', alert_handler=self._alert_handler)
    146         self.wait_for_object_by_id('w_enable')
    147 
    148 
    149     def set_mode(self, mode, band=None):
    150         # Mode overrides the band.  So if a band change is made after a mode
    151         # change it may make an incompatible pairing.
    152         self.add_item_to_command_list(self._set_mode, (mode, band), 1, 800)
    153 
    154 
    155     def _set_mode(self, mode, band=None):
    156         # Create the mode to popup item mapping
    157         mode_mapping = {ap_spec.MODE_B: '802.11b only',
    158             ap_spec.MODE_G: '802.11g only',
    159             ap_spec.MODE_N: '802.11n only',
    160             ap_spec.MODE_B | ap_spec.MODE_G: 'Mixed 802.11g and 802.11b',
    161             ap_spec.MODE_N | ap_spec.MODE_G: 'Mixed 802.11n and 802.11g',
    162             ap_spec.MODE_N | ap_spec.MODE_G | ap_spec.MODE_B:
    163             'Mixed 802.11n, 802.11g and 802.11b'}
    164         if mode in mode_mapping.keys():
    165             popup_value = mode_mapping[mode]
    166         else:
    167             raise SeleniumTimeoutException('The mode selected %s is not '
    168                                            'supported by router %s.' %
    169                                            (hex(mode), self.name))
    170         # When we change to an N based mode another popup is displayed.  We need
    171         # to wait for the before proceeding.
    172         wait_for_xpath = 'id("show_ssid")'
    173         if mode & ap_spec.MODE_N == ap_spec.MODE_N:
    174             wait_for_xpath = 'id("11n_protection")'
    175         self.select_item_from_popup_by_id(popup_value, 'dot11_mode',
    176                                           wait_for_xpath=wait_for_xpath)
    177 
    178 
    179     def set_radio(self, enabled=True):
    180         # If we are enabling we are activating all other UI components, do
    181         # it first. Otherwise we are turning everything off so do it last.
    182         if enabled:
    183             weight = 1
    184         else:
    185             weight = 1000
    186         self.add_item_to_command_list(self._set_radio, (enabled,), 1, weight)
    187 
    188 
    189     def _set_radio(self, enabled=True):
    190         # The radio checkbox for this router always has a value of 1. So we need
    191         # to use other methods to determine if the radio is on or not. Check if
    192         # the ssid textfield is disabled.
    193         ssid = self.driver.find_element_by_id('show_ssid')
    194         checkbox = self.driver.find_element_by_id('w_enable')
    195         if ssid.get_attribute('disabled') == 'true':
    196             radio_enabled = False
    197         else:
    198             radio_enabled = True
    199         if radio_enabled == enabled:
    200             # Nothing to do
    201             return
    202         self.set_check_box_selected_by_id('w_enable', selected=False,
    203             wait_for_xpath='id("wep_type")')
    204 
    205 
    206     def set_ssid(self, ssid):
    207         # Can be done as long as it is enabled
    208         self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
    209 
    210 
    211     def _set_ssid(self, ssid):
    212         self._set_radio(enabled=True)
    213         self.set_content_of_text_field_by_id(ssid, 'show_ssid')
    214         self._ssid = ssid
    215 
    216 
    217     def set_channel(self, channel):
    218         self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
    219 
    220 
    221     def _set_channel(self, channel):
    222         position = self._get_channel_popup_position(channel)
    223         self._set_radio(enabled=True)
    224         channel_choices = ['2.412 GHz - CH 1 ', '2.417 GHz - CH 2',
    225                            '2.422 GHz - CH 3', '2.427 GHz - CH 4',
    226                            '2.432 GHz - CH 5', '2.437 GHz - CH 6',
    227                            '2.442 GHz - CH 7', '2.447 GHz - CH 8',
    228                            '2.452 GHz - CH 9', '2.457 GHz - CH 10',
    229                            '2.462 GHz - CH 11']
    230         channel_popup = self.driver.find_element_by_id('sel_wlan0_channel')
    231         if channel_popup.get_attribute('disabled') == 'true':
    232             self.set_check_box_selected_by_id('auto_channel', selected=False)
    233         self.select_item_from_popup_by_id(channel_choices[position],
    234                                           'sel_wlan0_channel')
    235 
    236 
    237     def set_band(self, band):
    238         logging.debug('This router (%s) does not support multiple bands.',
    239                       self.name)
    240         return None
    241 
    242 
    243     def set_security_disabled(self):
    244         self.add_item_to_command_list(self._set_security_disabled, (), 1, 900)
    245 
    246 
    247     def _set_security_disabled(self):
    248         self._set_radio(enabled=True)
    249         self.select_item_from_popup_by_id('None', 'wep_type')
    250 
    251 
    252     def set_security_wep(self, key_value, authentication):
    253         self.add_item_to_command_list(self._set_security_wep,
    254                                       (key_value, authentication), 1, 900)
    255 
    256 
    257     def _set_security_wep(self, key_value, authentication):
    258         self._set_radio(enabled=True)
    259         self.select_item_from_popup_by_id('WEP', 'wep_type',
    260                                           wait_for_xpath='id("key1")')
    261         self.select_item_from_popup_by_id(authentication, 'auth_type',
    262                                           wait_for_xpath='id("key1")')
    263         self.set_content_of_text_field_by_id(key_value, 'key1')
    264 
    265 
    266     def set_security_wpapsk(self, security, shared_key, update_interval=1800):
    267         self.add_item_to_command_list(self._set_security_wpapsk,
    268                                       (security, shared_key, update_interval),
    269                                        1, 900)
    270 
    271 
    272     def _set_security_wpapsk(self, security, shared_key, update_interval=1800):
    273         self._set_radio(enabled=True)
    274         self.select_item_from_popup_by_id('WPA-Personal', 'wep_type',
    275             wait_for_xpath='id("wlan0_gkey_rekey_time")')
    276         if security == ap_spec.SECURITY_TYPE_WPAPSK:
    277             wpa_item = 'WPA Only'
    278         else:
    279             wpa_item = 'WPA2 Only'
    280         self.select_item_from_popup_by_id(wpa_item, 'wpa_mode',
    281              wait_for_xpath='id("wlan0_psk_pass_phrase")')
    282         self.set_content_of_text_field_by_id(str(update_interval),
    283                                              'wlan0_gkey_rekey_time')
    284         self.set_content_of_text_field_by_id(shared_key,
    285                                              'wlan0_psk_pass_phrase')
    286 
    287 
    288     def set_visibility(self, visible=True):
    289         self.add_item_to_command_list(self._set_visibility, (visible,), 1, 900)
    290 
    291 
    292     def _set_visibility(self, visible=True):
    293         self._set_radio(enabled=True)
    294         # value=1 is visible; value=0 is invisible
    295         int_value = 1 if visible else 0
    296         xpath = ('//input[@value="%d" '
    297                  'and @name="wlan0_ssid_broadcast"]' % int_value)
    298         self.click_button_by_xpath(xpath, alert_handler=self._alert_handler)
    299