00001
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
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
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
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
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"
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
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
00300 if config['txpower'] != self.current_config['txpower'] or \
00301 config['bitrate'] != self.current_config['bitrate']:
00302
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
00314 if config['wmm'] != self.current_config['wmm']:
00315 self.set_wmm(config['wmm'])
00316 change = True
00317
00318
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
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()