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 5import logging 6import urlparse 7 8import dynamic_ap_configurator 9import ap_spec 10from selenium.common.exceptions import NoSuchElementException as \ 11 SeleniumNoSuchElementException 12from selenium.common.exceptions import WebDriverException 13from selenium.common.exceptions import TimeoutException 14 15 16class BelkinF9K1105APConfigurator( 17 dynamic_ap_configurator.DynamicAPConfigurator): 18 """Base class for Belkin F9K1105 router.""" 19 20 21 def _security_alert(self, alert): 22 text = alert.text 23 if "It is recommended to use WPA/WPA2 when WPS is enabled" in text: 24 alert.accept() 25 elif "Selecting WEP Encryption will disable the WPS" in text: 26 alert.accept() 27 elif 'Key0 is not complete' in text: 28 raise RuntimeError('Got %s error. You should click the generate ' 29 'button to generate a key first' % alert.text) 30 else: 31 raise RuntimeError('Unknown alert dialog' + alert.text) 32 33 34 def get_supported_bands(self): 35 return [{'band': ap_spec.BAND_2GHZ, 36 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, 37 {'band': ap_spec.BAND_5GHZ, 38 'channels': ['Auto', 36, 40, 44, 48, 149, 153, 157, 161]}] 39 40 41 def get_supported_modes(self): 42 return [{'band': ap_spec.BAND_2GHZ, 43 'modes': [ap_spec.MODE_G, ap_spec.MODE_N, 44 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N]}, 45 {'band': ap_spec.BAND_5GHZ, 46 'modes': [ap_spec.MODE_N, ap_spec.MODE_A, 47 ap_spec.MODE_A | ap_spec.MODE_N]}] 48 49 50 def get_number_of_pages(self): 51 return 2 52 53 54 def is_security_mode_supported(self, security_mode): 55 """ 56 Returns if a given security_type is supported. 57 58 @param security_mode: one security modes defined in the APSpec 59 60 @return True if the security mode is supported; False otherwise. 61 62 """ 63 return security_mode in (ap_spec.SECURITY_TYPE_DISABLED, 64 ap_spec.SECURITY_TYPE_WPAPSK, 65 ap_spec.SECURITY_TYPE_WPA2PSK, 66 ap_spec.SECURITY_TYPE_WEP) 67 68 69 def navigate_to_page(self, page_number): 70 """ 71 Navigates to the page corresponding to the given page number. 72 73 This method performs the translation between a page number and a url to 74 load. This is used internally by apply_settings. 75 76 @param page_number: page number of the page to load 77 78 """ 79 if page_number == 1: 80 page_url = urlparse.urljoin(self.admin_interface_url, 'wifi_id.htm') 81 self._load_the_page(page_url, page_title="Network Name") 82 elif page_number == 2: 83 page_url = urlparse.urljoin(self.admin_interface_url, 'wifi_sc.htm') 84 self._load_the_page(page_url, page_title="Security") 85 else: 86 raise RuntimeError('Invalid page number passed. Number of pages ' 87 '%d, page value sent was %d' % 88 (self.get_number_of_pages(), page_number)) 89 90 91 def _load_the_page(self, page_url, page_title): 92 """ 93 Load the given page and check if the title matches and we see the 94 save_button object. 95 96 @param page_url: The url of the page to load. 97 @param page_title: The title of the page we are loading. 98 99 """ 100 self.set_wait_time(20) # The webpage takes a long time to load. 101 try: 102 self.get_url(page_url) 103 self.wait.until(lambda _:page_title in self.driver.title) 104 if 'dashboard' in self.driver.title: 105 # This is a workaround for an issue where the wait would return 106 # even though the page title is not what we expect. 107 self._login(page_url, page_title) 108 except TimeoutException, e: 109 dup = '//h1[contains(text(), "Duplicate Administrator")]' 110 if self.driver.find_element_by_id('p1210a005'): 111 self._login(page_url, page_title) 112 elif self.driver.find_element_by_xpath(dup).is_displayed(): 113 raise RuntimeError('We got the Duplicate admin message. ' 114 'Some one has already logged into the ' 115 'router. So we cannot login.') 116 finally: 117 self.set_wait_time(20) 118 self.wait.until(lambda _:page_title in self.driver.title) 119 self.restore_default_wait_time() 120 121 122 def _login(self, page_url, page_title): 123 """ 124 Login to the router. 125 126 @param page_url: The url of the page to load. 127 @param page_title: The title of the page we are loading. 128 129 """ 130 try: 131 self.wait_for_object_by_id('p1210Password') 132 except SeleniumNoSuchElementException, e: 133 if page_url in self.driver.current_url(): 134 logging.debug("In the login method, but we are already " 135 "logged in.") 136 else: 137 raise RuntimeError('We could not load the page ' + page_url + 138 str(e)) 139 self.set_content_of_text_field_by_id('password', 'p1210Password', 140 abort_check=True) 141 self.click_button_by_id('p1210a005') 142 pwd_wrong = '//small[@class="error" and @id="errpwderr"]' 143 if self.driver.find_element_by_xpath(pwd_wrong).is_displayed(): 144 try: 145 self.wait.until(lambda _:page_title in self.driver.title) 146 except TimeoutException, e: 147 raise RuntimeError('Incorrect password error: ' 148 'The router is not accepting the password.') 149 150 151 def save_page(self, page_number): 152 """ 153 Saves the given page. 154 155 @param page_number: Page number of the page to save. 156 157 """ 158 if page_number == 1: 159 button_id = 'dnsapply' 160 elif page_number == 2: 161 button_id = 'btnapply' 162 if self.driver.find_element_by_id(button_id).is_displayed(): 163 self.click_button_by_id(button_id) 164 page_title = 'Welcome to your Belkin router dashboard!' 165 # The page reloads in about 80 secs and goes back to the dashboard. 166 # The device reboots to apply the changes, hence this delay. 167 try: 168 self.set_wait_time(120) 169 self.wait.until(lambda _: page_title in self.driver.title) 170 except: 171 self.driver.refresh() 172 # If page did not load even after a refresh just continue 173 # because we already clicked the save button. 174 if not page_title in self.driver.title: 175 pass 176 finally: 177 self.restore_default_wait_time() 178 else: 179 raise RuntimeError("We did not save the changes because we " 180 "could not find the button.") 181 182 183 def set_radio(self, enabled=True): 184 logging.debug('This router (%s) does not set the radio', 185 self.name) 186 return None 187 188 189 def set_ssid(self, ssid): 190 self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900) 191 192 193 def _set_ssid(self, ssid): 194 xpath = '//input[@name="wifi_ssid"]' 195 if self.current_band == ap_spec.BAND_5GHZ: 196 xpath = '//input[@name="wifi_ssid1"]' 197 self.set_content_of_text_field_by_xpath(ssid, xpath, abort_check=False) 198 self._ssid = ssid 199 200 201 def set_channel(self, channel): 202 self.add_item_to_command_list(self._set_channel, (channel,), 1, 900) 203 204 205 def _set_channel(self, channel): 206 position = self._get_channel_popup_position(channel) 207 channel_choices = ['Auto', '1', '2', '3', '4', '5', '6', '7', '8', 208 '9', '10', '11'] 209 xpath = '//select[@name="wchan"]' 210 if self.current_band == ap_spec.BAND_5GHZ: 211 xpath = '//select[@name="wchan1"]' 212 channel_choices = ['Auto', '36', '40', '44', '48', '149', '153', 213 '157', '161'] 214 self.select_item_from_popup_by_xpath(channel_choices[position], xpath) 215 216 217 def set_mode(self, mode, band=None): 218 self.add_item_to_command_list(self._set_mode, (mode, band,), 1, 900) 219 220 221 def _set_mode(self, mode, band=None): 222 mode_mapping = {ap_spec.MODE_G: '802.11 g', ap_spec.MODE_A: '802.11 a', 223 ap_spec.MODE_N: '802.11 n', 224 ap_spec.MODE_A | ap_spec.MODE_N: '802.11a & 802.11n', 225 ap_spec.MODE_B | ap_spec.MODE_G | ap_spec.MODE_N: 226 '802.11b & 802.11g & 802.11n'} 227 mode_name = mode_mapping.get(mode) 228 if not mode_name: 229 raise RuntimeError('The mode %d not supported by router %s. ', 230 hex(mode), self.name) 231 xpath = '//select[@name="wbr"]' 232 if self.current_band == ap_spec.BAND_5GHZ: 233 xpath = '//select[@name="wbr1"]' 234 self.select_item_from_popup_by_xpath(mode_name, xpath) 235 236 237 def set_band(self, band): 238 if band == ap_spec.BAND_2GHZ: 239 self.current_band = ap_spec.BAND_2GHZ 240 elif band == ap_spec.BAND_5GHZ: 241 self.current_band = ap_spec.BAND_5GHZ 242 else: 243 raise RuntimeError('Invalid band sent %s' % band) 244 245 246 def _set_security(self, option, wait_for_xpath=None): 247 popup = '//select[@name="wl_authmod"]' 248 if self.current_band == ap_spec.BAND_5GHZ: 249 popup = '//select[@name="wl_authmod1"]' 250 try: 251 self.select_item_from_popup_by_xpath(option, popup, 252 wait_for_xpath=wait_for_xpath, 253 alert_handler= 254 self._security_alert) 255 except WebDriverException, e: 256 message = str(e) 257 if 'Selecting WEP Encryption will disable the WPS' in message: 258 alert = self.driver.switch_to_alert() 259 alert.accept() 260 261 262 def set_security_disabled(self): 263 self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000) 264 265 266 def _set_security_disabled(self): 267 self._set_security('Disabled') 268 269 270 def set_security_wep(self, key_value, authentication): 271 self.add_item_to_command_list(self._set_security_wep, 272 (key_value, authentication), 2, 1000) 273 274 275 def _set_security_wep(self, key_value, authentication): 276 text_field = '//input[@name="wl_phrase"]' 277 generate_button = '//a[@id="btngen" and \ 278 @onclick="return Gen64bitkey(0)"]' 279 if self.current_band == ap_spec.BAND_5GHZ: 280 text_field = '//input[@name="wl1_phrase"]' 281 generate_button = '//a[@id="btngen" and \ 282 @onclick="return Gen64bitkey(1)"]' 283 self._set_security('64bit WEP', wait_for_xpath=text_field) 284 self.set_content_of_text_field_by_xpath(key_value, text_field, 285 abort_check=True) 286 self.click_button_by_xpath(generate_button) 287 288 289 def set_security_wpapsk(self, security, shared_key, update_interval=None): 290 self.add_item_to_command_list(self._set_security_wpapsk, 291 (security, shared_key, update_interval), 292 2, 900) 293 294 295 def _set_security_wpapsk(self, security, shared_key, update_interval=None): 296 auth_popup = '//select[@name="wl_auth"]' 297 psk_field = '//input[@name="wl_wpa_ks_pwd"]' 298 if self.current_band == ap_spec.BAND_5GHZ: 299 auth_popup = '//select[@name="wl1_auth"]' 300 psk_field = '//input[@name="wl1_wpa_ks_pwd"]' 301 self._set_security('WPA/WPA2-Personal (PSK)', wait_for_xpath=auth_popup) 302 selection = 'WPA2-PSK' 303 if security == ap_spec.SECURITY_TYPE_WPAPSK: 304 selection = 'WPA-PSK' 305 self.select_item_from_popup_by_xpath(selection, auth_popup, 306 wait_for_xpath=psk_field, 307 alert_handler=self._security_alert) 308 self.set_content_of_text_field_by_xpath(shared_key, psk_field, 309 abort_check=False) 310 311 312 def is_visibility_supported(self): 313 """ 314 Returns if AP supports setting the visibility (SSID broadcast). 315 316 @return True if supported; False otherwise. 317 """ 318 return False 319 320 321 def is_update_interval_supported(self): 322 """ 323 Returns True if setting the PSK refresh interval is supported. 324 325 @return True is supported; False otherwise 326 """ 327 return False 328