|
|
@@ -0,0 +1,112 @@
|
|
|
+#!/usr/bin/env ucode
|
|
|
+
|
|
|
+import * as libubus from "ubus";
|
|
|
+
|
|
|
+let script_path = ARGV[0];
|
|
|
+let proto_name = ARGV[1];
|
|
|
+let action = ARGV[2];
|
|
|
+let iface_name = ARGV[3];
|
|
|
+let config_json = ARGV[4];
|
|
|
+let device = ARGV[5];
|
|
|
+
|
|
|
+let config;
|
|
|
+try {
|
|
|
+ let blob = json(config_json);
|
|
|
+ let inner = blob?._ucode_config;
|
|
|
+ config = inner ? json(inner) : blob;
|
|
|
+} catch (e) {
|
|
|
+ warn(`Failed to parse config JSON: ${e}\n${e.stacktrace[0].context}\n`);
|
|
|
+ exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+let ubus = libubus.connect();
|
|
|
+if (!ubus) {
|
|
|
+ warn(`Failed to connect to ubus\n`);
|
|
|
+ exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+let notify_path = `network.interface.${iface_name}`;
|
|
|
+
|
|
|
+function proto_notify(data)
|
|
|
+{
|
|
|
+ return ubus.call(notify_path, "notify_proto", data);
|
|
|
+}
|
|
|
+
|
|
|
+let proto = {
|
|
|
+ iface: iface_name,
|
|
|
+ proto: proto_name,
|
|
|
+ config,
|
|
|
+ device,
|
|
|
+
|
|
|
+ notify: proto_notify,
|
|
|
+
|
|
|
+ update_link: function(up, data) {
|
|
|
+ let msg = { action: 0, "link-up": up, ...(data ?? {}) };
|
|
|
+ return proto_notify(msg);
|
|
|
+ },
|
|
|
+
|
|
|
+ run_command: function(argv, env) {
|
|
|
+ let msg = { action: 1, command: argv };
|
|
|
+ if (env)
|
|
|
+ msg.env = env;
|
|
|
+ return proto_notify(msg);
|
|
|
+ },
|
|
|
+
|
|
|
+ kill_command: function(signal) {
|
|
|
+ return proto_notify({ action: 2, signal: signal ?? 15 });
|
|
|
+ },
|
|
|
+
|
|
|
+ error: function(errors) {
|
|
|
+ return proto_notify({ action: 3, error: errors });
|
|
|
+ },
|
|
|
+
|
|
|
+ block_restart: function() {
|
|
|
+ return proto_notify({ action: 4 });
|
|
|
+ },
|
|
|
+
|
|
|
+ set_available: function(available) {
|
|
|
+ return proto_notify({ action: 5, available });
|
|
|
+ },
|
|
|
+
|
|
|
+ add_host_dependency: function(host, ifname) {
|
|
|
+ let msg = { action: 6 };
|
|
|
+ if (host)
|
|
|
+ msg.host = host;
|
|
|
+ if (ifname)
|
|
|
+ msg.ifname = ifname;
|
|
|
+ return proto_notify(msg);
|
|
|
+ },
|
|
|
+
|
|
|
+ setup_failed: function() {
|
|
|
+ return proto_notify({ action: 7 });
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+let handlers = {};
|
|
|
+
|
|
|
+let netifd_stub = {
|
|
|
+ add_proto: function(handler) {
|
|
|
+ if (handler?.name)
|
|
|
+ handlers[handler.name] = handler;
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+try {
|
|
|
+ include(script_path, { netifd: netifd_stub });
|
|
|
+} catch (e) {
|
|
|
+ warn(`Failed to load proto handler script '${script_path}': ${e}\n${e.stacktrace[0].context}\n`);
|
|
|
+ exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+let handler = handlers[proto_name];
|
|
|
+if (!handler) {
|
|
|
+ warn(`No handler found for protocol '${proto_name}'\n`);
|
|
|
+ exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+if (!handler[action]) {
|
|
|
+ warn(`Handler '${proto_name}' has no '${action}' function\n`);
|
|
|
+ exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+handler[action](proto);
|