usync-schema: add serveral new schemas and templates

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin
2020-11-12 12:03:26 +01:00
parent bae2180e56
commit cf25613c01
40 changed files with 1198 additions and 123 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.schema

View File

@@ -7,6 +7,9 @@ In order to run the test cases you will need the following tools
* utpl
* usync-jsonschema
* jsonlint-php
* pip3 install jsonschema2md
* pip3 install json-schema-for-humans
* pip3 install python-json2yaml
### Unit testing
```sh

16
cfg_log.tpl Normal file
View File

@@ -0,0 +1,16 @@
{%
function generate_log() {
local log = {};
uci_set_option(log, cfg.log, "log_size");
if (uci_requires(cfg.log, [ "log_proto", "log_ip", "log_port" ])) {
uci_set_options(log, cfg.log, [ "log_proto", "log_ip", "log_port", "log_hostname" ]);
log.log_remote = 1;
}
uci_render("system", { "@system[-1]": log});
}
generate_log();
%}

192
cfg_network.tpl Normal file
View File

@@ -0,0 +1,192 @@
{%
function fw_generate_zone(x, n, masq) {
local u = uci_new_section(x, n, "zone", {"name": n, "network": n});
if (masq) {
u.input = "REJECT";
u.output = "ACCEPT";
u.forward = "REJECT";
u.masq = 1;
u.mtu_fix = 1;
} else {
u.input = "ACCEPT";
u.output = "ACCEPT";
u.forward = "ACCEPT";
}
}
function fw_generate_fwd(x, src, dest) {
local name = sprintf("%s_%s", src, dest);
uci_new_section(x, name, "forwarding", {"src": src, "dest": dest});
}
function fw_generate_guest(x, src, ipaddr) {
local allow = sprintf("%s_allow", src);
local block = sprintf("%s_block", src);
if (ipaddr)
uci_new_section(x, allow, "rule", {"src": src, "family": "ipv4",
"dest_ip": ipaddr,
"proto": "tcp udp", "target": "ACCEPT" });
uci_new_section(x, block, "rule", {"src": src, "family": "ipv4",
"dest_ip": "192.168.0.0/16 172.16.0.0/24 10.0.0.0/24",
"proto": "tcp udp", "target": "REJECT" });
}
function bridge_generate_vlan(x, n, vid) {
local name = sprintf("%s_vlan", n);
local ports = "";
uci_new_section(x, name, "bridge-vlan", {"device": "bridge", "vlan": vid,
"ports": capab.network.wan.ifname + ":t"});
}
function dhcp_generate(x, v, n) {
local u = uci_new_section(x, n, "dhcp", {"interface": n});
if (!v) {
u.ignore = 1;
return;
}
uci_defaults(v, { "start": 100, "limit": 100, "leasetime": "12h" });
uci_set_options(u, v, ["start", "limit", "leasetime"]);
}
function lease_generate(x, v) {
if (!uci_requires(v, [ "hostname", "mac", "ip" ]))
return;
uci_new_section(x, v.hostname, "host", {
"hostname": v.hostname,
"ip": v.ip,
"mac":v.mac
});
}
function network_generate_vlan_rule(x, v, n) {
if (!v.vlan)
return;
local name = sprintf("%s_route", n);
uci_new_section(x, name, "rule", {"in": n, "lookup": v.vlan});
}
function network_generate_name(n, v) {
if (v.name && n in ["guest", "nat"])
n = v.name;
return v.vlan ? sprintf("%s%d", n, v.vlan) : n;
}
function network_generate_static(x, v, n) {
local u = uci_new_section(x, n, "interface", {"proto": "static"});
uci_defaults(v, {"netmask": "255.255.255.0"});
uci_set_options(u, v, ["ipaddr", "netmask", "gateway", "dns"]);
return u;
}
function network_generate_dhcp(x, v, n) {
local u = uci_new_section(x, n, "interface", {"proto": "dhcp"});
return u;
}
function network_generate_base(x, v, n) {
local u;
switch(v.proto) {
case "dhcp":
u = network_generate_dhcp(x.network, v, n);
break;
case "static":
u = network_generate_static(x.network, v, n);
break;
default:
warn("Unhandled network proto\n");
return;
}
uci_set_options(u, v, ["mtu", "ip6assign", "disabled"]);
return u;
}
function network_generate_wan(x, v) {
local name = network_generate_name("wan", v);
local u;
u = network_generate_base(x, v.cfg, name);
if (v.vlan) {
u.ifname = sprintf("bridge.%d", v.vlan);
u.ip4table = v.vlan;
u.ip6table = v.vlan;
bridge_generate_vlan(x.network, name, v.vlan);
fw_generate_zone(x.firewall, name, true);
}
dhcp_generate(x.dhcp, false, name);
}
function network_generate_lan(x, c, n) {
local name = network_generate_name(n, c);
local u;
u = network_generate_base(x, c.cfg, name);
dhcp_generate(x.dhcp, c.cfg.dhcp, name);
for (local k, v in c.cfg.leases)
lease_generate(x.dhcp, v);
network_generate_vlan_rule(x.network, c, name);
return u;
}
function network_generate_nat(x, c, n) {
local name = network_generate_name(n, c);
local wan = network_generate_name("wan", c);
local u;
u = network_generate_lan(x, c, n);
u.type = "bridge";
fw_generate_zone(x.firewall, name);
fw_generate_fwd(x.firewall, name, wan);
}
function network_generate_guest(x, c) {
local name = network_generate_name("guest", c);
network_generate_nat(x, c, "guest");
fw_generate_guest(x.firewall, name, c.cfg.ipaddr);
}
function network_generate() {
local uci = {
"network": {},
"dhcp": {},
"firewall": {}
};
for (local k, v in cfg.network) {
switch (v.mode) {
case "wan":
network_generate_wan(uci, v);
break;
case "nat":
network_generate_nat(uci, v, "nat");
break;
case "lan":
network_generate_lan(uci, v, "lan");
break;
case "guest":
network_generate_guest(uci, v);
break;
}
}
uci_render("network", uci.network);
uci_render("dhcp", uci.dhcp);
uci_render("firewall", uci.firewall);
}
network_generate();
%}

13
cfg_ntp.tpl Normal file
View File

@@ -0,0 +1,13 @@
{%
function generate_ntp() {
local ntp= {};
uci_set_option(ntp, cfg.ntp, "enabled");
uci_set_option(ntp, cfg.ntp, "enable_server");
uci_set_option(ntp, cfg.ntp, "server");
uci_render("system", { "ntp": ntp});
}
generate_ntp();
%}

114
cfg_phy.tpl Normal file
View File

@@ -0,0 +1,114 @@
{%
function ssid_generate(x, v, radio) {
local crypto = "none";
if (!uci_requires(v, [ "network", "ssid", "mode", "encryption"])) {
warn("ssid is missing a required option\n");
return;
}
if (v.encryption in [ "psk", "psk2", "psk-mixed" ]) {
if (!uci_requires(v, [ "key"])) {
warn("ssid has invalid psk options\n");
return;
}
crypto = "psk";
} else if (v.encryption in [ "wpa", "wpa2", "wpa-mixed" ]) {
if (!uci_requires(v, [ "server", "port", "auth_secret" ])) {
warn("ssid has invalid wpa options\n");
return;
}
crypto = "wpa";
}
local name = sprintf("%s_%s", radio, v.network);
local u = uci_new_section(x, name, "wifi-iface", { "device": radio });
uci_set_options(u, v, ["ssid", "network", "mode", "dtim_period", "hidden",
"ieee80211k", "ieee80211k", "ieee80211v", "ieee80211w",
"isolate", "rts_threshold", "uapsd", "ft_over_ds",
"ft_psk_generate_local", "mobility_domain" ]);
switch(crypto) {
case "psk":
uci_set_option(u, v, "key");
break;
case "wpa":
uci_set_options(u, v, [ "server", "port", "auth_secret" ]);
break;
}
}
function phy_htmode_verify(c, v) {
if (index(v, "HE") == 0 && c.he_capa)
return v;
if (index(v, "VHT") == 0 && c.vht_capa)
return v;
if (index(v, "HT") == 0 && c.ht_capa)
return v;
return "HT20";
}
function phy_channel_verify(c, v) {
if (v <= 16 && "2" in c.band)
return v;
if (v >= 32 && v <= 68 && ("5" in c.band || "5l" in c.band))
return v;
if (v >= 96 && v <= 173 && ("5" in c.band || "5u" in c.band))
return v;
return 0;
}
function phy_generate_options(x, c, v) {
local u = uci_new_section(x, c.uci, "wifi-device");
if (v.htmode)
u.htmode = phy_htmode_verify(c, v.htmode);
if (v.channel)
u.channel = phy_channel_verify(c, v.channel);
uci_set_options(u, v, ["disabled", "country", "beacon_int", "txpower",
"chanbw", "require_mode", "txantenna", "rxantenna", "legacy_rates"]);
}
function phy_generate(wifi, x) {
for (local phy in cfg.phy):
if (phy.band in x.band === false)
continue;
phy_generate_options(wifi, x, phy.cfg);
for (local ssid in cfg.ssid):
for (local band in ssid.band):
if (band != phy.band)
continue;
ssid_generate(wifi, ssid.cfg, x.uci);
endfor
endfor
return true;
endfor
return false;
}
function wifi_generate() {
local wifi= {};
if (!capab.wifi)
return;
cursor = uci.cursor();
cursor.load("wireless");
cursor.foreach("wireless", "wifi-device", function(d) {
if (!capab.wifi[d.path])
continue;
capab.wifi[d.path]["uci"] = d[".name"];
});
for (local path in capab.wifi):
local phy = capab.wifi[path];
if (phy_generate(wifi, phy) === false):
wifi[phy.uci] = {"disabled": "1"};
endif
endfor
uci_render("wireless", wifi);
}
wifi_generate();
%}

12
cfg_ssh.tpl Normal file
View File

@@ -0,0 +1,12 @@
{%
function generate_ssh() {
local ssh= {};
uci_set_option(ssh, cfg.ssh, "enable");
uci_set_option(ssh, cfg.ssh, "Port");
uci_render("dropbear", { "@dropbear[-1]": ssh});
}
generate_ssh();
%}

10
cfg_system.tpl Normal file
View File

@@ -0,0 +1,10 @@
{%
function generate_system() {
local system = {};
uci_set_options(system, cfg.system, [ "hostname", "timezone" ]);
uci_render("system", { "@system[-1]": system});
}
generate_system();
%}

8
cmd.tpl Normal file
View File

@@ -0,0 +1,8 @@
{%
try {
if (match(cmd.cmd, /^[A-Za-z0-9_]+$/))
include(sprintf("cmd_%s.tpl", cmd.cmd));
} catch (e) {
warn("Exception while executing: " + cmd + "\n");
}
%}

3
cmd_factory.tpl Normal file
View File

@@ -0,0 +1,3 @@
{%
fs.popen('jffs2reset -r -y', 'r');
%}

4
cmd_reboot.tpl Normal file
View File

@@ -0,0 +1,4 @@
{%
ctx = ubus.connect();
ctx.call("system", "reboot");
%}

19
cmd_sysupgrade.tpl Normal file
View File

@@ -0,0 +1,19 @@
{%
if (!cmd.url) {
warn("usync-upgrade: invalid FW URL\n");
return;
}
path = "/tmp/usync.upgrade";
fs.popen(sprintf('wget %s -O %s', cmd.url, path), 'r').close();
ctx = ubus.connect();
fw = ctx.call("system", "validate_firmware_image", { "path": path });
if (!fw.valid) {
ctx = ubus.connect();
ctx.call("usync", "log", {"error": "firmware file validation failed", "data": fw});
warn("usync-upgrade: firmware file validation failed\n");
return;
}
fs.popen(sprintf('/sbin/sysupgrade %s', path), 'r').close();
%}

175
docs/schema_doc.css Normal file
View File

@@ -0,0 +1,175 @@
body {
font: 16px/1.5em "Overpass", "Open Sans", Helvetica, sans-serif;
color: #333;
font-weight: 300;
padding: 40px;
}
.btn.btn-link {
font-size: 18px;
}
.jsfh-animated-property {
animation: eclair;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-duration: .75s;
}
@keyframes eclair {
0%,100% {
transform: scale(1);
}
50% {
transform: scale(1.03);
}
}
.btn.btn-primary {
margin: 10px;
}
.btn.example-show.collapsed:before {
content: "show"
}
.btn.example-show:before {
content: "hide"
}
.description.collapse:not(.show) {
max-height: 100px !important;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.description.collapsing {
min-height: 100px !important;
}
.collapse-description-link.collapsed:after {
content: '+ Read More';
}
.collapse-description-link:not(.collapsed):after {
content: '- Read Less';
}
.badge {
font-size: 100%;
margin-bottom: 0.5rem;
}
.badge.value-type {
font-size: 120%;
margin-right: 5px;
margin-bottom: 10px;
}
.badge.default-value {
font-size: 120%;
margin-left: 5px;
margin-bottom: 10px;
}
.badge.restriction {
display: inline-block;
}
.badge.required-property,.badge.deprecated-property,.badge.pattern-property,.badge.no-additional {
font-size: 100%;
margin-left: 10px;
}
.accordion div.card:only-child {
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
.examples {
padding: 1rem !important;
}
.highlight.jumbotron {
padding: 1rem !important;
}
.generated-by-footer {
margin-top: 1em;
text-align: right;
}
/* From https://github.com/richleland/pygments-css/blob/master/friendly.css, see https://github.com/trentm/python-markdown2/wiki/fenced-code-blocks */
.highlight { background: #e9ecef; } /* Changed from #f0f0f0 in the original style to be the same as bootstrap's jumbotron */
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #60a0b0; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #40a070 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #40a070 } /* Literal.Number.Bin */
.highlight .mf { color: #40a070 } /* Literal.Number.Float */
.highlight .mh { color: #40a070 } /* Literal.Number.Hex */
.highlight .mi { color: #40a070 } /* Literal.Number.Integer */
.highlight .mo { color: #40a070 } /* Literal.Number.Oct */
.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06287e } /* Name.Function.Magic */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */

1
docs/schema_doc.min.js vendored Normal file
View File

@@ -0,0 +1 @@
function flashElement(t){myElement=document.getElementById(t),myElement.classList.add("jsfh-animated-property"),setTimeout(function(){myElement.classList.remove("jsfh-animated-property")},1e3)}function setAnchor(t){history.pushState({},"",t)}function anchorOnLoad(){let t=window.location.hash.split("?")[0].split("&")[0];"#"===t[0]&&(t=t.substr(1)),t.length>0&&anchorLink(t)}function anchorLink(t){$("#"+t).parents().addBack().filter(".collapse:not(.show), .tab-pane, [role='tab']").each(function(t){if($(this).hasClass("collapse"))$(this).collapse("show");else if($(this).hasClass("tab-pane")){const t=$("a[href='#"+$(this).attr("id")+"']");t&&t.tab("show")}else"tab"===$(this).attr("role")&&$(this).tab("show")}),setTimeout(function(){let e=document.getElementById(t);e&&(e.scrollIntoView({block:"center",behavior:"smooth"}),setTimeout(function(){flashElement(t)},500))},1e3)}$(document).on("click",'a[href^="#"]',function(t){t.preventDefault(),history.pushState({},"",this.href)});

1
docs/usync-schema.html Normal file

File diff suppressed because one or more lines are too long

88
docs/usync-schema.md Normal file
View File

@@ -0,0 +1,88 @@
# JSON Schema
*OpenWrt uSync schema*
## Properties
- **`uuid`** *(integer)*
- **`network`** *(array)*: Network Configuration.
- **Items** *(object)*: This section allows you to configure your networks.
- **`mode`** *(string)*: This defines if the network interface shall be bridged directly with the WAN side or shall be NAT'ed out from LAN. Must be one of: `['wan', 'lan', 'nat', 'guest']`.
- **`vlan`** *(number)*: The VID that shall be assign to packets leaving this network interface. Minimum: `16`. Maximum: `4095`.
- **`name`** *(string)*: This option allows us to override the uci naming for NAT and guest networks.
- **`cfg`** *(object)*
- **`proto`** *(string)*: The configuration that shall be run on the network interface. Must be one of: `['none', 'dhcp', 'static']`.
- **`ipaddr`** *(string)*: The IPv4 address that shall be assigned to the network interface.
- **`netmask`** *(string)*: The IPv4 netmask that shall be assigned to the network interface.
- **`gateway`** *(string)*: The IPv4 gateway that shall be assigned to the network interface.
- **`dns`** *(string)*: The IPv4 DNS server that shall be assigned to the network interface.
- **`mtu`** *(number)*: The MTU that shall be used by the network interface. Minimum: `256`. Maximum: `65535`.
- **`disabled`** *(number)*: This option allows use to disable a network interface. Minimum: `0`. Maximum: `1`.
- **`ip6assign`** *(number)*: The prefix delegation mask that the interface shall use. Minimum: `0`. Maximum: `96`.
- **`dhcp`** *(object)*: The DHCP configuration of the network interface.
- **`start`** *(number)*: This defines which number shall be used as the first leasable IP address. Minimum: `1`. Maximum: `254`.
- **`limit`** *(number)*: This defines how many leasable IP addresses are available. Minimum: `10`.
- **`leasetime`** *(string)*: This defines how many hours the leases should be valid for. (12h, 30m, ...).
- **`leases`** *(array)*: A list of static dhcp leases assigned to the interface.
- **Items** *(object)*
- **`ip`** *(string)*: The IP address used by this static lease.
- **`mac`** *(string)*: The MAC address used by this static lease.
- **`hostname`** *(string)*: The hostname address used by this static lease.
- **`phy`** *(array)*
- **Items** *(object)*
- **`band`** *(string)*: Must be one of: `['2', '5', '5u', '5l', '6']`.
- **`cfg`** *(object)*
- **`beacon_int`** *(number)*: Minimum: `50`. Maximum: `200`.
- **`chanbw`** *(number)*: Must be one of: `[5, 10, 20]`.
- **`channel`** *(number)*: Minimum: `0`. Maximum: `171`.
- **`country`** *(string)*
- **`disabled`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`htmode`** *(string)*: Must be one of: `['NOHT', 'HT20', 'HT40', 'HT40+', 'HT40-', 'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40', 'HE80', 'HE160']`.
- **`hwmode`** *(string)*: Must be one of: `['11a', '11g']`.
- **`legacy_rates`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`require_mode`** *(string)*: Must be one of: `['g', 'n', 'ac', 'ax']`.
- **`rxantenna`** *(number)*: Minimum: `0`. Maximum: `255`.
- **`txantenna`** *(number)*: Minimum: `0`. Maximum: `255`.
- **`txpower`** *(number)*: Minimum: `0`. Maximum: `30`.
- **`ssid`** *(array)*: This is a list of all our SSIDs that shall be configured. Mapping of PHY/SSID is done via the "band" property.
- **Items** *(object)*
- **`band`** *(array)*: The list of wifi bands that the SSID should be broadcasted on. This value can be [ 2, 5, 5l, 5u, 6 ].
- **`cfg`** *(object)*
- **`auth_secret`** *(string)*
- **`bss_transition`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`bssid`** *(string)*
- **`dtim_period`** *(number)*: Minimum: `1`. Maximum: `255`.
- **`encryption`** *(string)*: Must be one of: `['none', 'psk', 'psk2', 'psk-mixed', 'wpa', 'wpa2', 'wpa-mixed']`.
- **`ft_over_ds`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`ft_psk_generate_local`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`hidden`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`ieee80211k`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`ieee80211r`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`ieee80211v`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`ieee80211w`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`isolate`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`key`** *(string)*
- **`mobility_domain`** *(string)*
- **`mode`** *(string)*: Must be one of: `['ap']`.
- **`network`** *(string)*
- **`port`** *(number)*: Minimum: `1024`. Maximum: `65535`.
- **`rts_threshold`** *(number)*: Minimum: `1`. Maximum: `65535`.
- **`server`** *(string)*
- **`ssid`** *(string)*
- **`uapsd`** *(number)*: Minimum: `0`. Maximum: `1`.
- **`system`** *(object)*
- **`hostname`** *(string)*: This allows you to change the hostname of the device.
- **`timezone`** *(string)*: This allows you to change the TZ of the device.
- **`log`** *(object)*
- **`log_ip`** *(string)*: IP address of a syslog server to which the log messages should be sent in addition to the local destination.
- **`log_port`** *(number)*: Port number of the remote syslog server specified with log_ip. Minimum: `100`. Maximum: `65535`.
- **`log_proto`** *(string)*: Sets the protocol to use for the connection, either tcp or udp. Must be one of: `['tcp', 'udp']`.
- **`log_hostname`** *(string)*: Hostname to send to remote syslog. If none is provided, the actual hostname is send.
- **`log_size`** *(number)*: Size of the file based log buffer in KiB. This value is used as the fallback value for log_buffer_size if the latter is not specified. Minimum: `32`.
- **`ntp`** *(object)*
- **`enabled`** *(number)*: Enable this option to tell the unit that it shall get its time from an upstream NTP server. The servers are defined by the <servers> attribute. Minimum: `0`. Maximum: `1`.
- **`enable_server`** *(number)*: Enable this option if you would like the unit to enable a downstream NTP server for its connected clients. Minimum: `0`. Maximum: `1`.
- **`server`** *(array)*: This is an array of URL/IP of the upstream NTP servers that the unit shall use to acquire its current time.
- **`ssh`** *(object)*
- **`enable`** *(number)*: Enable this option if you would like to enable the SSH server on the unit. Minimum: `0`. Maximum: `1`.
- **`Port`** *(number)*: This option defines which port the SSH server shall be available on. Minimum: `1`. Maximum: `65535`.

14
generate.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
sed -i "s/\t/ /g" -i *.yml
yaml2json network.yml network.schema
yaml2json system.yml system.schema
yaml2json log.yml log.schema
yaml2json ntp.yml ntp.schema
yaml2json ssh.yml ssh.schema
yaml2json wifi-phy.yml wifi-phy.schema
yaml2json wifi-ssid.yml wifi-ssid.schema
./merge-schema.py
jsonschema2md usync.schema.json docs/usync-schema.md
generate-schema-doc usync.schema.json docs/usync-schema.html

9
log.cfg Normal file
View File

@@ -0,0 +1,9 @@
{
"log": {
"log_proto": "udp",
"log_ip": "192.168.11.23",
"log_port": 12345,
"log_hostname": "foo",
"log_size": 128
}
}

34
log.yml Normal file
View File

@@ -0,0 +1,34 @@
type: object
properties:
log:
type: object
properties:
log_ip:
description:
IP address of a syslog server to which the log messages should be
sent in addition to the local destination.
type: string
log_port:
description:
Port number of the remote syslog server specified with log_ip.
type: number
maximum: 65535
minimum: 100
log_proto:
description:
Sets the protocol to use for the connection, either tcp or udp.
type: string
enum:
- tcp
- udp
log_hostname:
description:
Hostname to send to remote syslog. If none is provided, the actual
hostname is send.
type: string
log_size:
description:
Size of the file based log buffer in KiB. This value is used as the fallback
value for log_buffer_size if the latter is not specified.
type: number
minimum: 32

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env python
import json
merge = {}
def config_merge(path):
try:
with open(path) as infile:
cfg = json.load(infile)
for k in cfg:
merge[k] = cfg[k]
print(f"merged {path}")
except:
print(f"failed to merge {path}")
def config_write():
try:
with open(f"usync.cfg", 'w') as outfile:
json.dump(merge, outfile, indent=True)
except:
print("failed to write usync.cfg")
config_merge("wifi-phy.cfg")
config_merge("wifi-ssid.cfg")
config_write()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import json
@@ -31,4 +31,8 @@ def schema_write():
schema_merge("network", "network.schema")
schema_merge("phy", "wifi-phy.schema")
schema_merge("ssid", "wifi-ssid.schema")
schema_merge("system", "system.schema")
schema_merge("log", "log.schema")
schema_merge("ntp", "ntp.schema")
schema_merge("ssh", "ssh.schema")
schema_write()

39
network.cfg Normal file
View File

@@ -0,0 +1,39 @@
{
"network": [
{
"mode": "bridge",
"vlan": 200,
"cfg": {
"proto": "dhcp"
}
}, {
"mode": "nat",
"vlan": 200,
"cfg": {
"proto": "static",
"ipaddr": "192.168.100.1",
"netmask": "255.255.255.0",
"gateway": "192.168.100.2",
"dns": "192.168.100.2",
"mtu": 1500,
"ip6assign": 60,
"dhcp": {
"start": 10,
"limit": 100,
"leasetime": "6h"
},
"leases": [
{
"ip": "192.168.100.2",
"mac": "00:11:22:33:44:55",
"hostname": "test"
}, {
"ip": "192.168.100.3",
"mac": "00:11:22:33:44:56",
"hostname": "test2"
}
]
}
}
]
}

View File

@@ -1 +1 @@
{"type": "object", "properties": {"network": {"type": "array", "items": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["bridge", "nat"]}, "cfg": {"type": "object", "required": ["disabled"], "properties": {"proto": {"type": "string", "enum": ["dhcp", "static"]}, "ipaddr": {"type": "string"}, "netmask": {"type": "string"}, "gateway": {"type": "string"}, "dns": {"type": "string"}, "mtu": {"type": "number", "maximum": 65535, "minimum": 256}, "disabled": {"type": "number", "maximum": 1, "minimum": 0}, "ip6assign": {"type": "number", "maximum": 96, "minimum": 0}}}}}}}}
{"type": "object", "properties": {"network": {"description": "Network Configuration", "type": "array", "items": {"description": "This section allows you to configure your networks.", "type": "object", "properties": {"mode": {"description": "This defines if the network interface shall be bridged directly with the WAN side or shall be NAT'ed out from LAN.", "type": "string", "enum": ["wan", "lan", "nat", "guest"]}, "vlan": {"description": "The VID that shall be assign to packets leaving this network interface.", "type": "number", "maximum": 4095, "minimum": 16}, "name": {"description": "This option allows us to override the uci naming for NAT and guest networks.", "type": "string"}, "cfg": {"type": "object", "properties": {"proto": {"description": "The configuration that shall be run on the network interface.", "type": "string", "enum": ["none", "dhcp", "static"]}, "ipaddr": {"description": "The IPv4 address that shall be assigned to the network interface.", "type": "string"}, "netmask": {"description": "The IPv4 netmask that shall be assigned to the network interface.", "type": "string"}, "gateway": {"description": "The IPv4 gateway that shall be assigned to the network interface.", "type": "string"}, "dns": {"description": "The IPv4 DNS server that shall be assigned to the network interface.", "type": "string"}, "mtu": {"description": "The MTU that shall be used by the network interface.", "type": "number", "maximum": 65535, "minimum": 256}, "disabled": {"description": "This option allows use to disable a network interface.", "type": "number", "maximum": 1, "minimum": 0}, "ip6assign": {"description": "The prefix delegation mask that the interface shall use.", "type": "number", "maximum": 96, "minimum": 0}, "dhcp": {"description": "The DHCP configuration of the network interface.", "type": "object", "properties": {"start": {"description": "This defines which number shall be used as the first leasable IP address.", "type": "number", "maximum": 254, "minimum": 1}, "limit": {"description": "This defines how many leasable IP addresses are available.", "type": "number", "minimum": 10}, "leasetime": {"description": "This defines how many hours the leases should be valid for. (12h, 30m, ...)", "type": "string"}}}, "leases": {"description": "A list of static dhcp leases assigned to the interface.", "type": "array", "items": {"type": "object", "properties": {"ip": {"description": "The IP address used by this static lease.", "type": "string"}, "mac": {"description": "The MAC address used by this static lease.", "type": "string"}, "hostname": {"description": "The hostname address used by this static lease.", "type": "string"}}}}}}}}}}}

View File

@@ -1,42 +1,115 @@
type: object
properties:
network:
description:
Network Configuration
type: array
items:
description:
This section allows you to configure your networks.
type: object
properties:
mode:
description:
This defines if the network interface shall be bridged directly with the
WAN side or shall be NAT'ed out from LAN.
type: string
enum:
- 'bridge'
- 'wan'
- 'lan'
- 'nat'
- 'guest'
vlan:
description:
The VID that shall be assign to packets leaving this network interface.
type: number
maximum: 4095
minimum: 16
name:
description:
This option allows us to override the uci naming for NAT and guest networks.
type: string
cfg:
type: object
required:
- disabled
properties:
proto:
description:
The configuration that shall be run on the network interface.
type: string
enum:
- "none"
- "dhcp"
- "static"
ipaddr:
description:
The IPv4 address that shall be assigned to the network interface.
type: string
netmask:
description:
The IPv4 netmask that shall be assigned to the network interface.
type: string
gateway:
description:
The IPv4 gateway that shall be assigned to the network interface.
type: string
dns:
description:
The IPv4 DNS server that shall be assigned to the network interface.
type: string
mtu:
description:
The MTU that shall be used by the network interface.
type: number
maximum: 65535
minimum: 256
disabled:
description:
This option allows use to disable a network interface.
type: number
maximum: 1
minimum: 0
ip6assign:
description:
The prefix delegation mask that the interface shall use.
type: number
maximum: 96
minimum: 0
dhcp:
description:
The DHCP configuration of the network interface.
type: object
properties:
start:
description:
This defines which number shall be used as the first leasable IP address.
type: number
maximum: 254
minimum: 1
limit:
description:
This defines how many leasable IP addresses are available.
type: number
minimum: 10
leasetime:
description:
This defines how many hours the leases should be valid for. (12h, 30m, ...)
type: string
leases:
description:
A list of static dhcp leases assigned to the interface.
type: array
items:
type: object
properties:
ip:
description:
The IP address used by this static lease.
type: string
mac:
description:
The MAC address used by this static lease.
type: string
hostname:
description:
The hostname address used by this static lease.
type: string

11
ntp.cfg Normal file
View File

@@ -0,0 +1,11 @@
{
"ntp": {
"enabled": 1,
"enable_server": 1,
"server": [
"0.openwrt.pool.ntp.org",
"1.openwrt.pool.ntp.org",
"2.openwrt.pool.ntp.org"
]
}
}

1
ntp.schema Normal file
View File

@@ -0,0 +1 @@
{"type": "object", "properties": {"ntp": {"type": "object", "properties": {"enabled": {"description": "Enable this option to tell the unit that it shall get its time from an upstream NTP server. The servers are defined by the <servers> attribute.", "type": "number", "maximum": 1, "minimum": 0}, "enable_server": {"description": "Enable this option if you would like the unit to enable a downstream NTP server for its connected clients.", "type": "number", "maximum": 1, "minimum": 0}, "server": {"description": "This is an array of URL/IP of the upstream NTP servers that the unit shall use to acquire its current time.", "type": "array"}}}}}

24
ntp.yml Normal file
View File

@@ -0,0 +1,24 @@
type: object
properties:
ntp:
type: object
properties:
enabled:
description:
Enable this option to tell the unit that it shall get its time from an upstream NTP
server. The servers are defined by the <servers> attribute.
type: number
maximum: 1
minimum: 0
enable_server:
description:
Enable this option if you would like the unit to enable a downstream NTP server for
its connected clients.
type: number
maximum: 1
minimum: 0
server:
description:
This is an array of URL/IP of the upstream NTP servers that the unit shall use to
acquire its current time.
type: array

6
ssh.cfg Normal file
View File

@@ -0,0 +1,6 @@
{
"ssh": {
"enable": 1,
"Port": 2222
}
}

17
ssh.yml Normal file
View File

@@ -0,0 +1,17 @@
type: object
properties:
ssh:
type: object
properties:
enable:
description:
Enable this option if you would like to enable the SSH server on the unit.
type: number
maximum: 1
minimum: 0
Port:
description:
This option defines which port the SSH server shall be available on.
type: number
maximum: 65535
minimum: 1

6
system.cfg Normal file
View File

@@ -0,0 +1,6 @@
{
"system": {
"hostname": "uSync",
"timezone": "CET-1CEST,M3.5.0,M10.5.0/3"
}
}

13
system.yml Normal file
View File

@@ -0,0 +1,13 @@
type: object
properties:
system:
type: object
properties:
hostname:
description:
This allows you to change the hostname of the device.
type: string
timezone:
description:
This allows you to change the TZ of the device.
type: string

11
unit.sh
View File

@@ -29,12 +29,15 @@ schema_test() {
[ $? -eq 0 ] || error_inc
}
./generate
schema_test network
schema_test wifi-phy
schema_test wifi-ssid
test_inc
utpl -m fs -i wifi.tpl
[ $? -eq 0 ] || error_inc
schema_test ntp
schema_test ssh
schema_test system
schema_test log
echo $error/$test failed

View File

@@ -1,8 +1,57 @@
{
"ssh": {
"enable": 1,
"Port": 2222
},
"ntp": {
"enabled": 1,
"enable_server": 1,
"server": [
"0.openwrt.pool.ntp.org",
"1.openwrt.pool.ntp.org",
"2.openwrt.pool.ntp.org"
]
},
"network": [
{
"mode": "bridge",
"cfg": {
"proto": "dhcp"
}
},
{
"mode": "nat",
"cfg": {
"proto": "static",
"ipaddr": "192.168.100.1",
"netmask": "255.255.255.0",
"gateway": "192.168.100.2",
"dns": "192.168.100.2",
"mtu": 1500,
"ip6assign": 60,
"dhcp": {
"start": 10,
"limit": 100,
"leasetime": "6h"
},
"leases": [
{
"ip": "192.168.100.2",
"mac": "00:11:22:33:44:55",
"hostname": "test"
},
{
"ip": "192.168.100.3",
"mac": "00:11:22:33:44:56",
"hostname": "test2"
}
]
}
}
],
"phy": [
{
"band": "2",
"name": "radio0",
"cfg": {
"disabled": 0,
"country": "DE",
@@ -20,7 +69,6 @@
},
{
"band": "5",
"name": "radio1",
"cfg": {
"disabled": 0,
"country": "DE",
@@ -50,7 +98,6 @@
"key": "12345678",
"server": "192.168.10.10",
"auth_secret": "secret",
"mobility_domain": "abc123",
"port": 2000,
"ft_over_ds": 0,
"ft_psk_generate_local": 0,
@@ -79,7 +126,6 @@
"key": "12345678",
"server": "192.168.10.10",
"auth_secret": "secret",
"mobility_domain": "abc123",
"port": 2000,
"ft_over_ds": 0,
"ft_psk_generate_local": 0,

View File

@@ -8,56 +8,119 @@
"type": "integer"
},
"network": {
"description": "Network Configuration",
"type": "array",
"items": {
"description": "This section allows you to configure your networks.",
"type": "object",
"properties": {
"mode": {
"description": "This defines if the network interface shall be bridged directly with the WAN side or shall be NAT'ed out from LAN.",
"type": "string",
"enum": [
"bridge",
"nat"
"wan",
"lan",
"nat",
"guest"
]
},
"vlan": {
"description": "The VID that shall be assign to packets leaving this network interface.",
"type": "number",
"maximum": 4095,
"minimum": 16
},
"name": {
"description": "This option allows us to override the uci naming for NAT and guest networks.",
"type": "string"
},
"cfg": {
"type": "object",
"required": [
"disabled"
],
"properties": {
"proto": {
"description": "The configuration that shall be run on the network interface.",
"type": "string",
"enum": [
"none",
"dhcp",
"static"
]
},
"ipaddr": {
"description": "The IPv4 address that shall be assigned to the network interface.",
"type": "string"
},
"netmask": {
"description": "The IPv4 netmask that shall be assigned to the network interface.",
"type": "string"
},
"gateway": {
"description": "The IPv4 gateway that shall be assigned to the network interface.",
"type": "string"
},
"dns": {
"description": "The IPv4 DNS server that shall be assigned to the network interface.",
"type": "string"
},
"mtu": {
"description": "The MTU that shall be used by the network interface.",
"type": "number",
"maximum": 65535,
"minimum": 256
},
"disabled": {
"description": "This option allows use to disable a network interface.",
"type": "number",
"maximum": 1,
"minimum": 0
},
"ip6assign": {
"description": "The prefix delegation mask that the interface shall use.",
"type": "number",
"maximum": 96,
"minimum": 0
},
"dhcp": {
"description": "The DHCP configuration of the network interface.",
"type": "object",
"properties": {
"start": {
"description": "This defines which number shall be used as the first leasable IP address.",
"type": "number",
"maximum": 254,
"minimum": 1
},
"limit": {
"description": "This defines how many leasable IP addresses are available.",
"type": "number",
"minimum": 10
},
"leasetime": {
"description": "This defines how many hours the leases should be valid for. (12h, 30m, ...)",
"type": "string"
}
}
},
"leases": {
"description": "A list of static dhcp leases assigned to the interface.",
"type": "array",
"items": {
"type": "object",
"properties": {
"ip": {
"description": "The IP address used by this static lease.",
"type": "string"
},
"mac": {
"description": "The MAC address used by this static lease.",
"type": "string"
},
"hostname": {
"description": "The hostname address used by this static lease.",
"type": "string"
}
}
}
}
}
}
@@ -173,18 +236,15 @@
}
},
"ssid": {
"description": "This is a list of all our SSIDs that shall be configured. Mapping of PHY/SSID is done via the \"band\" property.",
"type": "array",
"items": {
"type": "object",
"properties": {
"band": {
"description": "The list of wifi bands that the SSID should be broadcasted on. This value can be [ 2, 5, 5l, 5u, 6 ].",
"type": "array"
},
"name": {
"maxLength": 16,
"minLength": 1,
"type": "string"
},
"cfg": {
"type": "object",
"properties": {
@@ -302,6 +362,89 @@
}
}
}
},
"system": {
"type": "object",
"properties": {
"hostname": {
"description": "This allows you to change the hostname of the device.",
"type": "string"
},
"timezone": {
"description": "This allows you to change the TZ of the device.",
"type": "string"
}
}
},
"log": {
"type": "object",
"properties": {
"log_ip": {
"description": "IP address of a syslog server to which the log messages should be sent in addition to the local destination.",
"type": "string"
},
"log_port": {
"description": "Port number of the remote syslog server specified with log_ip.",
"type": "number",
"maximum": 65535,
"minimum": 100
},
"log_proto": {
"description": "Sets the protocol to use for the connection, either tcp or udp.",
"type": "string",
"enum": [
"tcp",
"udp"
]
},
"log_hostname": {
"description": "Hostname to send to remote syslog. If none is provided, the actual hostname is send.",
"type": "string"
},
"log_size": {
"description": "Size of the file based log buffer in KiB. This value is used as the fallback value for log_buffer_size if the latter is not specified.",
"type": "number",
"minimum": 32
}
}
},
"ntp": {
"type": "object",
"properties": {
"enabled": {
"description": "Enable this option to tell the unit that it shall get its time from an upstream NTP server. The servers are defined by the <servers> attribute.",
"type": "number",
"maximum": 1,
"minimum": 0
},
"enable_server": {
"description": "Enable this option if you would like the unit to enable a downstream NTP server for its connected clients.",
"type": "number",
"maximum": 1,
"minimum": 0
},
"server": {
"description": "This is an array of URL/IP of the upstream NTP servers that the unit shall use to acquire its current time.",
"type": "array"
}
}
},
"ssh": {
"type": "object",
"properties": {
"enable": {
"description": "Enable this option if you would like to enable the SSH server on the unit.",
"type": "number",
"maximum": 1,
"minimum": 0
},
"Port": {
"description": "This option defines which port the SSH server shall be available on.",
"type": "number",
"maximum": 65535,
"minimum": 1
}
}
}
}
}

View File

@@ -1,5 +1,18 @@
{%
function render_uci(file, obj) {
function uci_defaults(o, d) {
for (local k, v in d)
if (!o[k])
o[k] = v;
}
function uci_requires(o, d) {
for (local k, v in d)
if (!o[v])
return false;
return true;
}
function uci_render(file, obj) {
for (local sname in obj):
local section = obj[sname];
@@ -10,10 +23,60 @@ function render_uci(file, obj) {
if (oname == ".type")
continue;
local option = section[oname];
if (type(option) == "array"):
-%}del {{file}}.{{ sname }}.{{ oname }}
{%
for (local k, v in option):
-%}add_list {{file}}.{{ sname }}.{{ oname }}='{{ v }}'
{%
endfor
else
-%}set {{file}}.{{ sname }}.{{ oname }}='{{ option }}'
{% endfor
{%
endif
endfor
endfor
}
include("wifi.tpl")
function uci_new_section(x, name, type, vals) {
x[name] = { ".type": type };
if (vals)
for(local k,v in vals)
x[name][k] = v;
return x[name];
}
function uci_set_option(obj, cfg, key) {
if (exists(cfg, key))
obj[key] = cfg[key];
}
function uci_set_options(obj, cfg, key) {
for (local k, v in key)
uci_set_option(obj, cfg, v);
}
fails = {};
failed = false;
for (key in cfg) {
if (key in ["uuid", "ssid"])
continue;
try {
include(sprintf("cfg_%s.tpl", key));
} catch (e) {
failed = true;
fails[key] = e;
warn("Exception while generating " + key + ": " + e + "\n");
}
}
if (failed) {
ctx = ubus.connect();
ctx.call("usync", "log", {"error": "failed to apply config", "data": fails});
exit(1);
}
%}

View File

@@ -2,7 +2,6 @@
"phy": [
{
"band": "2",
"name": "radio0",
"cfg": {
"disabled": 0,
"country": "DE",
@@ -19,7 +18,6 @@
}
}, {
"band": "5",
"name": "radio1",
"cfg": {
"disabled": 0,
"country": "DE",

View File

@@ -9,7 +9,6 @@
"key": "12345678",
"server": "192.168.10.10",
"auth_secret": "secret",
"mobility_domain": "abc123",
"port": 2000,
"ft_over_ds": 0,
"ft_psk_generate_local": 0,
@@ -35,7 +34,6 @@
"key": "12345678",
"server": "192.168.10.10",
"auth_secret": "secret",
"mobility_domain": "abc123",
"port": 2000,
"ft_over_ds": 0,
"ft_psk_generate_local": 0,

View File

@@ -1 +1 @@
{"type": "object", "properties": {"ssid": {"type": "array", "items": {"type": "object", "properties": {"band": {"type": "array"}, "name": {"maxLength": 16, "minLength": 1, "type": "string"}, "cfg": {"type": "object", "properties": {"auth_secret": {"type": "string"}, "bss_transition": {"maximum": 1, "minimum": 0, "type": "number"}, "bssid": {"maxLength": 17, "minLength": 17, "type": "string"}, "dtim_period": {"maximum": 255, "minimum": 1, "type": "number"}, "encryption": {"enum": ["none", "psk", "psk2", "psk-mixed", "wpa", "wpa2", "wpa-mixed"], "type": "string"}, "ft_over_ds": {"maximum": 1, "minimum": 0, "type": "number"}, "ft_psk_generate_local": {"maximum": 1, "minimum": 0, "type": "number"}, "hidden": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211k": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211r": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211v": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211w": {"maximum": 1, "minimum": 0, "type": "number"}, "isolate": {"maximum": 1, "minimum": 0, "type": "number"}, "key": {"maxLength": 63, "minLength": 8, "type": "string"}, "mobility_domain": {"type": "string"}, "mode": {"enum": ["ap"], "type": "string"}, "network": {"type": "string"}, "port": {"maximum": 65535, "minimum": 1024, "type": "number"}, "rts_threshold": {"maximum": 65535, "minimum": 1, "type": "number"}, "server": {"type": "string"}, "ssid": {"maxLength": 32, "minLength": 1, "type": "string"}, "uapsd": {"maximum": 1, "minimum": 0, "type": "number"}}}}}}}}
{"type": "object", "properties": {"ssid": {"description": "This is a list of all our SSIDs that shall be configured. Mapping of PHY/SSID is done via the \"band\" property.", "type": "array", "items": {"type": "object", "properties": {"band": {"description": "The list of wifi bands that the SSID should be broadcasted on. This value can be [ 2, 5, 5l, 5u, 6 ].", "type": "array"}, "cfg": {"type": "object", "properties": {"auth_secret": {"type": "string"}, "bss_transition": {"maximum": 1, "minimum": 0, "type": "number"}, "bssid": {"maxLength": 17, "minLength": 17, "type": "string"}, "dtim_period": {"maximum": 255, "minimum": 1, "type": "number"}, "encryption": {"enum": ["none", "psk", "psk2", "psk-mixed", "wpa", "wpa2", "wpa-mixed"], "type": "string"}, "ft_over_ds": {"maximum": 1, "minimum": 0, "type": "number"}, "ft_psk_generate_local": {"maximum": 1, "minimum": 0, "type": "number"}, "hidden": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211k": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211r": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211v": {"maximum": 1, "minimum": 0, "type": "number"}, "ieee80211w": {"maximum": 1, "minimum": 0, "type": "number"}, "isolate": {"maximum": 1, "minimum": 0, "type": "number"}, "key": {"maxLength": 63, "minLength": 8, "type": "string"}, "mobility_domain": {"type": "string"}, "mode": {"enum": ["ap"], "type": "string"}, "network": {"type": "string"}, "port": {"maximum": 65535, "minimum": 1024, "type": "number"}, "rts_threshold": {"maximum": 65535, "minimum": 1, "type": "number"}, "server": {"type": "string"}, "ssid": {"maxLength": 32, "minLength": 1, "type": "string"}, "uapsd": {"maximum": 1, "minimum": 0, "type": "number"}}}}}}}}

View File

@@ -1,16 +1,17 @@
type: object
properties:
ssid:
description:
This is a list of all our SSIDs that shall be configured. Mapping of PHY/SSID is done via the
"band" property.
type: array
items:
type: object
properties:
band:
description:
The list of wifi bands that the SSID should be broadcasted on. This value can be [ 2, 5, 5l, 5u, 6 ].
type: array
name:
maxLength: 16
minLength: 1
type: string
cfg:
type: object
properties:

View File

@@ -1,62 +0,0 @@
{%
function generate_ssid(wifi, radio, ssid, name) {
local name = radio + "_" + ssid.name;
wifi[name] = {".type": "wifi-iface", "device": radio };
for (local key in ssid.cfg):
local val = ssid.cfg[key];
wifi[name][key] = val;
endfor
}
function generate_phy(wifi, x) {
for (local phy in cfg.phy):
if (phy.band in x.band === false)
continue;
wifi[x.uci] = {};
for (local key in phy.cfg):
local val = phy.cfg[key];
wifi[x.uci][key] = val;
endfor
for (local ssid in cfg.ssid):
for (local band in ssid.band):
if (band != phy.band)
continue;
generate_ssid(wifi, x.uci, ssid);
endfor
endfor
return true;
endfor
return false;
}
function generate_wifi() {
local wifi= {};
if (!capab.wifi)
return;
cursor = uci.cursor();
cursor.load("wireless");
cursor.foreach("wireless", "wifi-device", function(d) {
if (!capab.wifi[d.path])
continue;
capab.wifi[d.path]["uci"] = d[".name"];
});
for (local path in capab.wifi):
local phy = capab.wifi[path];
if (generate_phy(wifi, phy) === false):
wifi[phy.uci] = {"disabled": "1"};
endif
endfor
render_uci("wireless", wifi);
}
generate_wifi();
%}