Home | History | Annotate | Download | only in ap_configurators
      1 # Copyright (c) 2013 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 import logging
      6 import urlparse
      7 import ap_spec
      8 import dynamic_ap_configurator
      9 from selenium.common.exceptions import WebDriverException
     10 from selenium.common.exceptions import TimeoutException as \
     11     SeleniumTimeoutException
     12 
     13 
     14 class BelkinF9K1103APConfigurator(
     15         dynamic_ap_configurator.DynamicAPConfigurator):
     16     """Class to configure Belkin F9K1103 v1 (01c) router."""
     17 
     18 
     19     def _security_alert(self, alert):
     20         text = alert.text
     21         if 'Invalid character' in text:
     22             alert.accept()
     23         elif 'It is recommended to use WPA/WPA2 when WPS is enabled' in text:
     24             alert.accept()
     25         else:
     26             alert.accept()
     27             raise RuntimeError('Unhandeled modal dialog. %s' % text)
     28 
     29 
     30     def _login(self):
     31         """Opens the login page and logs in using the password.
     32            We need to login before doing any other change to make sure that
     33            we have access to the router.
     34         """
     35         self.driver.delete_all_cookies()
     36         page_url = urlparse.urljoin(self.admin_interface_url,'login.htm')
     37         self.get_url(page_url)
     38         self.driver.switch_to_default_content()
     39         frame = self.driver.find_element_by_name('mainFrame')
     40         self.driver.switch_to_frame(frame)
     41         xpath = '//input[@name="ui_pws"]'
     42         try:
     43             self.set_content_of_text_field_by_xpath('password', xpath,
     44                                                     abort_check=True)
     45             self.click_button_by_id('412')
     46         except WebDriverException, e:
     47             element = self.driver.find_element_by_id('60')
     48             if 'Duplicate Administrator' in element.text:
     49                 raise RuntimeError('Cannot login. Someone has already '
     50                                    'logged into the router. ' + str(e))
     51             else:
     52                 raise WebDriverException('Cannot login. ' + str(e))
     53 
     54 
     55     def get_supported_bands(self):
     56         return [{'band': ap_spec.BAND_2GHZ,
     57                  'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]},
     58                 {'band': ap_spec.BAND_5GHZ,
     59                  'channels': ['Auto', 149, 153, 157, 161, 165]}]
     60 
     61 
     62     def get_supported_modes(self):
     63         return [{'band': ap_spec.BAND_2GHZ,
     64                  'modes': [ap_spec.MODE_G, ap_spec.MODE_N,
     65                            ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N]},
     66                 {'band': ap_spec.BAND_5GHZ,
     67                  'modes': [ap_spec.MODE_A, ap_spec.MODE_N,
     68                            ap_spec.MODE_A | ap_spec.MODE_N]}]
     69 
     70 
     71     def get_number_of_pages(self):
     72         return 2
     73 
     74 
     75     def is_security_mode_supported(self, security_mode):
     76         """
     77         Returns if a given security_type is supported.
     78 
     79         @param security_mode: one security modes defined in the APSpec
     80 
     81         @return True if the security mode is supported; False otherwise.
     82 
     83         """
     84         return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
     85                                  ap_spec.SECURITY_TYPE_WPAPSK,
     86                                  ap_spec.SECURITY_TYPE_WEP)
     87 
     88 
     89     def navigate_to_page(self, page_number):
     90         """
     91         Navigates to the page corresponding to the given page number.
     92 
     93         This method performs the translation between a page number and a url to
     94         load. This is used internally by apply_settings.
     95 
     96         @param page_number: page number of the page to load
     97 
     98         """
     99         self._login()
    100         if page_number == 1:
    101             page_url = urlparse.urljoin(self.admin_interface_url, 'wifi_id.htm')
    102             self.get_url(page_url, page_title='Channel and SSID')
    103             self.driver.switch_to_default_content()
    104             frame = self.driver.find_element_by_name('mainFrame')
    105             self.driver.switch_to_frame(frame)
    106             self.wait_for_object_by_xpath('//input[@name="wifi_ssid"]')
    107         elif page_number == 2:
    108             page_url = urlparse.urljoin(self.admin_interface_url, 'wifi_e.htm')
    109             try:
    110                 self.driver.get(page_url)
    111                 self.wait.until(lambda _:'index.htm' in self.driver.title)
    112             except SeleniumTimeoutException, e:
    113                 # The security page does not load properly, hence we
    114                 # refresh if we don't get the intended page
    115                 try:
    116                     self.driver.get(page_url)
    117                     self.wait.until(lambda _:'index.htm' in self.driver.title)
    118                 except SeleniumTimeoutException, e:
    119                     raise SeleniumTimeoutException('Page did not load. '
    120                                                    + str(e))
    121             try:
    122                 self.driver.switch_to_default_content()
    123                 frame = self.driver.find_element_by_name('mainFrame')
    124                 self.driver.switch_to_frame(frame)
    125                 self.wait_for_object_by_xpath('//select[@name=wl_authmod]')
    126             except (WebDriverException, SeleniumTimeoutException), e:
    127                 message = str(e)
    128                 if (not any(alert in message for alert in [
    129                     'unexpected alert open', 'An open modal dialog blocked'])):
    130                     raise RuntimeError(message)
    131                     return
    132                 self._security_alert(self.driver.switch_to_alert())
    133         else:
    134             raise RuntimeError('Invalid page number passed. Number of pages '
    135                                '%d, page value sent was %d' %
    136                                (self.get_number_of_pages(), page_number))
    137 
    138 
    139     def save_page(self, page_number):
    140         """Save changes and logout from the router.
    141 
    142         @param page_number: the page number to save as an integer.
    143 
    144         """
    145         self.click_button_by_xpath('//input[@type="button" and '
    146                                    '@value="Apply Changes"]',
    147                                    alert_handler=self._security_alert)
    148         self.set_wait_time(120)
    149         try:
    150             self.wait.until(lambda _:'Status' in self.driver.title)
    151         except SeleniumTimeoutException, e:
    152             try:
    153                 # The webpages of this router have a tendency to not load
    154                 # completely, hence we refresh before we raise an excpetion.
    155                 self.driver.refresh()
    156                 self.wait.until(lambda _:'Status' in self.driver.title)
    157             except SeleniumTimeoutException, e:
    158                 raise SeleniumTimeoutException('The changes were not saved. '
    159                                                '%s' % str(e))
    160         finally:
    161             self.restore_default_wait_time()
    162 
    163 
    164     def set_ssid(self, ssid):
    165         self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
    166 
    167 
    168     def _set_ssid(self, ssid):
    169         xpath = '//input[@name="wifi_ssid"]'
    170         if self.current_band == ap_spec.BAND_5GHZ:
    171             xpath = '//input[@name="wifi_ssid1"]'
    172         self.set_content_of_text_field_by_xpath(ssid, xpath, abort_check=False)
    173         self._ssid = ssid
    174 
    175 
    176     def set_channel(self, channel):
    177         self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
    178 
    179 
    180     def _set_channel(self, channel):
    181         position = self._get_channel_popup_position(channel)
    182         channel_choices = ['Auto', '1', '2', '3', '4', '5', '6', '7', '8',
    183                            '9', '10', '11']
    184         xpath = '//select[@name="wchan"]'
    185         if self.current_band == ap_spec.BAND_5GHZ:
    186             xpath = '//select[@name="wchan1"]'
    187             channel_choices = ['Auto', '149', '153', '157', '161', '165']
    188         self.select_item_from_popup_by_xpath(channel_choices[position], xpath)
    189 
    190 
    191     def set_mode(self, mode):
    192         self.add_item_to_command_list(self._set_mode, (mode,), 1, 900)
    193 
    194 
    195     def _set_mode(self, mode):
    196         mode_mapping = {ap_spec.MODE_G: '802.11g', ap_spec.MODE_A: '802.11a',
    197                         ap_spec.MODE_N: '802.11n',
    198                         ap_spec.MODE_A | ap_spec.MODE_N: '802.11a & 802.11n',
    199                         ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N:
    200                         '802.11b & 802.11g & 802.11n'}
    201         mode_name = mode_mapping.get(mode)
    202         if not mode_name:
    203             raise RuntimeError('The mode %d not supported by router %s. ',
    204                                hex(mode), self.name)
    205         xpath = '//select[@name="wbr"]'
    206         if self.current_band == ap_spec.BAND_5GHZ:
    207             xpath = '//select[@name="wbr1"]'
    208         self.select_item_from_popup_by_xpath(mode_name, xpath,
    209                                              wait_for_xpath=None,
    210                                              alert_handler=self._security_alert)
    211 
    212 
    213     def set_radio(self, enabled=True):
    214         logging.debug('This router (%s) does not support radio',
    215                       self.name)
    216         return None
    217 
    218 
    219     def set_band(self, band):
    220         if band == ap_spec.BAND_2GHZ:
    221             self.current_band = ap_spec.BAND_2GHZ
    222         elif band == ap_spec.BAND_5GHZ:
    223             self.current_band = ap_spec.BAND_5GHZ
    224         else:
    225             raise RuntimeError('Invalid band sent %s' % band)
    226 
    227 
    228     def _set_security(self, option, wait_for_xpath=None):
    229         popup = '//select[@name="wl_authmod"]'
    230         if self.current_band == ap_spec.BAND_5GHZ:
    231             popup = '//select[@name="wl_authmod1"]'
    232         try:
    233             self.select_item_from_popup_by_xpath(option, popup,
    234                                                  wait_for_xpath=wait_for_xpath,
    235                                                  alert_handler=
    236                                                  self._security_alert)
    237         except WebDriverException, e:
    238             message = str(e)
    239             if 'Selecting WEP Encryption will disable the WPS' in message:
    240                 alert = self.driver.switch_to_alert()
    241                 alert.accept()
    242 
    243 
    244     def set_security_disabled(self):
    245         self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000)
    246 
    247 
    248     def _set_security_disabled(self):
    249         self._set_security('Disabled')
    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), 2, 1000)
    255 
    256 
    257     def _set_security_wep(self, key_value, authentication):
    258         text_field = '//input[@name="wl_phrase"]'
    259         generate_button = '//input[@id="811" and type="button" and \
    260                           @onclick="Gen64bitkey(0)"]'
    261         if self.current_band == ap_spec.BAND_5GHZ:
    262             text_field = '//input[@name="wl1_phrase"]'
    263             generate_button = '//input[@id="811" and type="button" and \
    264                                @onclick="Gen64bitkey(1)"]'
    265         self._set_security('64bit WEP', wait_for_xpath=text_field)
    266         self.set_content_of_text_field_by_xpath(key_value, text_field,
    267                                                 abort_check=True)
    268         self.click_button_by_id(generate_button)
    269 
    270 
    271     def set_security_wpapsk(self, shared_key, update_interval=None):
    272         self.add_item_to_command_list(self._set_security_wpapsk,
    273                                       (shared_key, update_interval), 2, 900)
    274 
    275 
    276     def _set_security_wpapsk(self, shared_key, update_interval=None):
    277         auth_popup = '//select[@name="wl_auth"]'
    278         psk_field = '//input[@name="wl_wpa_ks_txt"]'
    279         if self.current_band == ap_spec.BAND_5GHZ:
    280             auth_popup = '//select[@name="wl1_auth"]'
    281             psk_field = '//input[@name="wl1_wpa_ks_txt"]'
    282         self._set_security('WPA/WPA2-Personal (PSK)', wait_for_xpath=auth_popup)
    283         self.select_item_from_popup_by_xpath('WPA-PSK', auth_popup,
    284                                              wait_for_xpath=psk_field,
    285                                              alert_handler=
    286                                              self._security_alert)
    287         self.set_content_of_text_field_by_xpath(shared_key, psk_field,
    288                                                 abort_check=True)
    289 
    290 
    291     def is_visibility_supported(self):
    292         """
    293         Returns if AP supports setting the visibility (SSID broadcast).
    294 
    295         @return True if supported; False otherwise.
    296         """
    297         return False
    298 
    299 
    300     def is_update_interval_supported(self):
    301         """
    302         Returns True if setting the PSK refresh interval is supported.
    303 
    304         @return True is supported; False otherwise
    305         """
    306         return False
    307