hostapd: add AFC support
[openwrt/staging/nbd.git] / package / network / services / hostapd / files / afcd.uc
diff --git a/package/network/services/hostapd/files/afcd.uc b/package/network/services/hostapd/files/afcd.uc
new file mode 100644 (file)
index 0000000..9bb7b84
--- /dev/null
@@ -0,0 +1,132 @@
+#!/usr/bin/env ucode
+'use strict';
+import { basename } from "fs";
+let uclient = require("uclient");
+let uloop = require("uloop");
+let libubus = require("ubus");
+let opts = {};
+let reqs = [];
+
+const usage_message = `Usage: ${basename(sourcepath())} <options>
+Options:
+       -u <url>:               AFC server URL (required)
+       -c <path>:              AFC server CA certificate
+
+`;
+
+function usage() {
+    warn(usage_message);
+    exit(1);
+}
+
+while (substr(ARGV[0], 0, 1) == "-") {
+       let opt = substr(shift(ARGV), 1);
+       switch (opt) {
+       case 'u':
+               opts.url = shift(ARGV);
+               break;
+       case 'c':
+               opts.cert = shift(ARGV);
+               if (!opts.cert)
+                       usage();
+               break;
+       default:
+               usage();
+       }
+}
+
+if (!opts.url)
+       usage();
+
+function request_done(cb, error)
+{
+       if (!cb.req)
+               return;
+
+       if (error)
+               delete cb.data;
+
+       cb.req.reply({ data: cb.data }, error);
+
+       delete cb.req;
+       delete cb.client;
+}
+
+const cb_proto = {
+       data_read: function(cb) {
+               let cur;
+               while (length(cur = this.read()) > 0)
+                       cb.data += cur;
+       },
+       data_eof: function(cb) {
+               request_done(cb, 0);
+       },
+       error: function(cb, code) {
+               request_done(cb, libubus.STATUS_UNKNOWN_ERROR);
+       },
+};
+
+function handle_request(req)
+{
+       let cb = proto({ data: "" }, cb_proto);
+
+       let cl = uclient.new(opts.url, null, cb);
+
+       if (!cl.ssl_init({ verify: true, ca_files: [ opts.cert ] })) {
+               warn(`Failed to initialize SSL\n`);
+               return false;
+       }
+
+       if (!cl.connect()) {
+               warn(`Failed to connect\n`);
+               return false;
+       }
+
+       let meta = {
+               headers: {
+                       "Content-Type": "application/json",
+               },
+               post_data: req.args.data
+       };
+
+       if (!cl.request("POST", meta)) {
+               warn(`Failed to send request\n`);
+               return false;
+       }
+
+       cb.client = cl;
+       cb.req = req;
+
+       return true;
+}
+
+function add_ubus(ubus) {
+       return ubus.publish("afc", {
+               request: {
+                       call: function(req) {
+                               if (!req.args.data)
+                                       return libubus.STATUS_INVALID_ARGUMENT;
+
+                               let ret = handle_request(req);
+                               if (!ret)
+                                       return libubus.STATUS_UNKNOWN_ERROR;
+
+                               req.defer();
+                       },
+                       args: {
+                               data: "",
+                       },
+               },
+       });
+}
+
+uloop.init();
+
+let ubus = libubus.connect();
+if (!add_ubus(ubus)) {
+       warn("Failed to publish ubus object\n");
+       exit(1);
+}
+
+uloop.run();
+uloop.done();