From 402ce55c8a079176ef903c94e158310e08530e48 Mon Sep 17 00:00:00 2001 From: hschang Date: Tue, 11 Mar 2014 16:42:44 +0900 Subject: [PATCH] [WirelessAccessPoint] remove so library. - remove _wirelessap.so - add nameserver settings. - use legacy/kernel driver. (for ralink) --- .../SystemPlugins/WirelessAccessPoint/Makefile.am | 4 +- .../WirelessAccessPoint/_wirelessap.so | Bin 131663 -> 0 bytes .../SystemPlugins/WirelessAccessPoint/plugin.py | 493 ++++++++++++++++----- .../WirelessAccessPoint/wirelessap.py | 87 ---- 4 files changed, 379 insertions(+), 205 deletions(-) delete mode 100755 lib/python/Plugins/SystemPlugins/WirelessAccessPoint/_wirelessap.so delete mode 100644 lib/python/Plugins/SystemPlugins/WirelessAccessPoint/wirelessap.py diff --git a/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/Makefile.am b/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/Makefile.am index 4790bfd..e619adc 100755 --- a/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/Makefile.am +++ b/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/Makefile.am @@ -5,6 +5,4 @@ SUBDIRS = meta install_PYTHON = \ __init__.py \ plugin.py \ - hostapd.conf.orig \ - _wirelessap.so \ - wirelessap.py + hostapd.conf.orig diff --git a/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/_wirelessap.so b/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/_wirelessap.so deleted file mode 100755 index ad8bb7d9d74cf0bad7eb9750e380790bb2cb11d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131663 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

