linksys_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 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()


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