wrt310n_apcontrol_node.py
Go to the documentation of this file.
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 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         # mode & ssid & channel
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         # bitrate 
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         # encryption_mode | encryption_pass
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         # wmm
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" # or "128"
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 #                args["%s_crypto"%(self.interface)] = "tkip" 
00215             elif encryption_mode == ApControlConfig.ApControl_wpa2:
00216                 args["security_mode2"] = "wpa2_personal"
00217 #                args["%s_crypto"%(self.interface)] = "tkip" 
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         # enabled, ssid, freq, mode, ieee80211n
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             # bitrate & txpower
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             # wmm
00299             if config['wmm'] != self.current_config['wmm']:
00300                 self.set_wmm(config['wmm'])
00301                 change = True
00302 
00303             # security params:
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         # verify config
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()


linksys_access_point
Author(s): Catalin Drula
autogenerated on Thu Jan 2 2014 11:26:26