luci-base: support disconnecting (deauthenticating) wireless clients
authorWang805447391 <805447391@qq.com>
Mon, 12 Nov 2018 07:03:31 +0000 (15:03 +0800)
committerJo-Philipp Wich <jo@mein.io>
Thu, 15 Nov 2018 07:28:45 +0000 (08:28 +0100)
Add a button to each row in the wireless assoclist table to allow
disconnecting clients using the ubus del_client method if the underlying
radio interface supports it.

Ref: https://github.com/openwrt/luci/pull/2271
Submitted-by: Wang805447391 <805447391@qq.com>
[move deauth function to luci-base next to the existing assoclist function,
 require post security, fix parameter check condition, hide button if not
 supported by the radio, disable button after call, squash commits, fix
 whitespace, reword subject, add commit message]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/luasrc/controller/admin/index.lua
modules/luci-base/luasrc/view/wifi_assoclist.htm

index 39004c6760222310833c66642e85b7095b79dba4..1f7db0cb38db474e17d5641a703e57f9747e6487 100644 (file)
@@ -80,6 +80,9 @@ function index()
        if has_wifi then
                page = entry({"admin", "wireless_assoclist"}, call("wifi_assoclist"), nil)
                page.leaf = true
+
+               page = entry({"admin", "wireless_deauth"}, post("wifi_deauth"), nil)
+               page.leaf = true
        end
 
        page = entry({"admin", "translations"}, call("action_translations"), nil)
@@ -144,3 +147,18 @@ function wifi_assoclist()
        luci.http.prepare_content("application/json")
        luci.http.write_json(s.wifi_assoclist())
 end
+
+function wifi_deauth()
+       local iface = luci.http.formvalue("iface")
+       local bssid = luci.http.formvalue("bssid")
+
+       if iface and bssid then
+               luci.util.ubus("hostapd.%s" % iface, "del_client", {
+                       addr = bssid,
+                       deauth = true,
+                       reason = 5,
+                       ban_time = 60000
+               })
+       end
+       luci.http.status(200, "OK")
+end
index 700d998ad8fb309b19071876c6ef6227248d0879..b7147bfb7176350b0c96438b2189e27bc21ec6f2 100644 (file)
@@ -1,4 +1,21 @@
+<%
+       local supports_deauth = {}
+
+       local _, v
+       for _, v in ipairs(luci.util.ubus()) do
+               local iface = v:match("^hostapd%.(.+)$")
+               if iface then
+                       local funcs = luci.util.ubus(v)
+                       if type(funcs) == "table" and funcs.del_client then
+                               supports_deauth[iface] = true
+                       end
+               end
+       end
+%>
+
 <script type="text/javascript">//<![CDATA[
+       var supports_deauth = <%= luci.http.write_json(supports_deauth) %>;
+
        function wifirate(bss, rx) {
                var p = rx ? 'rx_' : 'tx_',
                    s = '%.1f <%:Mbit/s%>, %d<%:MHz%>'
                return s;
        }
 
+       function handleDeauth(ev) {
+               (new XHR()).post('<%=url('admin/wireless_deauth')%>', {
+                       token: '<%=token%>',
+                       iface: ev.target.getAttribute('data-iface'),
+                       bssid: ev.target.getAttribute('data-bssid')
+               }, function() {
+                       ev.target.disabled = true;
+               });
+       }
+
        XHR.poll(5, '<%=url('admin/wireless_assoclist')%>', null,
                function(x, st)
                {
                                                        E('span', wifirate(bss, true)),
                                                        E('br'),
                                                        E('span', wifirate(bss, false))
-                                               ])
+                                               ]),
+                                               supports_deauth[bss.ifname] ? E('input', {
+                                                       type: 'button',
+                                                       class: 'cbi-button cbi-button-remove',
+                                                       value: '<%:Disconnect%>',
+                                                       'data-bssid': bss.bssid,
+                                                       'data-iface': bss.ifname,
+                                                       click: handleDeauth
+                                               }) : '-'
                                        ]);
                                });
 
                <div class="th nowrap"><%:Host%></div>
                <div class="th nowrap"><%:Signal%> / <%:Noise%></div>
                <div class="th nowrap"><%:RX Rate%> / <%:TX Rate%></div>
+               <% if next(supports_deauth) then %>
+                       <div class="th right"><%:Disconnect%></div>
+               <% end %>
        </div>
        <div class="tr placeholder">
                <div class="td"><em><%:Collecting data...%></em></div>