modules/admin-full: expose wmm option for mac80211 interfaces
[project/luci.git] / modules / admin-full / luasrc / model / cbi / admin_network / wifi.lua
index b7cfec4..e65dce4 100644 (file)
@@ -14,6 +14,7 @@ $Id$
 
 local wa = require "luci.tools.webadmin"
 local nw = require "luci.model.network"
+local ut = require "luci.util"
 local fs = require "nixio.fs"
 
 arg[1] = arg[1] or ""
@@ -105,6 +106,33 @@ local function txpower_current(pwr, list)
        return (list[#list] and list[#list].driver_dbm) or pwr or 0
 end
 
+local function arplist(opt)
+       local _, e, mac, ip, name
+       local arp = { }
+
+       for _, e in ipairs(luci.sys.net.arptable()) do
+               arp[e["HW address"]:upper()] = { e["IP address"] }
+       end
+
+       if fs.access("/etc/ethers") then
+               for e in io.lines("/etc/ethers") do
+                       mac, ip = e:match("^([a-f0-9]%S+) (%S+)")
+                       if mac and ip then arp[mac:upper()] = { ip } end
+               end
+       end
+
+       if fs.access("/var/dhcp.leases") then
+               for e in io.lines("/var/dhcp.leases") do
+                       mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)")
+                       if mac and ip then arp[mac:upper()] = { ip, name ~= "*" and name } end
+               end
+       end
+
+       for mac, e in luci.util.kspairs(arp) do
+               opt:value(mac, "%s (%s)" %{ mac, e[2] or e[1] })
+       end
+end
+
 local iw = luci.sys.wifi.getiwinfo(arg[1])
 local hw_modes      = iw.hwmodelist or { }
 local tx_power_list = txpower_list(iw)
@@ -174,20 +202,19 @@ end
 ------------------- MAC80211 Device ------------------
 
 if hwtype == "mac80211" then
-       tp = s:taboption("general",
-               (#tx_power_list > 0) and ListValue or Value,
-               "txpower", translate("Transmit Power"), "dBm")
-
-       tp.rmempty = true
-       tp.default = tx_power_cur
-
-       function tp.cfgvalue(...)
-               return txpower_current(Value.cfgvalue(...), tx_power_list)
-       end
+       if #tx_power_list > 1 then
+               tp = s:taboption("general", ListValue,
+                       "txpower", translate("Transmit Power"), "dBm")
+               tp.rmempty = true
+               tp.default = tx_power_cur
+               function tp.cfgvalue(...)
+                       return txpower_current(Value.cfgvalue(...), tx_power_list)
+               end
 
-       for _, p in ipairs(tx_power_list) do
-               tp:value(p.driver_dbm, "%i dBm (%i mW)"
-                       %{ p.display_dbm, p.display_mw })
+               for _, p in ipairs(tx_power_list) do
+                       tp:value(p.driver_dbm, "%i dBm (%i mW)"
+                               %{ p.display_dbm, p.display_mw })
+               end
        end
 
        mode = s:taboption("advanced", ListValue, "hwmode", translate("Mode"))
@@ -389,7 +416,8 @@ network = s:taboption("general", Value, "network", translate("Network"),
 
 network.rmempty = true
 network.template = "cbi/network_netlist"
-network.widget = "radio"
+network.widget = "checkbox"
+network.novirtual = true
 
 function network.write(self, section, value)
        local i = nw:get_interface(section)
@@ -404,10 +432,18 @@ function network.write(self, section, value)
                                if n then n:del_interface(i) end
                        end
                else
-                       local n = nw:get_network(value)
-                       if n then
-                               n:set("type", "bridge")
-                               n:add_interface(i)
+                       local v
+                       for _, v in ipairs(i:get_networks()) do
+                               v:del_interface(i)
+                       end
+                       for v in ut.imatch(value) do
+                               local n = nw:get_network(v)
+                               if n then
+                                       if not n:is_empty() then
+                                               n:set("type", "bridge")
+                                       end
+                                       n:add_interface(i)
+                               end
                        end
                end
        end
@@ -437,6 +473,7 @@ if hwtype == "mac80211" then
        ml.datatype = "macaddr"
        ml:depends({macfilter="allow"})
        ml:depends({macfilter="deny"})
+       arplist(ml)
 
        mode:value("ap-wds", "%s (%s)" % {translate("Access Point"), translate("WDS")})
        mode:value("sta-wds", "%s (%s)" % {translate("Client"), translate("WDS")})
@@ -470,6 +507,11 @@ if hwtype == "mac80211" then
        hidden = s:taboption("general", Flag, "hidden", translate("Hide <abbr title=\"Extended Service Set Identifier\">ESSID</abbr>"))
        hidden:depends({mode="ap"})
        hidden:depends({mode="ap-wds"})
+
+       wmm = s:taboption("general", Flag, "wmm", translate("WMM Mode"))
+       wmm:depends({mode="ap"})
+       wmm:depends({mode="ap-wds"})
+       wmm.default = wmm.enabled
 end
 
 
@@ -536,6 +578,7 @@ if hwtype == "atheros" then
        ml.datatype = "macaddr"
        ml:depends({macpolicy="allow"})
        ml:depends({macpolicy="deny"})
+       arplist(ml)
 
        s:taboption("advanced", Value, "rate", translate("Transmission Rate"))
        s:taboption("advanced", Value, "mcast_rate", translate("Multicast Rate"))
@@ -609,6 +652,7 @@ if hwtype == "prism2" then
        ml = s:taboption("macfilter", DynamicList, "maclist", translate("MAC-List"))
        ml:depends({macpolicy="allow"})
        ml:depends({macpolicy="deny"})
+       arplist(ml)
 
        s:taboption("advanced", Value, "rate", translate("Transmission Rate"))
        s:taboption("advanced", Value, "frag", translate("Fragmentation Threshold"))
@@ -682,25 +726,33 @@ end
 
 
 encr:value("none", "No Encryption")
-encr:value("wep-open",   translate("WEP Open System"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
-encr:value("wep-shared", translate("WEP Shared Key"),  {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+encr:value("wep-open",   translate("WEP Open System"), {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
+encr:value("wep-shared", translate("WEP Shared Key"),  {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"}, {mode="adhoc"}, {mode="ahdemo"}, {mode="wds"})
 
 if hwtype == "atheros" or hwtype == "mac80211" or hwtype == "prism2" then
        local supplicant = fs.access("/usr/sbin/wpa_supplicant")
        local hostapd = fs.access("/usr/sbin/hostapd")
 
+       -- Probe EAP support
+       local has_ap_eap  = (os.execute("hostapd -veap >/dev/null 2>/dev/null") == 0)
+       local has_sta_eap = (os.execute("wpa_supplicant -veap >/dev/null 2>/dev/null") == 0)
+
        if hostapd and supplicant then
-               encr:value("psk", "WPA-PSK")
-               encr:value("psk2", "WPA2-PSK")
-               encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode")
-               encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
-               encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+               encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+               encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+               encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+               if has_ap_eap and has_sta_eap then
+                       encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+                       encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="sta"}, {mode="ap-wds"}, {mode="sta-wds"})
+               end
        elseif hostapd and not supplicant then
-               encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="ap-wds"}, {mode="adhoc"}, {mode="ahdemo"})
-               encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="ap-wds"}, {mode="adhoc"}, {mode="ahdemo"})
-               encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="ap-wds"}, {mode="adhoc"}, {mode="ahdemo"})
-               encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="ap-wds"})
-               encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="ap-wds"})
+               encr:value("psk", "WPA-PSK", {mode="ap"}, {mode="ap-wds"})
+               encr:value("psk2", "WPA2-PSK", {mode="ap"}, {mode="ap-wds"})
+               encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="ap"}, {mode="ap-wds"})
+               if has_ap_eap then
+                       encr:value("wpa", "WPA-EAP", {mode="ap"}, {mode="ap-wds"})
+                       encr:value("wpa2", "WPA2-EAP", {mode="ap"}, {mode="ap-wds"})
+               end
                encr.description = translate(
                        "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
                        "and ad-hoc mode) to be installed."
@@ -709,8 +761,10 @@ if hwtype == "atheros" or hwtype == "mac80211" or hwtype == "prism2" then
                encr:value("psk", "WPA-PSK", {mode="sta"}, {mode="sta-wds"})
                encr:value("psk2", "WPA2-PSK", {mode="sta"}, {mode="sta-wds"})
                encr:value("psk-mixed", "WPA-PSK/WPA2-PSK Mixed Mode", {mode="sta"}, {mode="sta-wds"})
-               encr:value("wpa", "WPA-EAP", {mode="sta"}, {mode="sta-wds"})
-               encr:value("wpa2", "WPA2-EAP", {mode="sta"}, {mode="sta-wds"})
+               if has_sta_eap then
+                       encr:value("wpa", "WPA-EAP", {mode="sta"}, {mode="sta-wds"})
+                       encr:value("wpa2", "WPA2-EAP", {mode="sta"}, {mode="sta-wds"})
+               end
                encr.description = translate(
                        "WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP " ..
                        "and ad-hoc mode) to be installed."
@@ -859,6 +913,12 @@ if hwtype == "atheros" or hwtype == "mac80211" or hwtype == "prism2" then
        cacert:depends({mode="sta-wds", encryption="wpa"})
        cacert:depends({mode="sta-wds", encryption="wpa2"})
 
+       clientcert = s:taboption("encryption", FileUpload, "client_cert", translate("Path to Client-Certificate"))
+       clientcert:depends({mode="sta", encryption="wpa"})
+       clientcert:depends({mode="sta", encryption="wpa2"})
+       clientcert:depends({mode="sta-wds", encryption="wpa"})
+       clientcert:depends({mode="sta-wds", encryption="wpa2"})
+
        privkey = s:taboption("encryption", FileUpload, "priv_key", translate("Path to Private Key"))
        privkey:depends({mode="sta", eap_type="tls", encryption="wpa2"})
        privkey:depends({mode="sta", eap_type="tls", encryption="wpa"})