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 7import logging 8import time 9import urlparse 10 11import dynamic_ap_configurator 12import ap_spec 13from selenium.common.exceptions import TimeoutException as \ 14 SeleniumTimeoutException 15 16 17class 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