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 Linksys WRT54G2 router."""
6
7import logging
8import urlparse
9
10import dynamic_ap_configurator
11import ap_spec
12
13
14class LinksysAPConfigurator(
15        dynamic_ap_configurator.DynamicAPConfigurator):
16    """Derived class to control Linksys WRT54G2 router."""
17
18
19    def _sec_alert(self, alert):
20        text = alert.text
21        if 'Invalid Key, must be between 8 and 63 ASCII' in text:
22            raise RuntimeError('We got a modal dialog. ' + text)
23        else:
24            raise RuntimeError('Unhandled alert message: %s' % text)
25
26
27    def get_number_of_pages(self):
28        return 2
29
30
31    def get_supported_bands(self):
32        return [{'band': ap_spec.BAND_2GHZ,
33                 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}]
34
35
36    def get_supported_modes(self):
37        return [{'band': ap_spec.BAND_2GHZ,
38                 'modes': [ap_spec.MODE_B, ap_spec.MODE_G, ap_spec.MODE_B |
39                           ap_spec.MODE_G]}]
40
41
42    def is_security_mode_supported(self, security_mode):
43        return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
44                                 ap_spec.SECURITY_TYPE_WPAPSK,
45                                 ap_spec.SECURITY_TYPE_WPA2PSK,
46                                 ap_spec.SECURITY_TYPE_WEP)
47
48
49    def navigate_to_page(self, page_number):
50        if page_number == 1:
51            url = urlparse.urljoin(self.admin_interface_url, 'wireless.htm')
52            self.driver.get(url)
53            xpath = '//input[@name="wsc_smode" and @value=1]'
54            button = self.driver.find_element_by_xpath(xpath)
55            if not button.is_selected():
56                self.click_button_by_xpath(xpath)
57        elif page_number == 2:
58            url = urlparse.urljoin(self.admin_interface_url, 'WSecurity.htm')
59            self.driver.get(url)
60        else:
61            raise RuntimeError('Invalid page number passed.  Number of pages '
62                               '%d, page value sent was %d' %
63                               (self.get_number_of_pages(), page_number))
64
65
66    def save_page(self, page_number):
67        self.wait_for_object_by_id('divBT1')
68        self.click_button_by_xpath('id("divBT1")')
69        # Wait for the continue button
70        continue_xpath = '//input[@value="Continue" and @type="button"]'
71        self.wait_for_object_by_xpath(continue_xpath)
72        self.click_button_by_xpath(continue_xpath,
73                                   alert_handler=self._sec_alert)
74
75
76    def set_mode(self, mode, band=None):
77        self.add_item_to_command_list(self._set_mode, (mode,), 1, 900)
78
79
80    def _set_mode(self, mode):
81        # Different bands are not supported so we ignore.
82        # Create the mode to popup item mapping
83        mode_mapping = {ap_spec.MODE_B: 'B-Only', ap_spec.MODE_G: 'G-Only',
84                        ap_spec.MODE_B | ap_spec.MODE_G: 'Mixed',
85                        'Disabled': 'Disabled'}
86        mode_name = mode_mapping.get(mode)
87        if not mode_name:
88            raise RuntimeError('The mode selected %d is not supported by router'
89                               ' %s.', hex(mode), self.name)
90        xpath = ('//select[@onchange="SelWL()" and @name="Mode"]')
91        self.select_item_from_popup_by_xpath(mode_name, xpath)
92
93
94    def set_radio(self, enabled=True):
95        # If we are enabling we are activating all other UI components, do it
96        # first.  Otherwise we are turning everything off so do it last.
97        weight = 1 if enabled else 1000
98        self.add_item_to_command_list(self._set_radio, (enabled,), 1, weight)
99
100
101    def _set_radio(self, enabled=True):
102        # To turn off we pick disabled, to turn on we set to G
103        if not enabled:
104            self._set_mode('Disabled')
105        else:
106            self._set_mode(ap_spec.MODE_G)
107
108
109    def set_ssid(self, ssid):
110        self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
111
112
113    def _set_ssid(self, ssid):
114        self._set_radio(enabled=True)
115        xpath = ('//input[@maxlength="32" and @name="SSID"]')
116        self.set_content_of_text_field_by_xpath(ssid, xpath)
117        self._ssid = ssid
118
119
120    def set_channel(self, channel):
121        self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
122
123
124    def _set_channel(self, channel):
125        position = self._get_channel_popup_position(channel)
126        self._set_radio(enabled=True)
127        channel_choices = ['1 - 2.412GHz', '2 - 2.417GHz', '3 - 2.422GHz',
128                           '4 - 2.427GHz', '5 - 2.432GHz', '6 - 2.437GHz',
129                           '7 - 2.442GHz', '8 - 2.447GHz', '9 - 2.452GHz',
130                           '10 - 2.457GHz', '11 - 2.462GHz']
131        xpath = ('//select[@onfocus="check_action(this,0)" and @name="Freq"]')
132        self.select_item_from_popup_by_xpath(channel_choices[position],
133                                             xpath)
134
135
136    def set_band(self, band):
137        return None
138
139
140    def set_security_disabled(self):
141        self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000)
142
143
144    def _set_security_disabled(self):
145        xpath = ('//select[@name="SecurityMode"]')
146        self.select_item_from_popup_by_xpath('Disabled', xpath)
147
148
149    def set_security_wep(self, key_value, authentication):
150        self.add_item_to_command_list(self._set_security_wep,
151                                      (key_value, authentication), 2, 1000)
152
153
154    def _set_security_wep(self, key_value, authentication):
155        logging.debug('This router %s doesnt support WEP authentication type: '
156                      '%s', self.name, authentication)
157        popup = '//select[@name="SecurityMode"]'
158        self.wait_for_object_by_xpath(popup)
159        text_field = ('//input[@name="wl_passphrase"]')
160        self.select_item_from_popup_by_xpath('WEP', popup,
161                                             wait_for_xpath=text_field,
162                                             alert_handler=self._sec_alert)
163        self.set_content_of_text_field_by_xpath(key_value, text_field,
164                                                abort_check=True)
165        self.click_button_by_xpath('//input[@value="Generate"]',
166                                   alert_handler=self._sec_alert)
167
168
169    def set_security_wpapsk(self, security, shared_key, update_interval=1800):
170        self.add_item_to_command_list(self._set_security_wpapsk,
171                                      (security, shared_key, update_interval),
172                                       2, 900)
173
174
175    def _set_security_wpapsk(self, security, shared_key, update_interval=1800):
176        if update_interval < 600:
177            logging.debug('The minimum update interval is 600, overriding.')
178            update_interval = 600
179        elif update_interval > 7200:
180            logging.debug('The maximum update interval is 7200, overriding.')
181            update_interval = 7200
182        popup = '//select[@name="SecurityMode"]'
183        self.wait_for_object_by_xpath(popup)
184        key_field = '//input[@name="PassPhrase"]'
185        if security == ap_spec.SECURITY_TYPE_WPAPSK:
186            wpa_item = 'WPA Personal'
187        else:
188            wpa_item = 'WPA2 Personal'
189        self.select_item_from_popup_by_xpath(wpa_item, popup,
190                                             wait_for_xpath=key_field,
191                                             alert_handler=self._sec_alert)
192        self.set_content_of_text_field_by_xpath(shared_key, key_field,
193                                                abort_check=True)
194        interval_field = ('//input[@name="GkuInterval"]')
195        self.set_content_of_text_field_by_xpath(str(update_interval),
196                                                interval_field)
197
198
199    def set_visibility(self, visible=True):
200        self.add_item_to_command_list(self._set_visibility, (visible,), 1, 900)
201
202
203    def _set_visibility(self, visible=True):
204        self._set_radio(enabled=True)
205        # value=1 is visible; value=0 is invisible
206        int_value = int(visible)
207        xpath = ('//input[@value="%d" and @name="wl_closed"]' % int_value)
208        self.click_button_by_xpath(xpath)
209