vf40C4`b7$BZ(gjc08glsImv;?0 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 xD_g3o!2gC={BJCLRYJk*@kI+9BQj`)G%B*B_uA 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 10: + apModeConfig.wepType.value = "128" + if apModeConfig.wpa.value is not "0" and apModeConfig.wpa_passphrase.value: # (1,WPA), (2,WPA2), (3,WPA/WPA2) apModeConfig.encrypt.value = True apModeConfig.method.value = apModeConfig.wpa.value elif apModeConfig.wep.value and apModeConfig.wep_key0.value: apModeConfig.encrypt.value = True - apModeConfig.method.value = "0" - if len(apModeConfig.wep_key0.value) > 10: - apModeConfig.wepType.value = "128" + apModeConfig.method.value = "0" # wep else: apModeConfig.encrypt.value = False @@ -262,9 +290,14 @@ class WirelessAccessPoint(Screen,ConfigListScreen): self.ipEntry = getConfigListEntry(_("IP Address"), apModeConfig.address) self.netmaskEntry = getConfigListEntry(_("NetMask"), apModeConfig.netmask) self.gatewayEntry = getConfigListEntry(_("Gateway"), apModeConfig.gateway) + self.nameserverEntry = getConfigListEntry(_("Nameserver"), apModeConfig.nameserver) def createConfig(self): global apModeConfig + apModeConfig.address.value = iNetwork.getAdapterAttribute(apModeConfig.branch.value, "ip") or [0,0,0,0] + apModeConfig.netmask.value = iNetwork.getAdapterAttribute(apModeConfig.branch.value, "netmask") or [255,0,0,0] + apModeConfig.gateway.value = iNetwork.getAdapterAttribute(apModeConfig.branch.value, "gateway") or [0,0,0,0] + self.configList = [] self.configList.append( self.useApEntry ) if apModeConfig.useap.value is True: @@ -295,6 +328,7 @@ class WirelessAccessPoint(Screen,ConfigListScreen): self.configList.append( self.ipEntry ) self.configList.append( self.netmaskEntry ) self.configList.append( self.gatewayEntry ) + self.configList.append( self.nameserverEntry ) self["config"].list = self.configList self["config"].l.setList(self.configList) @@ -310,11 +344,68 @@ class WirelessAccessPoint(Screen,ConfigListScreen): if self["config"].getCurrent() in [ self.encryptEntry, self.methodEntry, self.useApEntry, self.usedhcpEntry, self.setupModeEntry]: self.createConfig() + # 0 : legacy module activated, 1 : kernel module activated, -1 : None + def checkProcModules(self): + proc_path = "/proc/modules" + legacy_modules = ("rt3070", "rt3070sta", "rt5372", "rt5372sta", "rt5370", "rt5370sta") + kernel_modules = ("rt2800usb", "rt2800lib") + + fd = open(proc_path, "r") + data = fd.readlines() + fd.close() + + for line in data: + module = line.split()[0].strip() + if module in legacy_modules: + return 0 + elif module in kernel_modules: + return 1 + + return -1 + + def isRalinkModule(self): + global apModeConfig + iface = apModeConfig.wirelessdevice.value + +# check vendor ID for lagacy driver + vendorID = "148f" # ralink vendor ID + idVendorPath = "/sys/class/net/%s/device/idVendor" % iface + if access(idVendorPath, R_OK): + fd = open(idVendorPath, "r") + data = fd.read().strip() + fd.close() + + printDebugMsg("Vendor ID : %s" % data) + + if data == vendorID: + return True + +# check sys driver path for kernel driver + ralinkKmod = "rt2800usb" # ralink kernel driver name + driverPath = "/sys/class/net/%s/device/driver/" % iface + if os_path.exists(driverPath): + driverName = os_path.basename(os_path.realpath(driverPath)) + + printDebugMsg("driverName : %s" % driverName) + + if driverName == ralinkKmod: + return True + + return False + def doConfigMsg(self): - try: - self.session.openWithCallback(self.doConfig, MessageBox, (_("Are you sure you want to setup your AP?\n\n") ) ) - except: - printDebugMsg("doConfig failed") + global apModeConfig + msg = "Are you sure you want to setup AP?\n" + + isRainkIface = self.isRalinkModule() + isApMode = apModeConfig.useap.value is True + isRalinkKmodUploaded = self.checkProcModules() == 1 + + if isRainkIface and isApMode and (not isRalinkKmodUploaded ): + msg += "( STB should be reboot to enable AP mode. )\n" + else: + msg += ("\n") + self.session.openWithCallback(self.doConfig, MessageBox, (_(msg) ) ) def doConfig(self, ret = False): global apModeConfig @@ -325,13 +416,16 @@ class WirelessAccessPoint(Screen,ConfigListScreen): return if not self.checkConfig(): return + self.configStartMsg = self.session.openWithCallback(self.ConfigFinishedMsg, MessageBox, _("Please wait for AP Configuration....\n") , type = MessageBox.TYPE_INFO, enable_input = False) + if apModeConfig.useap.value is True: self.networkRestart( nextFunc = self.makeConf ) else: self.networkRestart( nextFunc = self.removeConf ) def checkEncrypKey(self): + global apModeConfig if apModeConfig.method.value == "0": if self.checkWep(apModeConfig.wep_key0.value) is False: self.session.open(MessageBox, _("Invalid WEP key\n\n"), type = MessageBox.TYPE_ERROR, timeout = 10 ) @@ -345,6 +439,7 @@ class WirelessAccessPoint(Screen,ConfigListScreen): return False def checkWep(self, key): + global apModeConfig length = len(key) if length == 0: return False @@ -356,6 +451,7 @@ class WirelessAccessPoint(Screen,ConfigListScreen): return False def checkConfig(self): + global apModeConfig # ssid Check if len(apModeConfig.ssid.value) == 0 or len(apModeConfig.ssid.value) > 32: self.session.open(MessageBox, _("Invalid SSID\n"), type = MessageBox.TYPE_ERROR, timeout = 10) @@ -402,13 +498,15 @@ class WirelessAccessPoint(Screen,ConfigListScreen): result = self.writeHostapdConfig() if result == -1: self.configStartMsg.close(False) + self.configErrorTimer.start(100, True) return self.setIpForward(1) self.networkRestart_start() def removeConf(self,extra_args): + global apModeConfig printDebugMsg("removeConf") - if fileExists("/etc/hostapd.conf", 0): + if fileExists("/etc/hostapd.conf", 'f'): os_system("mv /etc/hostapd.conf /etc/hostapd.conf.linuxap.back") fp = file("/etc/network/interfaces", 'w') fp.write("# automatically generated by AP Setup Plugin\n# do NOT change manually!\n\n") @@ -423,38 +521,103 @@ class WirelessAccessPoint(Screen,ConfigListScreen): fp.write(" address %d.%d.%d.%d\n" % tuple(apModeConfig.address.value) ) fp.write(" netmask %d.%d.%d.%d\n" % tuple(apModeConfig.netmask.value) ) fp.write(" gateway %d.%d.%d.%d\n" % tuple(apModeConfig.gateway.value) ) + fp.write(" dns-nameservers %d.%d.%d.%d\n" % tuple(apModeConfig.nameserver.value) ) fp.close() self.setIpForward(0) self.networkRestart_start() def networkRestart_start(self): + global apModeConfig printDebugMsg("networkRestart_start") self.restartConsole = Console() self.commands = [] self.commands.append("/etc/init.d/networking start") self.commands.append("/etc/init.d/avahi-daemon start") - self.commands.append("/etc/init.d/hostapd start") + if apModeConfig.useap.value is True: + self.commands.append("/etc/init.d/hostapd start") self.restartConsole.eBatch(self.commands, self.networkRestartFinished, debug=True) def networkRestartFinished(self, data): printDebugMsg("networkRestartFinished") - iNetwork.removeAdapterAttribute('br0',"ip") - iNetwork.removeAdapterAttribute('br0',"netmask") - iNetwork.removeAdapterAttribute('br0',"gateway") + iNetwork.ifaces = {} iNetwork.getInterfaces(self.getInterfacesDataAvail) def getInterfacesDataAvail(self, data): + self.blacklist_legacy_drivers() if data is True and self.configStartMsg is not None: self.configStartMsg.close(True) def ConfigFinishedMsg(self, ret): if ret is True: self.session.openWithCallback(self.ConfigFinishedMsgCallback ,MessageBox, _("Configuration your AP is finished"), type = MessageBox.TYPE_INFO, timeout = 5, default = False) + + def needRalinkKmod(self): + global apModeConfig + isRainkIface = self.isRalinkModule() + ApMode = apModeConfig.useap.value is True + + if isRainkIface and ApMode: + return True else: - self.session.openWithCallback(self.close ,MessageBox, _("Invalid model or Image."), MessageBox.TYPE_ERROR) + return False def ConfigFinishedMsgCallback(self,data): - self.close() + isRalinkKmodUploaded = self.checkProcModules() == 1 + needRalinkKmod_ = self.needRalinkKmod() + + if needRalinkKmod_ : # ralink device is activated in AP Mode. + if not isRalinkKmodUploaded : # reboot to loading kernel module. + msg = "You should now reboot your STB in order to ralink device operate in AP mode.\n\nReboot now ?\n\n" + self.session.openWithCallback(self.doReboot, MessageBox, _(msg), type = MessageBox.TYPE_YESNO, default = True ) + else: + self.close() + elif isRalinkKmodUploaded : + msg = "You should now reboot your STB to better performance of ralink device in STA mode.\n\nReboot now ?\n\n" + self.session.openWithCallback(self.doReboot, MessageBox, _(msg), type = MessageBox.TYPE_YESNO, default = True ) + else: + self.close() + + def blacklist_legacy_drivers(self): + blacklist_conf_dir = "/etc/modprobe.d" + blacklist_conf_file = blacklist_conf_dir + "/blacklist-wlan.conf" + legacy_modules = ("rt3070", "rt3070sta", "rt5372", "rt5372sta", "rt5370", "rt5370sta") + kernel_modules = ("rt2800usb", "rt2800lib") + blacklist = "" + + need_ralink_kmod = self.needRalinkKmod() + + if access(blacklist_conf_file, R_OK) is True: + fd = open(blacklist_conf_file, "r") + data = fd.read() + fd.close() + + if need_ralink_kmod: # check legacy modules in blacklist + for mod in legacy_modules: + if data.find(mod) != -1: return + else: + for mod in kernel_modules: # check kernel modules in blacklist + if data.find(mod) != -1: return + + if not os_path.exists(blacklist_conf_dir): + makedirs(blacklist_conf_dir) + + if need_ralink_kmod: + blacklist_modules = legacy_modules + else: + blacklist_modules = kernel_modules + + for module in blacklist_modules: + blacklist += "blacklist %s\n" % module + f = open(blacklist_conf_file, "w+") + f.write(blacklist) + f.close() + self.apModeChanged = True + + def doReboot(self, res): + if res: + self.session.open(TryQuitMainloop, 2) + else: + self.close() def msgPlugins(self,reason = False): for p in plugins.getPlugins(PluginDescriptor.WHERE_NETWORKCONFIG_READ): @@ -471,11 +634,6 @@ class WirelessAccessPoint(Screen,ConfigListScreen): fp.write("iface eth0 inet manual\n") fp.write(" up ip link set $IFACE up\n") fp.write(" down ip link set $IFACE down\n\n") - # Wireless device setup - fp.write("auto %s\n" % apModeConfig.wirelessdevice.value) - fp.write("iface %s inet manual\n" % apModeConfig.wirelessdevice.value) - fp.write(" up ip link set $IFACE up\n") - fp.write(" down ip link set $IFACE down\n") # branch setup fp.write("auto br0\n") if apModeConfig.usedhcp.value is True: @@ -485,27 +643,14 @@ class WirelessAccessPoint(Screen,ConfigListScreen): fp.write(" address %d.%d.%d.%d\n" % tuple(apModeConfig.address.value) ) fp.write(" netmask %d.%d.%d.%d\n" % tuple(apModeConfig.netmask.value) ) fp.write(" gateway %d.%d.%d.%d\n" % tuple(apModeConfig.gateway.value) ) + fp.write(" dns-nameservers %d.%d.%d.%d\n" % tuple(apModeConfig.nameserver.value) ) fp.write(" pre-up brctl addbr br0\n") fp.write(" pre-up brctl addif br0 eth0\n") -# fp.write(" pre-up brctl addif br0 wlan0\n") // runned by hostpad fp.write(" post-down brctl delif br0 eth0\n") -# fp.write(" post-down brctl delif br0 wlan0\n") // runned by hostpad fp.write(" post-down brctl delbr br0\n\n") fp.write("\n") fp.close() - def writeHostapdConfig(self): #c++ - global apModeConfig - configDict = {} - for key in self.hostapdConfigList.keys(): - configDict[key] = str(self.hostapdConfigList[key].value) - configDict["config.encrypt"] = str(int(apModeConfig.encrypt.value)) - configDict["config.method"] = apModeConfig.method.value - ret = self.wirelessAP.writeHostapdConfig(configDict) - if(ret != 0): - return -1 - return 0 - def setIpForward(self, setValue = 0): ipForwardFilePath = "/proc/sys/net/ipv4/ip_forward" if not fileExists(ipForwardFilePath): @@ -537,21 +682,6 @@ class WirelessAccessPoint(Screen,ConfigListScreen): fp.close() return 0 - def checkWirelessDevices(self): - global apModeConfig - self.wlanDeviceList = [] - wlanIfaces =[] - for x in iNetwork.getInstalledAdapters(): - if x.startswith('eth') or x.startswith('br') or x.startswith('mon'): - continue - wlanIfaces.append(x) - description=self.getAdapterDescription(x) - if description == "Unknown network adapter": - self.wlanDeviceList.append((x, x)) - else: - self.wlanDeviceList.append(( x, description + " (%s)"%x )) - apModeConfig.wirelessdevice = ConfigSelection( choices = self.wlanDeviceList ) - def getAdapterDescription(self, iface): classdir = "/sys/class/net/" + iface + "/device/" driverdir = "/sys/class/net/" + iface + "/device/driver/" @@ -576,6 +706,7 @@ class WirelessAccessPoint(Screen,ConfigListScreen): return _("Unknown network adapter") def __onClose(self): + global apModeConfig for x in self["config"].list: x[1].cancel() apModeConfig.wpa.value = "0" @@ -584,9 +715,141 @@ class WirelessAccessPoint(Screen,ConfigListScreen): def keyCancel(self): self.close() + def printConfigList(self, confList): + printDebugMsg("== printConfigList =="); + for (key, entry) in confList.items(): + printDebugMsg("%s = %s"%(key , str(entry.value))); + + printDebugMsg("== printConfigList end =="); + + def loadHostapConfig(self): + global apModeConfig + fd = -1 + if access("/etc/hostapd.conf", R_OK) is True: + printDebugMsg("open /etc/hostapd.conf") + fd = open("/etc/hostapd.conf", "r") + elif access("/etc/hostapd.conf.linuxap.back", R_OK) is True: + printDebugMsg("open /etc/hostapd.conf.linuxap.back") + fd = open("/etc/hostapd.conf.linuxap.back", "r") + if fd == -1: + printDebugMsg("can not open hostapd.conf") + return -1 + + for line in fd.readlines(): + line = line.strip() + + if (len(line) == 0) or (line.find('=') == -1): + continue + + data = line.split('=', 1) + if len(data) != 2: + continue + + key = data[0].strip() + value = data[1].strip() + + if key == "#wep_key0": + self.hostapdConf["wep_key0"].value = value + apModeConfig.wep.value = False + + elif key == "wep_key0": + self.hostapdConf["wep_key0"].value = value + apModeConfig.wep.value = True + + elif key.startswith('#'): + continue + + elif key == "channel" : + if int(value) not in range(14): + self.hostapdConf[key].value = 1 + else: + self.hostapdConf[key].value = int(value) + + elif key in ["beacon_int", "rts_threshold", "fragm_threshold", "wpa_group_rekey"]: + self.hostapdConf[key].value = int(value) + + elif key in self.hostapdConf.keys(): + self.hostapdConf[key].value = value + + fd.close() + self.printConfigList(self.hostapdConf) + + return 0 + + def writeHostapdConfig(self): + global apModeConfig + global ORIG_HOSTAPD_CONF + self.printConfigList(self.hostapdConf) + if access(ORIG_HOSTAPD_CONF, R_OK) is not True: + self.msg = "can not access file. (%s)" % ORIG_HOSTAPD_CONF + printDebugMsg(self.msg) + return -1 + + orig_conf = open(ORIG_HOSTAPD_CONF, "r") + if orig_conf == -1: + print "can't open file. (%s)" % ORIG_HOSTAPD_CONF + + new_conf = open(HOSTAPD_CONF, "w") + if new_conf == -1: + print "can't open file. (%s)" % HOSTAPD_CONF + + isEncryptOn = apModeConfig.encrypt.value is True + isEncryptWEP = apModeConfig.method.value == "0" + isEncryptWPA = not isEncryptWEP + + for r_line in orig_conf.readlines(): + line = r_line.strip() + if len(line) < 2: + new_conf.write(r_line) + continue + + fix_line = None +# for encrypt line + if line.find("wep_default_key=") != -1 : # is wepLine + if isEncryptOn and isEncryptWEP : + fix_line = "wep_default_key=%s\n" % self.hostapdConf["wep_default_key"].value + + elif line.find("wep_key0=") != -1 : # is WepKeyLine + if isEncryptOn: + if isEncryptWEP : + fix_line = "wep_key0=%s\n" % self.hostapdConf["wep_key0"].value + else: + fix_line = "#wep_key0=%s\n" % self.hostapdConf["wep_key0"].value + + else: + fix_line = "#wep_key0=%s\n" % self.hostapdConf["wep_key0"].value + + elif line.find("wpa=") != -1 : # is wpaLine + if isEncryptOn and isEncryptWPA : + fix_line = "wpa=%s\n" % apModeConfig.method.value +## + elif line.startswith("#ssid"): + pass + + else: + for (key , entry) in self.hostapdConf.items(): + value = str(entry.value) + pos = line.find(key+'=') + if ( (pos != -1) and (pos < 2) ) and len(value)!=0 : + fix_line = "%s=%s\n" % (key, value) + break + +# if fix_line is not None: +# print "r_line : ", r_line, +# print "fix_li : ", fix_line + + if fix_line is not None: + new_conf.write(fix_line) + else: + new_conf.write(r_line) + + orig_conf.close() + new_conf.close() + return 0 + def main(session, **kwargs): session.open(WirelessAccessPoint) def Plugins(**kwargs): - return [PluginDescriptor(name=_("Wireless Access Point"), description="Using a Wireless module as access point.", where = PluginDescriptor.WHERE_PLUGINMENU, needsRestart = True, fnc=main)] + return [PluginDescriptor(name=_("Wireless Access Point"), description=_("Using a Wireless module as access point."), where = PluginDescriptor.WHERE_PLUGINMENU, needsRestart = True, fnc=main)] diff --git a/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/wirelessap.py b/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/wirelessap.py deleted file mode 100644 index 56e85cb..0000000 --- a/lib/python/Plugins/SystemPlugins/WirelessAccessPoint/wirelessap.py +++ /dev/null @@ -1,87 +0,0 @@ -# This file was automatically generated by SWIG (http://www.swig.org). -# Version 1.3.39 -# -# Do not make changes to this file unless you know what you are doing--modify -# the SWIG interface file instead. -# This file is compatible with both classic and new-style classes. - -from sys import version_info -if version_info >= (2,6,0): - def swig_import_helper(): - from os.path import dirname - import imp - fp = None - try: - fp, pathname, description = imp.find_module('_wirelessap', [dirname(__file__)]) - except ImportError: - import _wirelessap - return _wirelessap - if fp is not None: - try: - _mod = imp.load_module('_wirelessap', fp, pathname, description) - finally: - fp.close() - return _mod - _wirelessap = swig_import_helper() - del swig_import_helper -else: - import _wirelessap -del version_info -try: - _swig_property = property -except NameError: - pass # Python < 2.2 doesn't have 'property'. -def _swig_setattr_nondynamic(self,class_type,name,value,static=1): - if (name == "thisown"): return self.this.own(value) - if (name == "this"): - if type(value).__name__ == 'SwigPyObject': - self.__dict__[name] = value - return - method = class_type.__swig_setmethods__.get(name,None) - if method: return method(self,value) - if (not static) or hasattr(self,name): - self.__dict__[name] = value - else: - raise AttributeError("You cannot add attributes to %s" % self) - -def _swig_setattr(self,class_type,name,value): - return _swig_setattr_nondynamic(self,class_type,name,value,0) - -def _swig_getattr(self,class_type,name): - if (name == "thisown"): return self.this.own() - method = class_type.__swig_getmethods__.get(name,None) - if method: return method(self) - raise AttributeError(name) - -def _swig_repr(self): - try: strthis = "proxy of " + self.this.__repr__() - except: strthis = "" - return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) - -try: - _object = object - _newclass = 1 -except AttributeError: - class _object : pass - _newclass = 0 - - -class wirelessAP(_object): - __swig_setmethods__ = {} - __setattr__ = lambda self, name, value: _swig_setattr(self, wirelessAP, name, value) - __swig_getmethods__ = {} - __getattr__ = lambda self, name: _swig_getattr(self, wirelessAP, name) - __repr__ = _swig_repr - def __init__(self): - this = _wirelessap.new_wirelessAP() - try: self.this.append(this) - except: self.this = this - __swig_destroy__ = _wirelessap.delete_wirelessAP - __del__ = lambda self : None; - def loadHostapConfig(self, *args): return _wirelessap.wirelessAP_loadHostapConfig(self, *args) - def writeHostapdConfig(self, *args): return _wirelessap.wirelessAP_writeHostapdConfig(self, *args) -wirelessAP_swigregister = _wirelessap.wirelessAP_swigregister -wirelessAP_swigregister(wirelessAP) - - - -- 2.7.4