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 LinksysWRT310NApControl:
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["change_status"] = "0"
00039 self.set_req_args["commit"] = "1"
00040 self.set_req_args["nvset_cgi"] = "wireless"
00041 self.set_req_args["next_page"] = ""
00042
00043 print self.current_config
00044
00045 node_name = rospy.get_name()
00046 for param_name in self.current_config:
00047 param_full_name = node_name + "/" + param_name
00048 if not rospy.has_param(param_full_name):
00049 rospy.set_param(param_full_name, self.current_config[param_name])
00050
00051 def mw_to_dbm(self, mw):
00052 return int(10 * math.log10(float(mw)) + 0.5)
00053
00054 def apply_request(self, args, page):
00055 req = urllib2.Request("http://%s/apply.cgi"%(self.hostname))
00056
00057 req_args = dict(self.set_req_args)
00058 if args:
00059 req_args.update(args)
00060 req_args["submit_button"] = page
00061 req.add_data(urllib.urlencode(req_args))
00062
00063 auth = self.passmgr.find_user_password(None, "http://%s/apply.cgi"%(self.hostname))
00064 base64string = base64.encodestring("%s:%s" % auth)[:-1]
00065 req.add_header("Authorization", "Basic %s" % base64string)
00066 req.add_header("Referer", "http://%s/%s.asp"%(self.hostname, page))
00067
00068 lines = urllib2.urlopen(req)
00069 html = lines.read()
00070
00071 if string.find(html, "Invalid Value") != -1:
00072 self.current_config['status'] = "FAIL"
00073 self.current_config['errmsg'] += "Invalid value for param in page %s"%(page)
00074 if string.find(html, "Settings are successful") == -1:
00075 self.current_config['status'] = "FAIL"
00076 self.current_config['errmsg'] += "The request was not successful"
00077
00078 def get_page_info(self, page):
00079 req = urllib2.Request("http://%s/%s.asp"%(self.hostname, page))
00080 auth = self.passmgr.find_user_password(None, "http://%s/%s.asp"%(self.hostname, page))
00081 base64string = base64.encodestring("%s:%s" % auth)[:-1]
00082 req.add_header("Authorization", "Basic %s" % base64string)
00083
00084 lines = urllib2.urlopen(req)
00085 html = lines.read()
00086
00087 return html
00088
00089
00090 def get_wireless_basic_params(self):
00091
00092 html = self.get_page_info("Wireless_Basic")
00093
00094 mode_out = re.findall("(?s)name=\"%s_net_mode.*?_net_mode = '(.*?)'"%(self.interface), html)
00095 ssid_out = re.findall("value='(.*)' name=\"%s_ssid\""%(self.interface), html)
00096 channel_out = re.findall("var %s_channel = '(\d+)'"%(self.interface), html)
00097
00098 if (not mode_out) or (not ssid_out) or (not channel_out):
00099 raise Exception("Could not read interface " + self.interface + " mode or ssid or channel. " +
00100 "Please check that the interface is set to Manual mode and not Wi-Fi Protected Setup")
00101
00102 return mode_out[0], ssid_out[0], int(channel_out[0])
00103
00104 def get_wireless_advanced_params(self):
00105
00106 html = self.get_page_info("Wireless_Advanced")
00107
00108 bitrate_out = re.findall("(?s)name=\"%s_rate.*?value=\"(\d+)\" selected"%(self.interface), html)
00109
00110 return int(bitrate_out[0])
00111
00112 def get_wireless_security_params(self):
00113
00114 html = self.get_page_info("WL_WPATable")
00115
00116 encryption_mode_out = re.findall("var security_mode2 = '(.*?)'", html)
00117
00118 if re.search("wpa2?_personal", encryption_mode_out[0]):
00119 encryption_mode = re.findall("(.*)_.*", encryption_mode_out[0])[0]
00120 encryption_pass = re.findall("name=%s_wpa_psk value='(.*?)'"%(self.interface), html)[0]
00121 elif re.search("wpa2?_enterprise", encryption_mode_out[0]):
00122 encryption_mode = re.findall("(.*)_.*", encryption_mode_out[0])[0] + "_enterprise"
00123 encryption_pass = re.findall("name=%s_radius_key value='(.*?)'"%(self.interface), html)[0]
00124 elif encryption_mode_out[0].find("wep") > -1:
00125 encryption_mode = ApControlConfig.ApControl_wep
00126 encryption_pass = re.findall("name=%s_key1 value='(.*?)'"%(self.interface), html)[0]
00127 else:
00128 encryption_mode = ApControlConfig.ApControl_open
00129 encryption_pass = ""
00130
00131 return encryption_mode, encryption_pass
00132
00133 def get_qos_params(self):
00134
00135 html = self.get_page_info("QoS")
00136
00137 wmm_out = re.findall("value=\"(.*?)\" name=wl_wme checked", html)
00138
00139 if wmm_out[0] == "on":
00140 return True
00141 else:
00142 return False
00143
00144 def get_current_config(self):
00145 mode, ssid, channel = self.get_wireless_basic_params()
00146 band = IEEE80211_Channels.BAND_2400_MHz
00147
00148 self.current_config['ssid'] = ssid
00149 self.current_config['freq'] = float(IEEE80211_Channels.get_freq(channel, band))
00150 if mode == "disabled":
00151 self.current_config['enabled'] = False
00152 else:
00153 self.current_config['enabled'] = True
00154 if mode in ["a-only", "b-only", "g-only"]:
00155 self.current_config['mode'] = mode[0]
00156 self.current_config['ieee80211n'] = False
00157 elif mode == "bg-mixed":
00158 self.current_config['mode'] = "g"
00159 self.current_config['ieee80211n'] = False
00160 elif mode == "mixed" and band == IEEE80211_Channels.BAND_2400_MHz:
00161 self.current_config['mode'] = "g"
00162 self.current_config['ieee80211n'] = True
00163 elif mode == "mixed" and band == IEEE80211_Channels.BAND_5000_MHz:
00164 self.current_config['mode'] = "a"
00165 self.current_config['ieee80211n'] = True
00166 elif mode == "n-only":
00167 self.current_config['ieee80211n'] = True
00168 else:
00169 self.current_config['mode'] = "unknown"
00170 self.current_config['ieee80211n'] = False
00171
00172 self.current_config['bitrate'] = self.get_wireless_advanced_params()
00173
00174 self.current_config['txpower_auto'] = True
00175 self.current_config['txpower'] = 0
00176
00177 self.current_config['encryption_mode'], self.current_config['encryption_pass'] = \
00178 self.get_wireless_security_params()
00179
00180 self.current_config['wmm'] = self.get_qos_params()
00181
00182 def set_wireless_basic(self, ssid, if_mode, channel):
00183 args = {}
00184 if ssid is not None:
00185 args["%s_ssid"%(self.interface)] = ssid
00186 args["%s_net_mode"%(self.interface)] = if_mode
00187 if channel is not None:
00188 args["%s_schannel"%(self.interface)] = channel
00189 args["%s_channel"%(self.interface)] = channel
00190 print args
00191 self.apply_request(args, "Wireless_Basic")
00192
00193 def set_wireless_advanced(self, bitrate):
00194 args = {}
00195 args["%s_rate"%(self.interface)] = bitrate
00196 self.apply_request(args, "Wireless_Advanced")
00197
00198 def set_wireless_security(self, encryption_mode, encryption_pass):
00199 args = {}
00200
00201 if encryption_mode == ApControlConfig.ApControl_open:
00202 args["security_mode2"] = "disabled"
00203 elif encryption_mode == ApControlConfig.ApControl_wep:
00204 args["security_mode2"] = "wep"
00205 args["%s_WEP_key"%(self.interface)] = ""
00206 args["%s_wep"%(self.interface)] = "restricted"
00207 args["%s_key"%(self.interface)] = "1"
00208 args["%s_wep_bit"%(self.interface)] = "64"
00209 args["%s_key1"%(self.interface)] = encryption_pass
00210 elif encryption_mode in [ApControlConfig.ApControl_wpa,\
00211 ApControlConfig.ApControl_wpa2]:
00212 if encryption_mode == ApControlConfig.ApControl_wpa:
00213 args["security_mode2"] = "wpa_personal"
00214
00215 elif encryption_mode == ApControlConfig.ApControl_wpa2:
00216 args["security_mode2"] = "wpa2_personal"
00217
00218 args["%s_wpa_gtk_rekey"%(self.interface)] = "3600"
00219 args["%s_wpa_psk"%(self.interface)] = encryption_pass
00220 elif encryption_mode in [ApControlConfig.ApControl_wpa_enterprise,\
00221 ApControlConfig.ApControl_wpa2_enterprise]:
00222 if encryption_mode == ApControlConfig.ApControl_wpa_enterprise:
00223 args["security_mode2"] = "wpa_enterprise"
00224 else:
00225 args["security_mode2"] = "wpa2_enterprise"
00226 args["%s_wpa_gtk_rekey"%(self.interface)] = "3600"
00227 args["%s_radius_key"%(self.interface)] = encryption_pass
00228 elif encryption_mode == ApControlConfig.ApControl_wpa_wpa2:
00229 self.current_config['status'] = "FAIL"
00230 self.current_config['errmsg'] += "WPA & WPA2 encryption mode not supported"
00231 return
00232 self.apply_request(args, "WL_WPATable")
00233
00234 def set_wmm(self, wmm):
00235 args = {}
00236 if wmm:
00237 args["wl_wme"] = "on"
00238 else:
00239 args["wl_wme"] = "off"
00240 self.apply_request(args, "QoS")
00241
00242 def compare_configs(self, requested_config, read_config):
00243 if requested_config['enabled'] != read_config['enabled']:
00244 self.current_config['status'] = "FAIL"
00245 self.current_config['errmsg'] += "Could not set enabled status, wrote %s, read %s"% \
00246 (requested_config['enabled'], read_config['enabled'])
00247 return
00248
00249 if read_config['enabled']:
00250 for prop in ['mode', 'ssid', 'freq', 'ieee80211n', 'bitrate', 'wmm', 'encryption_mode']:
00251 if requested_config[prop] != read_config[prop]:
00252 self.current_config['status'] = "FAIL"
00253 self.current_config['errmsg'] += "Could not set %s, wrote %s, read %s"% \
00254 (prop, str(requested_config[prop]), str(read_config[prop]))
00255
00256 if read_config['encryption_mode'] != "open":
00257 if requested_config['encryption_pass'] != read_config['encryption_pass']:
00258 self.current_config['status'] = "FAIL"
00259 self.current_config['errmsg'] += "Could not set encryption pass, wrote %s, read %s"% \
00260 (requested_config['encryption_pass'], read_config['encryption_pass'])
00261
00262 def reconfigure(self, config, level):
00263 self.current_config['status'] = "OK"
00264 self.current_config['errmsg'] = ""
00265
00266 change = False
00267
00268 if not config['enabled']:
00269 if self.current_config['enabled']:
00270 self.set_wireless_basic(None, "disabled", None)
00271 change = True
00272 else:
00273 if config['enabled'] != self.current_config['enabled'] or \
00274 config['ssid'] != self.current_config['ssid'] or \
00275 config['freq'] != self.current_config['freq'] or \
00276 config['mode'] != self.current_config['mode'] or \
00277 config['ieee80211n'] != self.current_config['ieee80211n']:
00278 new_channel = IEEE80211_Channels.get_channel(config['freq'])
00279 if not config['enabled']:
00280 new_mode = "disabled"
00281 elif config["ieee80211n"]:
00282 new_mode = "mixed"
00283 else:
00284 new_mode = config['mode'] + "-only"
00285 self.set_wireless_basic(config['ssid'], new_mode, new_channel)
00286 change = True
00287
00288
00289 if config['bitrate'] != self.current_config['bitrate']:
00290 self.set_wireless_advanced(config["bitrate"])
00291 change = True
00292
00293 for prop in [ 'txpower', 'txpower_auto' ]:
00294 if config[prop] != self.current_config[prop]:
00295 self.current_config['status'] = "FAIL"
00296 self.current_config['errmsg'] = "WRT310N does not support TX power control"
00297
00298
00299 if config['wmm'] != self.current_config['wmm']:
00300 self.set_wmm(config['wmm'])
00301 change = True
00302
00303
00304 if config['encryption_mode'] != self.current_config['encryption_mode'] or \
00305 (config['encryption_mode'] != "open" and
00306 config['encryption_pass'] != self.current_config['encryption_pass']):
00307 self.set_wireless_security(config['encryption_mode'], config['encryption_pass'])
00308 change = True
00309
00310
00311 if change:
00312 self.get_current_config()
00313 self.compare_configs(config, self.current_config)
00314
00315 if self.current_config['enabled']:
00316 return self.current_config
00317 else:
00318 config['status'] = self.current_config['status']
00319 config['errmsg'] = self.current_config['errmsg']
00320 config['enabled'] = False
00321 return config
00322
00323 if __name__ == "__main__":
00324 rospy.init_node("linksys_apcontrol_node")
00325
00326 ip = rospy.get_param("~ip", "192.168.1.1")
00327 user = rospy.get_param("~user", "")
00328 password = rospy.get_param("~password", "admin")
00329 interface = rospy.get_param("~interface", "wl")
00330
00331 ap = LinksysWRT310NApControl(ip, user, password, interface)
00332
00333 dynamic_reconfigure.server.Server(ApControlConfig, ap.reconfigure)
00334
00335 rospy.spin()