• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/netifd/proto-ucode.c

  1 /*
  2  * netifd - network interface daemon
  3  * Copyright (C) 2025 Felix Fietkau <nbd@nbd.name>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License version 2
  7  * as published by the Free Software Foundation
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  */
 14 #include <limits.h>
 15 
 16 #include <ucode/vm.h>
 17 #include <ucode/lib.h>
 18 #include <ucode/types.h>
 19 #include <ucode/program.h>
 20 
 21 #include "netifd.h"
 22 #include "proto.h"
 23 #include "proto-ext.h"
 24 #include "proto-ucode.h"
 25 #include "ucode.h"
 26 
 27 struct proto_ucode_handler {
 28         struct proto_handler proto;
 29         uc_value_t *res;
 30         char *script_name;
 31 };
 32 
 33 static const struct blobmsg_policy proto_ucode_policy = {
 34         .name = "_ucode_config", .type = BLOBMSG_TYPE_STRING,
 35 };
 36 
 37 static const struct uci_blob_param_list proto_ucode_config_params = {
 38         .n_params = 1, .params = &proto_ucode_policy,
 39 };
 40 
 41 static void
 42 proto_ucode_config_load(const struct proto_handler *h,
 43                         struct uci_section *s, struct blob_buf *b)
 44 {
 45         struct proto_ucode_handler *handler;
 46         uc_value_t *netifd_obj, *cb_obj, *fn, *config_cb, *ret;
 47         const char *str;
 48 
 49         handler = container_of(h, struct proto_ucode_handler, proto);
 50 
 51         netifd_obj = uc_vm_registry_get(&vm, "netifd.obj");
 52         if (!netifd_obj)
 53                 return;
 54 
 55         cb_obj = ucv_object_get(netifd_obj, "cb", NULL);
 56         if (ucv_type(cb_obj) != UC_OBJECT)
 57                 return;
 58 
 59         fn = ucv_object_get(cb_obj, "proto_config_load", NULL);
 60         if (!ucv_is_callable(fn))
 61                 return;
 62 
 63         config_cb = ucv_resource_value_get(handler->res, 0);
 64 
 65         uc_vm_stack_push(&vm, ucv_get(fn));
 66         uc_vm_stack_push(&vm, ucv_get(config_cb));
 67         uc_vm_stack_push(&vm, ucv_string_new(s->e.name));
 68 
 69         if (uc_vm_call(&vm, false, 2) != EXCEPTION_NONE) {
 70                 D(INTERFACE, "proto_config_load callback failed for '%s'",
 71                   handler->proto.name);
 72                 return;
 73         }
 74 
 75         ret = uc_vm_stack_pop(&vm);
 76         str = ucv_string_get(ret);
 77         if (str)
 78                 blobmsg_add_string(b, "_ucode_config", str);
 79 
 80         ucv_put(ret);
 81 }
 82 
 83 static int
 84 proto_ucode_start(struct proto_ext_state *state, const char *action,
 85                   const char *config, char **envp)
 86 {
 87         struct proto_ucode_handler *handler;
 88         char helper[PATH_MAX];
 89         const char *argv[9];
 90         int i = 0;
 91 
 92         handler = container_of(state->proto.handler, struct proto_ucode_handler, proto);
 93 
 94         snprintf(helper, sizeof(helper), "%s/proto-ucode.uc", main_path);
 95 
 96         argv[i++] = "ucode";
 97         argv[i++] = helper;
 98         argv[i++] = handler->script_name;
 99         argv[i++] = handler->proto.name;
100         argv[i++] = action;
101         argv[i++] = state->proto.iface->name;
102         argv[i++] = config;
103         if (state->proto.iface->main_dev.dev)
104                 argv[i++] = state->proto.iface->main_dev.dev->ifname;
105         argv[i] = NULL;
106 
107         return netifd_start_process(argv, envp, &state->script_task);
108 }
109 
110 static int
111 proto_ucode_handler(struct interface_proto_state *proto,
112                     enum interface_proto_cmd cmd, bool force)
113 {
114         struct proto_ext_state *state;
115 
116         state = container_of(proto, struct proto_ext_state, proto);
117         return proto_ext_run(state, cmd, force, proto_ucode_start);
118 }
119 
120 static struct interface_proto_state *
121 proto_ucode_attach(const struct proto_handler *h, struct interface *iface,
122                    struct blob_attr *attr)
123 {
124         struct proto_ext_state *state;
125 
126         state = calloc(1, sizeof(*state));
127         if (!state)
128                 return NULL;
129 
130         proto_ext_state_init(state, iface, attr, -1);
131         if (!state->config) {
132                 free(state);
133                 return NULL;
134         }
135 
136         state->proto.cb = proto_ucode_handler;
137 
138         return &state->proto;
139 }
140 
141 static char *
142 proto_ucode_get_script_path(uc_vm_t *vm)
143 {
144         uc_callframe_t *frame;
145         uc_source_t *source;
146 
147         for (size_t i = vm->callframes.count; i > 0; i--) {
148                 frame = &vm->callframes.entries[i - 1];
149 
150                 if (!frame->closure)
151                         continue;
152 
153                 source = uc_program_function_source(frame->closure->function);
154                 if (source && source->runpath)
155                         return source->runpath;
156         }
157 
158         return NULL;
159 }
160 
161 uc_value_t *
162 uc_netifd_add_proto_fn(uc_vm_t *vm, size_t nargs)
163 {
164         uc_value_t *obj = uc_fn_arg(0);
165         uc_value_t *name_val, *config_val, *flag_val, *res;
166         struct proto_ucode_handler *handler;
167         struct proto_handler *proto;
168         const char *name;
169         char *script_path, *proto_name, *script_name;
170 
171         if (ucv_type(obj) != UC_OBJECT)
172                 return NULL;
173 
174         name_val = ucv_object_get(obj, "name", NULL);
175         name = ucv_string_get(name_val);
176         if (!name)
177                 return NULL;
178 
179         script_path = proto_ucode_get_script_path(vm);
180         if (!script_path)
181                 return NULL;
182 
183         res = ucv_resource_create_ex(vm, "netifd.proto_handler",
184                                      (void **)&handler, 1,
185                                      sizeof(*handler) + strlen(name) + 1 +
186                                      strlen(script_path) + 1);
187         if (!res)
188                 return NULL;
189 
190         proto_name = (char *)(handler + 1);
191         script_name = proto_name + strlen(name) + 1;
192 
193         handler->res = res;
194         handler->script_name = strcpy(script_name, script_path);
195 
196         proto = &handler->proto;
197         proto->name = strcpy(proto_name, name);
198         proto->attach = proto_ucode_attach;
199         proto->config_load = proto_ucode_config_load;
200         proto->config_params = &proto_ucode_config_params;
201 
202         config_val = ucv_object_get(obj, "config", NULL);
203         if (ucv_is_callable(config_val)) {
204                 ucv_resource_value_set(res, 0, ucv_get(config_val));
205         }
206 
207         flag_val = ucv_object_get(obj, "no-device", NULL);
208         if (ucv_is_truish(flag_val))
209                 proto->flags |= PROTO_FLAG_NODEV;
210 
211         flag_val = ucv_object_get(obj, "no-device-config", NULL);
212         if (ucv_is_truish(flag_val))
213                 proto->flags |= PROTO_FLAG_NODEV_CONFIG;
214 
215         flag_val = ucv_object_get(obj, "no_proto_task", NULL);
216         if (ucv_is_truish(flag_val))
217                 proto->flags |= PROTO_FLAG_NO_TASK;
218 
219         flag_val = ucv_object_get(obj, "available", NULL);
220         if (ucv_is_truish(flag_val))
221                 proto->flags |= PROTO_FLAG_INIT_AVAILABLE;
222 
223         flag_val = ucv_object_get(obj, "renew-handler", NULL);
224         if (ucv_is_truish(flag_val))
225                 proto->flags |= PROTO_FLAG_RENEW_AVAILABLE;
226 
227         flag_val = ucv_object_get(obj, "lasterror", NULL);
228         if (ucv_is_truish(flag_val))
229                 proto->flags |= PROTO_FLAG_LASTERROR;
230 
231         flag_val = ucv_object_get(obj, "teardown-on-l3-link-down", NULL);
232         if (ucv_is_truish(flag_val))
233                 proto->flags |= PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN;
234 
235         ucv_resource_persistent_set(res, true);
236 
237         D(INTERFACE, "Add ucode handler for script %s: %s",
238           handler->script_name, proto->name);
239         add_proto_handler(proto);
240 
241         return ucv_boolean_new(true);
242 }
243 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt