2 local ubus = require "ubus"
3 local sys = require "luci.sys"
4 local utl = require "luci.util"
6 function connect_ubus(methods)
8 local conn = ubus.connect()
11 error("Failed to connect to ubusd")
14 result = conn:call("otbr", methods, {})
19 function threadget(action)
20 local result = connect_ubus(action)
25 local state = threadget("state").State
33 local addrlist = connect_ubus("macfilteraddr").addrlist
35 for k, v in pairs(addrlist) do
46 <h2><%:Thread Network: %><%=threadget("networkname").NetworkName%><%: (wpan0)%></h2>
47 <div> The Network Configuration section covers physical settings of the Thread Network such as channel, PAN ID. Per interface related settings like masterkey or MAC-filter are grouped in the Interface Configuration.</div>
50 <form class="inline" action="<%=url('admin/network/thread_handler_setting')%>" method="post" id="settingForm" name="settingForm" onsubmit="return validateForm()">
51 <h3><%:Network Configuration%></h3>
53 <ul class="cbi-tabmenu">
54 <li class="cbi-tab" id="generaltab"><a href="javascript:generalSetting();"><%:General Setup%></a></li>
55 <li class="cbi-tab-disabled" id="advancedtab"><a href="javascript:advancedSetting();"><%:Advanced Settings%></a></li>
58 <input type="hidden" name="submitcontent" id="submitcontent" />
59 <input type="hidden" name="removeAddrIndex" id="removeAddrIndex" />
60 <input type="hidden" name="token" value="<%=token%>" />
61 <!-- General Setup -->
62 <div style="width:80%;margin-left:10%;" id="generaldiv">
63 <div class="cbi-value">
64 <label class="cbi-value-title" style="margin-right:5%;">Thread Name</label>
65 <div class="cbi-value-title">
66 <input type="text" name="threadname" value="<%=threadget("networkname").NetworkName%>" style="width:30%;"/>
69 <div class="cbi-value">
70 <label class="cbi-value-title" style="margin-right:5%;">Status</label>
71 <div class="cbi-value-title">
72 <span class="ifacebadge large" style="padding:2%;">
74 <strong>PAN ID: </strong>
75 <%=threadget("panid").PanId%>
77 <strong>Extended PAN ID: </strong>
78 <%=threadget("extpanid").ExtPanId%>
80 <strong>State: </strong>
83 <strong>Channel: </strong>
84 <%=threadget("channel").Channel%>
89 <div class="cbi-value">
90 <% if state == "disabled" then %>
91 <label class="cbi-value-title" style="margin-right:5%;">Thread network is disabled</label>
92 <div class="cbi-value-field">
93 <input class="cbi-button cbi-button-add" type="submit" id="enable" name="enable" value="Enable" />
96 <label class="cbi-value-title" style="margin-right:5%;">Thread network is enabled</label>
97 <div class="cbi-value-field">
98 <input class="cbi-button cbi-button-reset" type="submit" id="disable" name="disable" value="Disable" />
102 <div class="cbi-value">
103 <label class="cbi-value-title" style="margin-right:5%;">Protocol</label>
104 <div class="cbi-value-field">
105 <select style="width:30%;" id="protocol" name="protocol">
106 <option value>unmanaged</option>
112 <!-- Advanced Settings -->
113 <div style="width:70%;margin-left:10%;display:none;" id="advanceddiv">
114 <div class="cbi-value">
115 <label class="cbi-value-title" style="margin-right:5%;">Channel</label>
116 <div class="cbi-value-title">
117 <input type="text" name="channel" value="<%=threadget("channel").Channel%>" style="width:50%;"/>
120 <div class="cbi-value">
121 <label class="cbi-value-title" style="margin-right:5%;">PAN ID</label>
122 <div class="cbi-value-title">
123 <input type="text" name="panid" value="<%=threadget("panid").PanId%>" style="width:50%;"/>
126 <div class="cbi-value">
127 <label class="cbi-value-title" style="margin-right:5%;">Extended PAN ID</label>
128 <div class="cbi-value-title">
129 <input type="text" name="extpanid" value="<%=threadget("extpanid").ExtPanId%>" style="width:50%;"/>
132 <div class="cbi-value">
133 <% if state == 'disabled' then %>
134 <label class="cbi-value-title" style="margin-right:5%;">Mode</label>
135 <div class="cbi-value-title">
136 <input type="text" name="mode" value="<%=threadget("mode").Mode%>" style="width:50%;"/>
138 <div style="margin-left:30%;margin-top:1%;">
139 <span><img src="<%=resource .. "/cbi/help.gif"%>"/><%:set the thread device mode value, must be consist of 'r', 's', 'd', 'n'.%></span>
142 <label class="cbi-value-title" style="margin-right:5%;">Mode</label>
143 <div class="cbi-value-title">
144 <input type="text" name="mode" value="<%=threadget("mode").Mode%>" readonly="readonly" style="width:50%;"/>
146 <div style="margin-left:30%;margin-top:1%;">
147 <span><img src="<%=resource .. "/cbi/help.gif"%>"/><%:can not change mode when thread network is started.%></span>
151 <div class="cbi-value" style="display:none">
152 <label class="cbi-value-title" style="margin-right:5%;">State</label>
153 <div class="cbi-value-field">
154 <select style="width:30%;" id="state" name="state" value="<%=state%>">
155 <option value="disabled">disabled</option>
156 <option value="leader">leader</option>
157 <option value="router">router</option>
158 <option value="child">child</option>
162 <div class="cbi-value">
163 <label class="cbi-value-title" style="margin-right:5%;">PartitionId</label>
164 <div class="cbi-value-title">
165 <%=threadget("partitionid").Partitionid%>
167 <div style="margin-left:30%;margin-top:1%;">
168 <span><img src="<%=resource .. "/cbi/help.gif"%>"/><%:can not change partitionid when thread network is started.%></span>
171 <div class="cbi-value">
172 <label class="cbi-value-title" style="margin-right:5%;">Leave</label>
173 <div class="cbi-value-field">
174 <input class="cbi-button cbi-button-reset" type="submit" id="leave" name="leave" value="LEAVE" />
176 <div style="margin-left:30%;margin-top:1%;">
177 <span><img src="<%=resource .. "/cbi/help.gif"%>"/><%:This will delete all the existed Configuration of your thread network!%></span>
182 <h3><%:Interface Configuration%></h3>
184 <ul class="cbi-tabmenu">
185 <li class="cbi-tab" id="securitytab"><a href="javascript:securitySetting();"><%:Thread Security%></a></li>
186 <li class="cbi-tab-disabled" id="macfiltertab"><a href="javascript:macfilterSetting();"><%:MAC-Filter%></a></li>
190 <!-- Thread Security -->
191 <div style="width:60%;margin-left:10%;" id="securitydiv">
192 <div class="cbi-value">
193 <label class="cbi-value-title" style="margin-right:5%;">Master Key</label>
194 <div class="cbi-value-title">
195 <input type="text" name="masterkey" value="<%=threadget("masterkey").Masterkey%>" style="width:60%;"/>
198 <div class="cbi-value">
199 <label class="cbi-value-title" style="margin-right:5%;">Network Password</label>
200 <div class="cbi-value-title">
201 <input type="text" name="pskc" value="<%=threadget("pskc").pskc%>" style="width:60%;"/>
207 <div style="width:60%;margin-left:10%;display:none;" id="macfilterdiv">
208 <div class="cbi-value">
209 <label class="cbi-value-title" style="margin-right:1%;">Protocol</label>
210 <div class="cbi-value-field">
211 <select style="width:30%;" id="macfilterselect" name="macfilterselect" onchange='macselectchange()' autocomplete="off">
212 <option value="disable">Disable</option>
213 <option value="allowlist">Allowlist</option>
214 <option value="denylist">Denylist</option>
218 <div class="cbi-value" id="macfilterlistdiv" style="display:none;">
220 <label class="cbi-value-title" style="margin-right:1%;">Existed Address</label>
221 <div class="cbi-value-field">
223 <% for i, addr in ipairs(addrlist()) do %>
224 <input type="hidden" id="macfilterremove" name="macfilterremove" value="<%=addr%>" />
227 <div class="center" style="margin-top:15px;"><%=addr%></div>
228 <div class="th cbi-section-actions">
229 <input class="cbi-button cbi-button-reset" type="submit" id="removeAddr<%=i%>" name="removeAddr<%=i%>" value="<%:Remove%>" />
233 <div class="tr cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
234 <div class="td col-2 center"><%=addr%></div>
235 <div class="td cbi-section-actions">
236 <input class="cbi-button cbi-button-reset" type="submit" id="removeAddr<%=i%>" name="removeAddr<%=i%>" value="<%:Remove%>" />
245 <div class="cbi-value">
246 <div class="cbi-value-field">
247 <input class="cbi-button cbi-button-reset" type="submit" id="clearAddr" name="clearAddr" value="<%:Clear%>" />
248 <span style="margin-left:3%"><img src="<%=resource .. "/cbi/help.gif"%>" style="margin-right:2%"/><%:This will clear all existed macfilter address!%></span>
252 <label class="cbi-value-title" style="margin-right:1%;">Add Address</label>
253 <div class="cbi-value-field">
255 <div class="tr table-titles">
256 <label><input type="text" id="macfilteradd" name="macfilteradd"/></label>
257 <input class="cbi-button cbi-button-add" type="submit" id="addAddr" name="addAddr" value="<%:Add%>" />
264 <div class="cbi-page-actions right">
265 <input class="cbi-button cbi-button-neutral" style="float:left;" type="button" onclick="window.location.href='thread'" value="<%:Back to Overview%>" />
266 <input class="cbi-button cbi-button-apply" type="submit" id="save" value="<%:Save & Apply%>" />
267 <input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" />
274 <script type="text/javascript" src="/luci-static/resources/handle_error.js"></script>
275 <script type="text/javascript">//<![CDATA[
276 handle_error(GetURLParameter('error'));
278 var macfilterstate = "<%=threadget("macfilterstate").state%>";
279 var macselect = document.querySelector('#macfilterselect');
282 macselect.value = macfilterstate;
283 var opt = macselect.options[macselect.selectedIndex];
285 if(opt.value == "disable")
287 document.getElementById('macfilterlistdiv').style.display = "none";
291 document.getElementById('macfilterlistdiv').style.display = "block";
295 function macselectchange()
297 var macselect = document.querySelector('#macfilterselect');
300 var opt = macselect.options[macselect.selectedIndex];
301 if(opt.value == "disable")
303 document.getElementById('macfilterlistdiv').style.display = "none";
307 document.getElementById('macfilterlistdiv').style.display = "block";
312 function generalSetting() {
313 document.getElementById('generaldiv').style.display = "block";
314 document.getElementById('advanceddiv').style.display = "none";
315 document.getElementById('generaltab').className = "cbi-tab";
316 document.getElementById('advancedtab').className = "cbi-tab-disabled";
319 function advancedSetting() {
320 document.getElementById('generaldiv').style.display = "none";
321 document.getElementById('advanceddiv').style.display = "block";
322 document.getElementById('generaltab').className = "cbi-tab-disabled";
323 document.getElementById('advancedtab').className = "cbi-tab";
326 function securitySetting() {
327 document.getElementById('securitydiv').style.display = "block";
328 document.getElementById('macfilterdiv').style.display = "none";
329 document.getElementById('securitytab').className = "cbi-tab";
330 document.getElementById('macfiltertab').className = "cbi-tab-disabled";
333 function macfilterSetting() {
334 document.getElementById('securitydiv').style.display = "none";
335 document.getElementById('macfilterdiv').style.display = "block";
336 document.getElementById('securitytab').className = "cbi-tab-disabled";
337 document.getElementById('macfiltertab').className = "cbi-tab";
340 document.getElementById('settingForm').addEventListener('submit', function() {
341 var length = document.activeElement.id.length;
342 document.getElementById('submitcontent').value = document.activeElement.id.substring(0, 10);
343 document.getElementById('removeAddrIndex').value = document.activeElement.id.substring(10, length);
346 function validateForm()
348 var activeElement = document.activeElement.id;
349 if(activeElement == "addAddr")
351 var addr = document.forms["settingForm"]["macfilteradd"].value;
352 if(addr.length != 16)
354 alert("Address length must be 16 bytes");
358 else if(activeElement.substring(0, 10) != "removeAddr")
360 var panid = document.forms["settingForm"]["panid"].value;
362 alert("panid must be a number");
366 var extpanid = document.forms["settingForm"]["extpanid"].value;
367 var re = /^[0-9a-f]+$/;
368 var OK = re.exec(extpanid);
370 alert("extpanid must be a number");
373 if (extpanid.length != 16) {
374 alert("extpanid length must be 16 bytes");
378 var mode = document.forms["settingForm"]["mode"].value;
379 var re = /^[rsdn]+$/;
380 var OK = re.exec(mode);
382 alert("mode must be consist of 'r', 's', 'd', 'n'");
386 var masterkey = document.forms["settingForm"]["masterkey"].value;
387 if (masterkey.length != 32) {
388 alert("Masterkey length must be 32 bytes");
392 var pskc = document.forms["settingForm"]["pskc"].value;
393 if (pskc.length != 32) {
394 alert("Network password length must be 32 bytes");