return true;
}
-void
-config_init_interfaces(const char *name)
+struct blob_attr *
+config_memdup(struct blob_attr *attr)
{
- struct uci_context *ctx;
+ struct blob_attr *ret;
+ int size = blob_pad_len(attr);
+
+ ret = malloc(size);
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, attr, size);
+ return ret;
+}
+
+static struct uci_package *
+config_init_package(const char *config)
+{
+ struct uci_context *ctx = uci_ctx;
struct uci_package *p = NULL;
- struct uci_element *e;
- ctx = uci_alloc_context();
- uci_ctx = ctx;
+ if (!ctx) {
+ ctx = uci_alloc_context();
+ uci_ctx = ctx;
#ifdef DUMMY_MODE
- uci_set_confdir(ctx, "./config");
- uci_set_savedir(ctx, "./tmp");
+ uci_set_confdir(ctx, "./config");
+ uci_set_savedir(ctx, "./tmp");
#endif
+ } else {
+ p = uci_lookup_package(ctx, config);
+ if (p)
+ uci_unload(ctx, p);
+ }
+
+ if (uci_load(ctx, "network", &p))
+ return NULL;
+
+ return p;
+}
+
+void
+config_init_interfaces(const char *name)
+{
+ struct uci_context *ctx;
+ struct uci_package *p = NULL;
+ struct uci_element *e;
- if (uci_load(ctx, "network", &p)) {
+ p = config_init_package("network");
+ ctx = uci_ctx;
+ if (!p) {
fprintf(stderr, "Failed to load network config\n");
return;
}
__device_free_unused(dev);
}
+enum dev_change_type
+device_reload_config(struct device *dev, struct blob_attr *attr)
+{
+ struct blob_attr *tb[__DEV_ATTR_MAX], *tb1[__DEV_ATTR_MAX];
+
+ blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb,
+ blob_data(attr), blob_len(attr));
+ blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb1,
+ blob_data(dev->config), blob_len(dev->config));
+
+ if (!config_diff(tb, tb1, &device_attr_list, NULL))
+ return DEV_CONFIG_NO_CHANGE;
+
+ device_init_settings(dev, tb);
+ return DEV_CONFIG_APPLIED;
+}
+
+static enum dev_change_type
+device_check_config(struct device *dev, struct blob_attr *attr)
+{
+ if (dev->type->reload)
+ return dev->type->reload(dev, attr);
+
+ return device_reload_config(dev, attr);
+}
+
+static void
+device_replace(struct device *dev, struct device *odev)
+{
+ struct device_user *dep, *tmp;
+ bool present = odev->present;
+
+ if (present)
+ device_set_present(odev, false);
+
+ list_for_each_entry_safe(dep, tmp, &odev->users, list) {
+ list_move_tail(&dep->list, &dev->users);
+ dep->dev = dev;
+ }
+ device_free(odev);
+
+ if (present)
+ device_set_present(dev, true);
+}
+
struct device *
device_create(const char *name, const struct device_type *type,
struct blob_attr *config)
{
- struct device *dev;
+ struct device *odev = NULL, *dev;
+ enum dev_change_type change;
+
+ odev = device_get(name, false);
+ if (odev) {
+ change = device_check_config(odev, config);
+ switch (change) {
+ case DEV_CONFIG_APPLIED:
+ free(odev->config);
+ odev->config = config_memdup(config);
+ if (odev->present) {
+ device_set_present(odev, false);
+ device_set_present(odev, true);
+ }
+ /* fall through */
+ case DEV_CONFIG_NO_CHANGE:
+ return odev;
+ case DEV_CONFIG_RECREATE:
+ break;
+ }
+ }
- dev = device_get(name, false);
- if (dev)
- return dev;
+ dev = type->create(config);
+ dev->config = config_memdup(config);
+ if (odev)
+ device_replace(dev, odev);
- return type->create(config);
+ return dev;
}
__DEV_ATTR_MAX,
};
+enum dev_change_type {
+ DEV_CONFIG_NO_CHANGE,
+ DEV_CONFIG_APPLIED,
+ DEV_CONFIG_RECREATE,
+};
+
struct device_type {
struct list_head list;
const char *name;
const struct config_param_list *config_params;
struct device *(*create)(struct blob_attr *attr);
+ enum dev_change_type (*reload)(struct device *, struct blob_attr *);
void (*dump_status)(struct device *, struct blob_buf *buf);
int (*check_state)(struct device *);
void (*free)(struct device *);
char ifname[IFNAMSIZ + 1];
int ifindex;
+ struct blob_attr *config;
bool present;
int active;
unsigned int mtu;
unsigned int txqueuelen;
uint8_t macaddr[6];
-
- uint32_t config_hash;
};
/* events broadcasted to all users of a device */