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"""Class to control the Buffalo WZR d1800hAP router."""
6
7import logging
8import urlparse
9
10import dynamic_ap_configurator
11import ap_spec
12
13
14class BuffalowzrAPConfigurator(
15        dynamic_ap_configurator.DynamicAPConfigurator):
16    """Base class for Buffalo WZR router."""
17
18
19    def get_number_of_pages(self):
20        return 2
21
22
23    def is_update_interval_supported(self):
24        """
25        Returns True if setting the PSK refresh interval is supported.
26
27        @return True is supported; False otherwise
28        """
29        return False
30
31
32    def get_supported_modes(self):
33        return [{'band': ap_spec.BAND_2GHZ,
34                 'modes': [ap_spec.MODE_B, ap_spec.MODE_N, ap_spec.MODE_G]},
35                {'band': ap_spec.BAND_5GHZ,
36                 'modes': [ap_spec.MODE_N, ap_spec.MODE_A]}]
37
38
39    def get_supported_bands(self):
40        return [{'band': ap_spec.BAND_2GHZ,
41                 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11]},
42                {'band': ap_spec.BAND_5GHZ,
43                 'channels': ['Auto', 36, 40, 44, 48, 149, 153,
44                              157, 161, 165]}]
45
46
47    def is_security_mode_supported(self, security_mode):
48        """
49        Returns if a given security_type is supported.
50
51        @param security_mode: one security modes defined in the APSpec
52
53        @return True if the security mode is supported; False otherwise.
54
55        """
56        return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
57                                 ap_spec.SECURITY_TYPE_WPAPSK,
58                                 ap_spec.SECURITY_TYPE_WPA2PSK,
59                                 ap_spec.SECURITY_TYPE_WEP)
60
61
62    def navigate_to_page(self, page_number):
63        """
64        Navigates to the page corresponding to the given page number.
65
66        This method performs the translation between a page number and a url to
67        load. This is used internally by apply_settings.
68
69        @param page_number: page number of the page to load
70
71        """
72        if page_number == 1:
73            url = 'cgi-bin/cgi?req=frm&frm=top_wizard_func_wlan_channel.html'
74            page_url = urlparse.urljoin(self.admin_interface_url, url)
75            self.get_url(page_url, page_title='AirStation Settings')
76        elif page_number == 2:
77            url = 'cgi-bin/cgi?req=frm&frm=top_wizard_func_wlan_if.html'
78            page_url = urlparse.urljoin(self.admin_interface_url, url)
79            self.get_url(page_url, page_title='AirStation Settings')
80        else:
81            raise RuntimeError('Invalid page number passed. Number of pages '
82                               '%d, page value sent was %d' %
83                               (self.get_number_of_pages(), page_number))
84
85
86    def refresh_page(self, apply_set):
87        """Refresh the settings page
88
89        @param apply_set: xpath for the apply button.
90
91        """
92        self.driver.refresh()
93        self._switch_frame()
94        self.wait_for_object_by_xpath(apply_set, wait_time=40)
95
96
97    def save_page(self, page_number):
98        """
99        Saves the given page.
100
101        @param page_number: Page number of the page to save.
102
103        """
104        self._switch_frame()
105        apply_set = '//input[@type="submit"]'
106        try:
107            self.wait_for_object_by_xpath(apply_set, wait_time=40)
108            self.click_button_by_xpath(apply_set)
109        except:
110            self.refresh_page(apply_set)
111            self.click_button_by_xpath(apply_set)
112        # We need to hit one more apply button when settings have changed.
113        try:
114            if self.driver.find_element_by_xpath(apply_set):
115                self.click_button_by_xpath(apply_set)
116        except:
117            logging.debug('Settings have not been changed.')
118        complete = '//input[@type="button"]'
119        # Give some time for router to save changes.
120        # In case when contents of page are not displayed, we need
121        # to refresh page and click apply button one more time.
122        try:
123            self.wait_for_object_by_xpath(complete, wait_time=40)
124        except:
125            self.refresh_page(apply_set)
126            self.click_button_by_xpath(apply_set)
127        self.wait_for_object_by_xpath(complete, wait_time=40)
128        self.driver.find_element_by_xpath(complete)
129        self.click_button_by_xpath(complete)
130
131
132    def _switch_frame(self):
133        frame1 = self.driver.find_element_by_xpath('//frame[@name="lower"]')
134        self.driver.switch_to_frame(frame1)
135
136
137    def set_mode(self, mode, band=None):
138        # We cannot set mode in Buffalo WZR.
139        logging.debug('This router (%s) does not support setting mode.' ,
140                      self.name)
141        return None
142
143
144    def set_radio(self, enabled=True):
145        #  We cannot turn off radio on Buffalo WZR.
146        logging.debug('This router (%s) does not support radio.' , self.name)
147        return None
148
149
150    def set_ssid(self, ssid):
151        self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
152
153
154    def _set_ssid(self, ssid):
155        self._switch_frame()
156        xpath = '//input[@type="text" and @name="ssid_11bg"]'
157        if self.current_band == ap_spec.BAND_5GHZ:
158            xpath = '//input[@type="text" and @name="ssid_11a"]'
159        self.set_content_of_text_field_by_xpath(ssid, xpath)
160        default = self.driver.switch_to_default_content()
161        self._ssid = ssid
162
163
164    def set_channel(self, channel):
165        self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
166
167
168    def _set_channel(self, channel):
169        apply_set = '//input[@type="submit"]'
170        self._switch_frame()
171        position = self._get_channel_popup_position(channel)
172        channel_choice = ['Auto', 'Channel 1', 'Channel 2', 'Channel 3',
173                          'Channel 4', 'Channel 5', 'Channel 6', 'Channel 7',
174                          'Channel 8', 'Channel 9', 'Channel 10', 'Channel 11']
175        xpath = '//select[@name="channel11bg"]'
176        if self.current_band == ap_spec.BAND_5GHZ:
177            xpath = '//select[@name="channel11a"]'
178            channel_choice = ['Auto', 'Channel 36', 'Channel 40', 'Channel 44',
179                              'Channel 48', 'Channel 149', 'Channel 153',
180                              'Channel 157', 'Channel 161', 'Channel 165']
181        try:
182            if self.number_of_items_in_popup_by_xpath(xpath) == 0:
183                # If the popup is empty, refresh.
184                self.refresh_page(apply_set)
185        except:
186            self.refresh_page(apply_set)
187        self.select_item_from_popup_by_xpath(channel_choice[position], xpath)
188        default = self.driver.switch_to_default_content()
189
190
191    def set_ch_width(self, width):
192        """
193        Adjusts the channel width.
194
195        @param width: the channel width
196        """
197        self.add_item_to_command_list(self._set_ch_width,(width,), 1, 900)
198
199
200    def _set_ch_width(self, width):
201        self._switch_frame()
202        channel_width_choice = ['11n/g/bNormal Mode (20 MHz)',
203                                '11n/g/b450 Mbps Mode (40 MHz)']
204        xpath = '//select[@name="nbw_11bg"]'
205        if self.current_band == ap_spec.BAND_5GHZ:
206            channel_width_choice = ['11n/aNormal Mode (20 MHz)',
207                                    '11n/a450 Mbps Mode (40 MHz)',
208                                    '11ac/n/a1300 Mbps Mode (80 MHz)']
209            xpath = '//select[@name="nbw_11a"]'
210        self.select_item_from_popup_by_xpath(channel_width_choice[width],
211                                             xpath)
212        default = self.driver.switch_to_default_content()
213
214
215    def set_band(self, band):
216        if band == ap_spec.BAND_5GHZ:
217            self.current_band = ap_spec.BAND_5GHZ
218        elif band == ap_spec.BAND_2GHZ:
219            self.current_band = ap_spec.BAND_2GHZ
220        else:
221            raise RuntimeError('Invalid band sent %s' % band)
222
223
224    def set_security_disabled(self):
225        self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000)
226
227
228    def _set_security_disabled(self):
229        self._switch_frame()
230        xpath = '//span[@class="WLAN11G"]'
231        if self.current_band == ap_spec.BAND_5GHZ:
232            xpath = '//span[@class="WLAN11A"]'
233        self.driver.find_element_by_xpath(xpath)
234        self.click_button_by_xpath(xpath)
235        self.driver.find_element_by_xpath('//a[text()="Open"]')
236        self.click_button_by_xpath('//a[text()="Open"]')
237        default = self.driver.switch_to_default_content()
238
239
240    def set_security_wep(self, key_value, authentication):
241        self.add_item_to_command_list(self._set_security_wep,
242                                      (key_value, authentication), 2, 1000)
243
244
245    def _set_security_wep(self, key_value, authentication):
246        self.security_wep = "Character Input : 5 characters (WEP64)"
247        self._switch_frame()
248        xpath = '//span[@class="WLAN11G"]'
249        if self.current_band == ap_spec.BAND_5GHZ:
250            xpath = '//span[@class="WLAN11A"]'
251        self.driver.find_element_by_xpath(xpath)
252        self.click_button_by_xpath(xpath)
253        self.driver.find_element_by_xpath('//a[text()="WEP"]')
254        self.click_button_by_xpath('//a[text()="WEP"]')
255        popup = '//select[@name="weptype"]'
256        text_field = '//input[@name="key0"]'
257        self.wait_for_object_by_xpath(popup)
258        self.select_item_from_popup_by_xpath(self.security_wep, popup,
259                                             wait_for_xpath=text_field)
260        self.set_content_of_text_field_by_xpath(key_value, text_field,
261                                                abort_check=True)
262        default = self.driver.switch_to_default_content()
263
264
265    def set_security_wpapsk(self, security, shared_key, update_interval=None):
266        self.add_item_to_command_list(self._set_security_wpapsk,
267                                      (security, shared_key,), 2, 900)
268
269
270    def _set_security_wpapsk(self, security, shared_key, update_interval=None):
271        self._switch_frame()
272        xpath = '//span[@class="WLAN11G"]'
273        if self.current_band == ap_spec.BAND_5GHZ:
274            xpath = '//span[@class="WLAN11A"]'
275        self.driver.find_element_by_xpath(xpath)
276        self.click_button_by_xpath(xpath)
277        if security == ap_spec.SECURITY_TYPE_WPAPSK:
278            wpa_item = '//a[text()="WPA-PSK (AES)"]'
279        else:
280            wpa_item = '//a[text()="WPA2-PSK (AES)"]'
281        self.driver.find_element_by_xpath(wpa_item)
282        self.click_button_by_xpath(wpa_item)
283        text_field = '//input[@name="wpapsk"]'
284        self.set_content_of_text_field_by_xpath(shared_key, text_field,
285                                                abort_check=True)
286        default = self.driver.switch_to_default_content()
287
288
289    def is_visibility_supported(self):
290        """
291        Returns if AP supports setting the visibility (SSID broadcast).
292
293        @return True if supported; False otherwise.
294        """
295        return False
296