Add WDS bridge client mode
Extending / repeating WDS network in AP wizard
Better 802.11s support
This commit is contained in:
Steven Barth 2009-11-29 13:46:04 +00:00
parent 2aa4534db4
commit e822874a71
11 changed files with 267 additions and 54 deletions

View file

@ -54,8 +54,16 @@ $Id$
cbi_d_add("cbi-<%=self.config.."-"..section.."-"..self.option..d.add%>", {
<%-
for k,v in pairs(d.deps) do
local depk
if k:find("!", 1, true) then
depk = string.format('"%s"', k)
elseif k:find(".", 1, true) then
depk = string.format('"cbid.%s"', k)
else
depk = string.format('"cbid.%s.%s.%s"', self.config, section, k)
end
-%>
<%-=string.format('"cbid.%s.%s.%s"', self.config, section, k) .. ":" .. string.format("%q", v)-%>
<%-= depk .. ":" .. string.format("%q", v)-%>
<%-if next(d.deps, k) then-%>,<%-end-%>
<%-
end

View file

@ -35,6 +35,7 @@ local nixio = require "nixio", require "nixio.util"
module("luci.dispatcher", package.seeall)
context = util.threadlocal()
uci = require "luci.model.uci"
i18n = require "luci.i18n"
_M.fs = fs
authenticator = {}

View file

@ -23,11 +23,20 @@ function index()
local toniu = {on_success_to={"niu"}}
local e = entry({"niu", "wireless"}, alias("niu"), "Wireless", 20)
local e = entry({"niu", "wireless"}, alias("niu"), i18n.translate("Wireless"), 20)
--e.niu_dbtemplate = "niu/wireless"
e.niu_dbtasks = true
e.niu_dbicon = "icons32/network-wireless.png"
entry({"niu", "wireless", "ap"},
cbi("niu/wireless/ap", toniu), "Configure Private Access Point", 1)
cbi("niu/wireless/ap", toniu), i18n.translate("Configure Private Access Point"), 1)
local bridge = false
uci.inst:foreach("wireless", "wifi-device", function(s)
if not bridge and (s.type == "mac80211" or s.type == "atheros") then
entry({"niu", "wireless", "bridge"},
cbi("niu/wireless/bridge", toniu), i18n.translate("Join a local WDS network"), 2)
bridge = true
end
end)
end

View file

@ -13,17 +13,30 @@ You may obtain a copy of the License at
$Id$
]]--
local bridge = (arg[1] == "bridgelan")
local niulib = require "luci.niulib"
local fs = require "nixio.fs"
local has_ipv6 = fs.access("/proc/net/ipv6_route")
m = Map("network", "Configure Local Network", "These settings affect the devices in your local network. "..
"Usually you do not need to change anything here for your router to work correctly.")
m = Map("network", translate("Configure Local Network"), bridge and
translate([[The wireless network will be connected directly to your local network.
Make sure you to assign any address to this device that is in the same subnet
of the other devices in your network but that is not already occupied.
If you have a DHCP-Server in this network you may also choose DHCP for address configuration.]])
or translate("These settings affect the devices in your local network. "..
"Usually you do not need to change anything here for your router to work correctly."))
s = m:section(NamedSection, "lan", "interface", "Network Settings")
s.addremove = false
s:tab("general", translate("General Settings"))
s:tab("expert", translate("Expert Settings"))
p = s:taboption("expert", ListValue, "proto", translate("Address Configuration"))
p.default = "static"
p:value("static", translate("Static Configuration"))
p:value("dhcp", "DHCP")
ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
ipaddr.default = "192.168.0.1"
@ -37,14 +50,6 @@ nm:value("255.0.0.0")
nm:depends("proto", "static")
s:tab("expert", translate("Expert Settings"))
p = s:taboption("expert", ListValue, "proto", translate("Connection Protocol"))
p.default = "static"
p:value("static", translate("Static Ethernet"))
p:value("dhcp", "DHCP")
mac = s:taboption("expert", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
mtu = s:taboption("expert", Value, "mtu", "MTU")
@ -54,7 +59,7 @@ dns = s:taboption("expert", Value, "dns", translate("<abbr title=\"Domain Name S
dns:depends("peerdns", "")
gw = s:taboption("expert", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
gw = s:taboption(bridge and "general" or "expert", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
gw:depends("proto", "static")
bcast = s:taboption("expert", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
@ -68,8 +73,11 @@ if has_ipv6 then
ip6gw:depends("proto", "static")
end
emerg = s:taboption("expert", Value, "_emergv4", translate("Emergency Access Address"))
emerg = s:taboption("expert", Value, "_emergv4", translate("Emergency Access Address"),
translate([[In case the DHCP request fails you will still be able to access this device using given IP
by configuring your computer to an address in the same subnet and netmask 255.255.255.0.]]))
emerg:depends("proto", "dhcp")
emerg:value("", translate("disable"))
emerg.default = "169.254.255.169"
@ -83,7 +91,6 @@ for _, eth in ipairs(niulib.eth_get_available("lan")) do
end
m2 = Map("dhcp")
s = m2:section(TypedSection, "dhcp", "DHCP")
@ -95,7 +102,10 @@ s:tab("general", translate("General Settings"))
s:depends("interface", "lan")
enable = s:taboption("general", ListValue, "ignore", "Automatic address assignment for network devices", "")
enable = s:taboption("general", ListValue, "ignore", translate("Automatic address assignment for network devices"),
bridge and
translate("Note: Be careful that you do not accidently two DHCP servers in the same network with overlapping address ranges.")
or "")
enable:value(0, translate("enable"), {["network.lan.proto"] = "static"})
enable:value(1, translate("disable"))
@ -103,17 +113,19 @@ enable:value(1, translate("disable"))
s:tab("expert", translate("Expert Settings"))
start = s:taboption("expert", Value, "start", translate("First leased address"))
start:depends("ignore", "0")
start.default = "100"
limit = s:taboption("expert", Value, "limit", translate("Number of leased addresses"), "")
limit:depends("ignore", "0")
limit.default = "150"
time = s:taboption("expert", Value, "leasetime", "Lease Time")
time = s:taboption("expert", Value, "leasetime", translate("Lease Time"))
time:depends("ignore", "0")
time.default = "12h"
local dd = s:taboption("expert", Flag, "dynamicdhcp", "Also generate addresses for unknown devices")
local dd = s:taboption("expert", Flag, "dynamicdhcp", translate("Also generate addresses for unknown devices"))
dd.rmempty = false
dd.default = "1"
dd:depends("ignore", "0")
return m, m2
return m, m2

View file

@ -18,47 +18,56 @@ local uci = require "luci.model.uci"
local nixio = require "nixio"
local iwinfo = require "iwinfo"
local bridge
local iface = "client"
local net = "wan"
if arg[1] == "bridge" then
bridge = true
iface = "bridge"
net = "lan"
end
local cursor = uci.inst
local state = uci.inst_state
cursor:unload("wireless")
state:unload("wireless")
local has_ipv6 = fs.access("/proc/net/ipv6_route")
local device = cursor:get("wireless", "client", "device")
local device = cursor:get("wireless", iface, "device")
local hwtype = cursor:get("wireless", device, "type")
-- Bring up interface and scan --
if not state:get("wireless", "client", "network") then
if not state:get("wireless", iface, "network") then
local olduci = uci.cursor(nil, "")
local oldcl = olduci:get_all("wireless", "client")
local oldcl = olduci:get_all("wireless", iface)
olduci:unload("wireless")
local newuci = uci.cursor()
local newcl = newuci:get_all("wireless", "client")
newcl.network = "wan"
local newcl = newuci:get_all("wireless", iface)
newcl.network = net
local proc = nixio.fork()
if proc == 0 then
newuci:delete("wireless", "client", "ssid")
newuci:delete("wireless", iface, "ssid")
newuci:commit("wireless")
nixio.exec("/sbin/wifi", "up", device)
os.exit(1)
end
nixio.wait(proc)
newuci:delete("wireless", "client")
newuci:section("wireless", "wifi-iface", "client", oldcl)
newuci:delete("wireless", iface)
newuci:section("wireless", "wifi-iface", iface, oldcl)
newuci:commit("wireless")
newuci:tset("wireless", "client", newcl)
newuci:tset("wireless", iface, newcl)
newuci:save("wireless")
newuci:unload("wireless")
state:unload("wireless")
end
local ifname = state:get("wireless", "client", "ifname") or "wlan0dummy"
local ifname = state:get("wireless", iface, "ifname") or "wlan0dummy"
local iwlib = iwinfo.type(ifname) and iwinfo[iwinfo.type(ifname)]
local suggest = {}
local encrdep = {
@ -78,9 +87,13 @@ end
-- Form definition --
m2 = Map("wireless", "Configure WLAN-Adapter for Internet Connection")
m2 = Map("wireless", translate("Configure WLAN-Adapter for Client Connection"),
bridge and ("<strong>" .. translate([[It is absolutely necessary that the network you are joining
supports and allows bridging (WDS) otherwise your connection will fail.]]) .. "</strong> " ..
translate([[Note: You can use the access point wizard to configure your
private access point to increase the range of the network you are connected to.]])) or "")
s = m2:section(NamedSection, "client", "wifi-iface", "Wireless Settings")
s = m2:section(NamedSection, iface, "wifi-iface", translate("Wireless Settings"))
s.addremove = false
s:tab("general", translate("General Settings"))
@ -122,9 +135,11 @@ encr = s:taboption("general", ListValue, "encryption", translate("Encryption"))
if hwtype == "mac80211" then
mode:value("mesh", translate("Mesh (802.11s)"))
local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID"))
meshid:depends("mode", "mesh")
if not bridge then
mode:value("mesh", translate("Mesh (802.11s)"))
local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID"))
meshid:depends("mode", "mesh")
end
local ps = s:taboption("expert", Flag, "powersave", translate("Enable Powersaving"))
ps:depends("mode", "sta")
@ -208,11 +223,11 @@ end
if not bridge then
m = Map("network")
s = m:section(NamedSection, "wan", "interface", translate("Address Settings"))
s = m:section(NamedSection, net, "interface", translate("Address Settings"))
s.addremove = false
s:tab("general", translate("General Settings"))
@ -261,3 +276,9 @@ mtu.isinteger = true
mac = s:taboption("expert", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
return m2, m
else
return m2
end

View file

@ -9,12 +9,21 @@ end
local function deviceroute(self)
cursor:unload("wireless")
local d = cursor:get("wireless", "ap", "device")
local t = cursor:get("wireless", "ap", "_cfgtpl")
if d ~= "none" then
cursor:delete_all("wireless", "wifi-iface", function(s)
return s.device == d and s._niu ~= "1"
end)
cursor:set("wireless", d, "disabled", 0)
cursor:set("wireless", "ap", "network", "lan")
if t and #t > 0 then
cursor:delete("wireless", "ap", "_cfgtpl")
cursor:set("wireless", "ap", "ssid", cursor:get("wireless", "bridge", "ssid"))
cursor:set("wireless", "ap", "encryption", cursor:get("wireless", "bridge", "encryption"))
cursor:set("wireless", "ap", "key", cursor:get("wireless", "bridge", "key"))
cursor:set("wireless", "ap", "wds", "1")
end
self:set_route("ap1")
else
cursor:delete("wireless", "ap", "network")

View file

@ -16,13 +16,13 @@ $Id$
local iface = "ap"
local ap = true
local fs = require "nixio.fs"
local sys = require "luci.sys"
local cursor = require "luci.model.uci".inst
local state = require "luci.model.uci".inst_state
cursor:unload("wireless")
local device = cursor:get("wireless", iface, "device")
local hwtype = cursor:get("wireless", device, "type")
@ -175,7 +175,9 @@ s.addremove = false
s:tab("general", translate("General Settings"))
s:tab("expert", translate("Expert Settings"))
s:taboption("general", Value, "ssid", translate("Network Name (<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>)"))
local ssid = s:taboption("general", Value, "ssid", translate("Network Name (<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>)"))
mode = s:taboption("expert", ListValue, "mode", translate("Operating Mode"))
mode.override_values = true
@ -185,8 +187,12 @@ encr = s:taboption("expert", ListValue, "encryption", translate("Encryption"))
if hwtype == "mac80211" then
s:taboption("expert", Flag, "wds", translate("Enable Bridging and Repeating (WDS)"))
s:taboption("expert", Flag, "powersave", translate("Enable Powersaving"))
mode:value("mesh", translate("Mesh (802.11s)"))
local meshid = s:taboption("expert", Value, "mesh_id", translate("Mesh ID"))
meshid:depends("mode", "mesh")
s:taboption("expert", Flag, "wds", translate("Enable Bridging and Repeating (WDS)")):depends("mode", "ap")
s:taboption("expert", Flag, "powersave", translate("Enable Powersaving")):depends("mode", "ap")
elseif hwtype == "atheros" then
-- mode:value("wds", translate("Static WDS"))
@ -246,16 +252,26 @@ encr:value("wep", "WEP", {mode="ap"})
if hwtype == "atheros" or hwtype == "mac80211" or hwtype == "prism2" then
local hostapd = fs.access("/usr/sbin/hostapd") or os.getenv("LUCI_SYSROOT")
local supplicant = fs.access("/usr/sbin/wpa_supplicant") or os.getenv("LUCI_SYSROOT")
if hostapd then
--s:taboption("expert", Flag, "_alloweap", "Allow EAP / 802.11i authentication")
if hostapd and not supplicant then
encr:value("psk", "WPA", {mode="ap"})
encr:value("wpa", "WPA-EAP", {mode="ap"})
encr:value("psk-mixed", "WPA + WPA2", {mode="ap"})
encr:value("psk2", "WPA2", {mode="ap"})
encr:value("wpa2", "WPA2-EAP (802.11i)", {mode="ap"})
encr.default = "psk-mixed"
elseif not hostapd and supplicant then
encr:value("psk", "WPA", {mode="mesh"})
encr:value("psk2", "WPA2", {mode="mesh"})
encr.default = "psk2"
elseif hostapd and supplicant then
encr:value("psk", "WPA", {mode="ap"}, {mode="mesh"})
encr:value("wpa", "WPA-EAP", {mode="ap"})
encr:value("psk-mixed", "WPA + WPA2", {mode="ap"})
encr:value("psk2", "WPA2", {mode="ap"}, {mode="mesh"})
encr:value("wpa2", "WPA2-EAP (802.11i)", {mode="ap"})
encr.default = "psk-mixed"
end
elseif hwtype == "broadcom" then
encr:value("psk", "WPA")

View file

@ -12,22 +12,35 @@ You may obtain a copy of the License at
$Id$
]]--
local niulib = require "luci.niulib"
local cursor = require "luci.model.uci".inst
m = Map("wireless", "Configure Private Access Point")
s = m:section(NamedSection, "ap", "interface", translate("Wireless Radio Device"),
m = Map("wireless", translate("Configure Private Access Point"))
s = m:section(NamedSection, "ap", "wifi-iface", translate("Wireless Radio Device"),
translate(
"Select the wireless radio device that should be used to run the interface."..
" Note that wireless radios will not show up here if you already use"..
" them for other wireless services and are not capable of being used as"..
" an access point in parallel."))
" them for other wireless services and are not capable of being used by"..
" more than one service simultaneously or run this specific service at all."))
s.anonymous = true
s.addremove = false
l = s:option(ListValue, "device", "Device providing Access Point")
local l = s:option(ListValue, "device", translate("Wireless Device"))
for _, wifi in ipairs(niulib.wifi_get_available("ap")) do
l:value(wifi, "WLAN-Adapter (%s)" % wifi)
l:value(wifi, translate("WLAN-Adapter (%s)") % wifi)
end
l:value("none", translate("Disable Private Access Point"))
local extend = cursor:get("wireless", "bridge", "network")
and cursor:get("wireless", "bridge", "ssid")
if extend ~= cursor:get("wireless", "ap", "ssid") then
local templ = s:option(ListValue, "_cfgtpl", translate("Configuration Template"))
templ:depends({["!default"] = 1})
templ:depends({["!reverse"] = 1, device = "none"})
templ:value("", translate("Access Point (Current Settings)"))
templ:value("bridge", translate("Extend network %s") % extend)
end
l:value("none", "Disable Private Access Point")
return m

View file

@ -0,0 +1,33 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2009 Steven Barth <steven@midlink.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
local niulib = require "luci.niulib"
m = Map("wireless", translate("Join a local WDS network"))
s = m:section(NamedSection, "bridge", "wifi-iface", translate("Wireless Radio Device"),
translate(
"Select the wireless radio device that should be used to run the interface."..
" Note that wireless radios will not show up here if you already use"..
" them for other wireless services and are not capable of being used by"..
" more than one service simultaneously or run this specific service at all."))
s.anonymous = true
s.addremove = false
l = s:option(ListValue, "device", translate("Wireless Device"))
for _, wifi in ipairs(niulib.wifi_get_available("bridge", {atheros = true, mac80211 = true})) do
l:value(wifi, translate("WLAN-Adapter (%s)") % wifi)
end
l:value("none", translate("Disable Bridge"))
return m

View file

@ -0,0 +1,91 @@
local uci = require "luci.model.uci"
local cursor = uci.cursor()
if not cursor:get("wireless", "bridge") then
cursor:section("wireless", "wifi-iface", "bridge",
{device = "_", doth = "1", _niu = "1", mode = "sta", wds = "1"})
cursor:save("wireless")
end
local function deviceroute(self)
cursor:unload("wireless")
local d = cursor:get("wireless", "bridge", "device")
if d ~= "none" then
local nc = uci.cursor(nil, "")
cursor:delete_all("wireless", "wifi-iface", function(s)
return s.device == d and s._niu ~= "1"
end)
if nc:get("wireless", "bridge", "network")
~= cursor:get("wireless", "bridge", "network") then
cursor:delete("wireless", "bridge", "network")
end
cursor:set("wireless", d, "disabled", 0)
cursor:foreach("dhcp", "dhcp", function(s)
if s.interface == "lan" and s.ignore ~= "1" then
cursor:set("dhcp", s[".name"], "ignore", "1")
end
end)
self:set_route("scan", "bridge", "bridgelan")
else
if cursor:get("wireless", "bridge", "network") then
cursor:delete("wireless", "bridge", "network")
cursor:foreach("dhcp", "dhcp", function(s)
if s.interface == "lan" and s.ignore == "1" then
cursor:set("dhcp", s[".name"], "ignore", "0")
end
end)
self:set_route("lan")
end
end
cursor:save("dhcp")
cursor:save("wireless")
end
local d = Delegator()
d.allow_finish = true
d.allow_back = true
d.allow_cancel = true
d:add("device", "niu/wireless/brdevice")
d:add("deviceroute", deviceroute)
d:set("scan", "niu/network/wlanwanscan")
d:set("bridge", "niu/network/wlanwan")
d:set("bridgelan", "niu/network/lan1")
d:set("lan", "niu/network/lan1")
function d.on_cancel()
cursor:revert("network")
cursor:revert("wireless")
cursor:revert("dhcp")
end
function d.on_done()
if uci.inst_state:get("network", "lan", "ipaddr") ~= cursor:get("network", "lan", "ipaddr") then
local cs = uci.cursor_state()
cs:set("network", "lan", "_ipchanged", "1")
cs:save("network")
end
if cursor:get("network", "lan", "proto") == "dhcp" then
local emergv4 = cursor:get("network", "lan", "_emergv4")
if emergv4 then
if cursor:get("network", "lan_ea") then
cursor:set("network", "lan_ea", "ipaddr", emergv4)
else
cursor:section("network", "alias", "lan_ea", {
ipaddr = emergv4,
netmask = "255.255.255.0",
network = "lan"
})
end
else
cursor:delete("network", "lan_ea")
end
end
cursor:commit("network")
cursor:commit("wireless")
cursor:commit("dhcp")
end
return d

View file

@ -52,7 +52,7 @@ function eth_get_bridged(except)
return cnt > 1 and ifs or {}
end
function wifi_get_available(except)
function wifi_get_available(except, types)
cursor:unload("wireless")
local iwinfo = require "iwinfo"
@ -72,7 +72,7 @@ function wifi_get_available(except)
local wifis = {}
cursor:foreach("wireless", "wifi-device", function(s)
if not used[s[".name"]] then
if not used[s[".name"]] and (not types or types[s.type]) then
wifis[#wifis+1] = s[".name"]
end
end)