$search
00001 #! /usr/bin/env python 00002 00003 import urllib, urllib2, base64 00004 import string, re 00005 import math 00006 00007 import roslib; roslib.load_manifest('linksys_access_point') 00008 import rospy 00009 00010 import dynamic_reconfigure.server 00011 from access_point_control.cfg import ApControlConfig 00012 from ieee80211_channels.channels import IEEE80211_Channels 00013 00014 class LinksysApControl: 00015 00016 def __init__(self, hostname, username, password, interface): 00017 self.hostname = hostname 00018 self.username = username 00019 self.password = password 00020 self.interface = interface 00021 00022 self.passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 00023 self.passmgr.add_password(realm=None, 00024 uri="http://%s/"%(hostname), 00025 user=username, 00026 passwd=password) 00027 self.auth_handler = urllib2.HTTPBasicAuthHandler(self.passmgr) 00028 self.opener = urllib2.build_opener(self.auth_handler) 00029 urllib2.install_opener(self.opener) 00030 00031 self.current_config = {} 00032 self.get_current_config() 00033 00034 self.set_req_args = {} 00035 self.set_req_args["action"] = "Apply" 00036 self.set_req_args["submit_type"] = "" 00037 self.set_req_args["change_action"] = "" 00038 self.set_req_args["commit"] = "1" 00039 self.set_req_args["next_page"] = "" 00040 00041 self.avail_txpower_list = self.get_avail_txpower_list() 00042 00043 node_name = rospy.get_name() 00044 for param_name in self.current_config: 00045 param_full_name = node_name + "/" + param_name 00046 if not rospy.has_param(param_full_name): 00047 rospy.set_param(param_full_name, self.current_config[param_name]) 00048 00049 def mw_to_dbm(self, mw): 00050 return int(10 * math.log10(float(mw)) + 0.5) 00051 00052 def apply_request(self, args, page): 00053 req = urllib2.Request("http://%s/apply.cgi"%(self.hostname)) 00054 00055 req_args = dict(self.set_req_args) 00056 if args: 00057 req_args.update(args) 00058 req_args["submit_button"] = page 00059 req.add_data(urllib.urlencode(req_args)) 00060 00061 auth = self.passmgr.find_user_password(None, "http://%s/apply.cgi"%(self.hostname)) 00062 base64string = base64.encodestring("%s:%s" % auth)[:-1] 00063 req.add_header("Authorization", "Basic %s" % base64string) 00064 req.add_header("Referer", "http://%s/%s.asp"%(self.hostname, page)) 00065 00066 lines = urllib2.urlopen(req) 00067 html = lines.read() 00068 00069 if string.find(html, "Invalid Value") != -1: 00070 self.current_config['status'] = "FAIL" 00071 self.current_config['errmsg'] += "Invalid value for param in page %s"%(page) 00072 if string.find(html, "Settings are successful") == -1: 00073 self.current_config['status'] = "FAIL" 00074 self.current_config['errmsg'] += "The request was not successful" 00075 00076 def get_page_info(self, page): 00077 req = urllib2.Request("http://%s/%s.asp"%(self.hostname, page)) 00078 auth = self.passmgr.find_user_password(None, "http://%s/%s.asp"%(self.hostname, page)) 00079 base64string = base64.encodestring("%s:%s" % auth)[:-1] 00080 req.add_header("Authorization", "Basic %s" % base64string) 00081 00082 lines = urllib2.urlopen(req) 00083 html = lines.read() 00084 00085 return html 00086 00087 def get_avail_txpower_list(self): 00088 html = self.get_page_info("Wireless_Advanced") 00089 out_list = re.findall("(?s)name=\"%s_txpwr.*?Array\((\"\d+\".*?)\)"%(self.interface), html) 00090 txpwr_list = re.findall("\"(\d+)\"", out_list[0]) 00091 txpwr_list_mw = [ int(el) for el in txpwr_list ] 00092 return [ (self.mw_to_dbm(el), el) for el in txpwr_list_mw ] 00093 00094 def get_wireless_basic_params(self): 00095 # mode & ssid & channel 00096 html = self.get_page_info("Wireless_Basic") 00097 00098 mode_out = re.findall("(?s)name=\"%s_net_mode.*?_net_mode = '(.*?)'"%(self.interface), html) 00099 ssid_out = re.findall("value='(.*)' name=\"%s_ssid\""%(self.interface), html) 00100 if self.interface == "wl0": 00101 expression = "(?s)InitValue\(passForm.*?var ch = '(\d+)'" 00102 else: 00103 expression = "(?s)InitValue\(passForm.*?var ch_1 = '(\d+)'" 00104 channel_out = re.findall(expression, html) 00105 00106 if (not mode_out) or (not ssid_out) or (not channel_out): 00107 raise Exception("Could not read interface " + self.interface + " mode or ssid or channel. " + 00108 "Please check that the interface is set to Manual mode and not Wi-Fi Protected Setup") 00109 00110 return mode_out[0], ssid_out[0], int(channel_out[0]) 00111 00112 def get_wireless_advanced_params(self): 00113 # bitrate & txpower 00114 html = self.get_page_info("Wireless_Advanced") 00115 00116 bitrate_out = re.findall("(?s)name=\"%s_rate.*?value=\"(\d+)\" selected"%(self.interface), html) 00117 txpower_out = re.findall("(?s)name=\"%s_txpwr.*?wl_txpwr = '(\d+)'"%(self.interface), html) 00118 00119 return int(bitrate_out[0]), int(txpower_out[0]) 00120 00121 def get_wireless_security_params(self): 00122 # encryption_mode | encryption_pass 00123 html = self.get_page_info("WL_WPATable") 00124 00125 encryption_mode_out = re.findall("(?s)name=%s_security_mode.*?var security_mode = '(.*?)'"%(self.interface), html) 00126 00127 if re.search("wpa2?_personal", encryption_mode_out[0]): 00128 encryption_mode = re.findall("(.*)_.*", encryption_mode_out[0])[0] 00129 encryption_pass = re.findall("name=%s_wpa_psk value='(.*?)'"%(self.interface), html)[0] 00130 elif re.search("wpa2?_enterprise", encryption_mode_out[0]): 00131 encryption_mode = re.findall("(.*)_.*", encryption_mode_out[0])[0] + "_enterprise" 00132 encryption_pass = re.findall("name=%s_radius_key value='(.*?)'"%(self.interface), html)[0] 00133 elif encryption_mode_out[0].find("wep") > -1: 00134 encryption_mode = ApControlConfig.ApControl_wep 00135 encryption_pass = re.findall("name=%s_key1 value='(.*?)'"%(self.interface), html)[0] 00136 else: 00137 encryption_mode = ApControlConfig.ApControl_open 00138 encryption_pass = "" 00139 00140 return encryption_mode, encryption_pass 00141 00142 def get_qos_params(self): 00143 # wmm 00144 html = self.get_page_info("QoS") 00145 00146 wmm_out = re.findall("value=\"(.*?)\" name=wl_wme checked", html) 00147 00148 if wmm_out[0] == "on": 00149 return True 00150 else: 00151 return False 00152 00153 def get_current_config(self): 00154 mode, ssid, channel = self.get_wireless_basic_params() 00155 if self.interface == "wl0": 00156 band = IEEE80211_Channels.BAND_2400_MHz 00157 else: 00158 band = IEEE80211_Channels.BAND_5000_MHz 00159 00160 self.current_config['ssid'] = ssid 00161 self.current_config['freq'] = float(IEEE80211_Channels.get_freq(channel, band)) 00162 if mode == "disabled": 00163 self.current_config['enabled'] = False 00164 else: 00165 self.current_config['enabled'] = True 00166 if mode in ["a-only", "b-only", "g-only"]: 00167 self.current_config['mode'] = mode[0] 00168 self.current_config['ieee80211n'] = False 00169 elif mode == "bg-mixed": 00170 self.current_config['mode'] = "g" 00171 self.current_config['ieee80211n'] = False 00172 elif mode == "mixed" and band == IEEE80211_Channels.BAND_2400_MHz: 00173 self.current_config['mode'] = "g" 00174 self.current_config['ieee80211n'] = True 00175 elif mode == "mixed" and band == IEEE80211_Channels.BAND_5000_MHz: 00176 self.current_config['mode'] = "a" 00177 self.current_config['ieee80211n'] = True 00178 elif mode == "n-only": 00179 self.current_config['ieee80211n'] = True 00180 else: 00181 self.current_config['mode'] = "unknown" 00182 self.current_config['ieee80211n'] = False 00183 00184 self.current_config['bitrate'], txpower = self.get_wireless_advanced_params() 00185 00186 self.current_config['txpower_auto'] = False 00187 self.current_config['txpower'] = self.mw_to_dbm(txpower) 00188 00189 self.current_config['encryption_mode'], self.current_config['encryption_pass'] = \ 00190 self.get_wireless_security_params() 00191 00192 self.current_config['wmm'] = self.get_qos_params() 00193 00194 def set_wireless_basic(self, ssid, if_mode, channel): 00195 args = {} 00196 if ssid is not None: 00197 args["%s_ssid"%(self.interface)] = ssid 00198 args["%s_net_mode"%(self.interface)] = if_mode 00199 if channel is not None: 00200 args["%s_channel"%(self.interface)] = channel 00201 self.apply_request(args, "Wireless_Basic") 00202 00203 def set_wireless_advanced(self, bitrate, txpower): 00204 args = {} 00205 args["%s_txpwr"%(self.interface)] = txpower 00206 args["%s_rate"%(self.interface)] = bitrate 00207 self.apply_request(args, "Wireless_Advanced") 00208 00209 def set_wireless_security(self, encryption_mode, encryption_pass): 00210 args = {} 00211 00212 if encryption_mode == ApControlConfig.ApControl_open: 00213 args["%s_security_mode"%(self.interface)] = "disabled" 00214 elif encryption_mode == ApControlConfig.ApControl_wep: 00215 args["%s_security_mode"%(self.interface)] = "wep" 00216 args["%s_WEP_key"%(self.interface)] = "" 00217 args["%s_wep"%(self.interface)] = "restricted" 00218 args["%s_key"%(self.interface)] = "1" 00219 args["%s_wep_bit"%(self.interface)] = "64" # or "128" 00220 args["%s_key1"%(self.interface)] = encryption_pass 00221 elif encryption_mode in [ApControlConfig.ApControl_wpa,\ 00222 ApControlConfig.ApControl_wpa2]: 00223 if encryption_mode == ApControlConfig.ApControl_wpa: 00224 args["%s_security_mode"%(self.interface)] = "wpa_personal" 00225 args["%s_crypto"%(self.interface)] = "tkip" 00226 elif encryption_mode == ApControlConfig.ApControl_wpa2: 00227 args["%s_security_mode"%(self.interface)] = "wpa2_personal" 00228 args["%s_crypto"%(self.interface)] = "tkip" 00229 args["%s_wpa_gtk_rekey"%(self.interface)] = "3600" 00230 args["%s_wpa_psk"%(self.interface)] = encryption_pass 00231 elif encryption_mode in [ApControlConfig.ApControl_wpa_enterprise,\ 00232 ApControlConfig.ApControl_wpa2_enterprise]: 00233 if encryption_mode == ApControlConfig.ApControl_wpa_enterprise: 00234 args["%s_security_mode"%(self.interface)] = "wpa_enterprise" 00235 else: 00236 args["%s_security_mode"%(self.interface)] = "wpa2_enterprise" 00237 args["%s_wpa_gtk_rekey"%(self.interface)] = "3600" 00238 args["%s_radius_key"%(self.interface)] = encryption_pass 00239 elif encryption_mode == ApControlConfig.ApControl_wpa_wpa2: 00240 self.current_config['status'] = "FAIL" 00241 self.current_config['errmsg'] += "WPA & WPA2 encryption mode not supported" 00242 return 00243 self.apply_request(args, "WL_WPATable") 00244 00245 def set_wmm(self, wmm): 00246 args = {} 00247 if wmm: 00248 args["wl_wme"] = "on" 00249 else: 00250 args["wl_wme"] = "off" 00251 self.apply_request(args, "QoS") 00252 00253 def compare_configs(self, requested_config, read_config): 00254 if requested_config['enabled'] != read_config['enabled']: 00255 self.current_config['status'] = "FAIL" 00256 self.current_config['errmsg'] += "Could not set enabled status, wrote %s, read %s"% \ 00257 (requested_config['enabled'], read_config['enabled']) 00258 return 00259 00260 if read_config['enabled']: 00261 for prop in ['mode', 'ssid', 'freq', 'ieee80211n', 'txpower', 'bitrate', 'wmm', 'encryption_mode']: 00262 if requested_config[prop] != read_config[prop]: 00263 self.current_config['status'] = "FAIL" 00264 self.current_config['errmsg'] += "Could not set %s, wrote %s, read %s"% \ 00265 (prop, str(requested_config[prop]), str(read_config[prop])) 00266 00267 if read_config['encryption_mode'] != "open": 00268 if requested_config['encryption_pass'] != read_config['encryption_pass']: 00269 self.current_config['status'] = "FAIL" 00270 self.current_config['errmsg'] += "Could not set encryption pass, wrote %s, read %s"% \ 00271 (requested_config['encryption_pass'], read_config['encryption_pass']) 00272 00273 def reconfigure(self, config, level): 00274 self.current_config['status'] = "OK" 00275 self.current_config['errmsg'] = "" 00276 00277 change = False 00278 # enabled, ssid, freq, mode, ieee80211n 00279 if not config['enabled']: 00280 if self.current_config['enabled']: 00281 self.set_wireless_basic(None, "disabled", None) 00282 change = True 00283 else: 00284 if config['enabled'] != self.current_config['enabled'] or \ 00285 config['ssid'] != self.current_config['ssid'] or \ 00286 config['freq'] != self.current_config['freq'] or \ 00287 config['mode'] != self.current_config['mode'] or \ 00288 config['ieee80211n'] != self.current_config['ieee80211n']: 00289 new_channel = IEEE80211_Channels.get_channel(config['freq']) 00290 if not config['enabled']: 00291 new_mode = "disabled" 00292 elif config["ieee80211n"]: 00293 new_mode = "mixed" 00294 else: 00295 new_mode = config['mode'] + "-only" 00296 self.set_wireless_basic(config['ssid'], new_mode, new_channel) 00297 change = True 00298 00299 # bitrate & txpower 00300 if config['txpower'] != self.current_config['txpower'] or \ 00301 config['bitrate'] != self.current_config['bitrate']: 00302 # find closest available tx power 00303 min_abs_diff = abs(config['txpower'] - self.avail_txpower_list[0][0]) 00304 for i in range(0, len(self.avail_txpower_list)): 00305 avail_power_dbm = self.avail_txpower_list[i][0] 00306 if abs(config['txpower'] - avail_power_dbm) <= min_abs_diff: 00307 min_abs_diff = abs(config['txpower'] - avail_power_dbm) 00308 closest_power_idx = i 00309 config['txpower'] = self.avail_txpower_list[closest_power_idx][0] 00310 self.set_wireless_advanced(config["bitrate"], self.avail_txpower_list[closest_power_idx][1]) 00311 change = True 00312 00313 # wmm 00314 if config['wmm'] != self.current_config['wmm']: 00315 self.set_wmm(config['wmm']) 00316 change = True 00317 00318 # security params: 00319 if config['encryption_mode'] != self.current_config['encryption_mode'] or \ 00320 (config['encryption_mode'] != "open" and 00321 config['encryption_pass'] != self.current_config['encryption_pass']): 00322 self.set_wireless_security(config['encryption_mode'], config['encryption_pass']) 00323 change = True 00324 00325 # verify config 00326 if change: 00327 self.get_current_config() 00328 self.compare_configs(config, self.current_config) 00329 00330 if self.current_config['enabled']: 00331 return self.current_config 00332 else: 00333 config['status'] = self.current_config['status'] 00334 config['errmsg'] = self.current_config['errmsg'] 00335 config['enabled'] = False 00336 return config 00337 00338 if __name__ == "__main__": 00339 rospy.init_node("linksys_apcontrol_node") 00340 00341 ip = rospy.get_param("~ip", "192.168.1.1") 00342 user = rospy.get_param("~user", "") 00343 password = rospy.get_param("~password", "admin") 00344 interface = rospy.get_param("~interface", "wl0") 00345 00346 ap = LinksysApControl(ip, user, password, interface) 00347 00348 dynamic_reconfigure.server.Server(ApControlConfig, ap.reconfigure) 00349 00350 rospy.spin()