};
static void
-run_cmd(const char *ifname, const char *device, enum interface_event event)
+run_cmd(const char *ifname, const char *device, enum interface_event event,
+ enum interface_update_flags updated)
{
char *argv[3];
int pid;
setenv("INTERFACE", ifname, 1);
if (device)
setenv("DEVICE", device, 1);
+
+ if (event == IFEV_UPDATE) {
+ if (updated & IUF_ADDRESS)
+ setenv("IFUPDATE_ADDRESSES", "1", 1);
+ if (updated & IUF_ROUTE)
+ setenv("IFUPDATE_ROUTES", "1", 1);
+ if (updated & IUF_PREFIX)
+ setenv("IFUPDATE_PREFIXES", "1", 1);
+ if (updated & IUF_DATA)
+ setenv("IFUPDATE_DATA", "1", 1);
+ }
+
argv[0] = hotplug_cmd_path;
argv[1] = "iface";
argv[2] = NULL;
device = current->l3_dev.dev->ifname;
D(SYSTEM, "Call hotplug handler for interface '%s' (%s)\n", current->name, device ? device : "none");
- run_cmd(current->name, device, current_ev);
+ run_cmd(current->name, device, current_ev, current->updated);
}
static void
iface = ip->iface;
dev = iface->l3_dev.dev;
+ if (!node_new || !node_old)
+ iface->updated |= IUF_ADDRESS;
+
if (node_new) {
a_new = container_of(node_new, struct device_addr, node);
iface = ip->iface;
dev = iface->l3_dev.dev;
+ if (!node_new || !node_old)
+ iface->updated |= IUF_ROUTE;
+
route_old = container_of(node_old, struct device_route, node);
route_new = container_of(node_new, struct device_route, node);
prefix_old = container_of(node_old, struct device_prefix, node);
prefix_new = container_of(node_new, struct device_prefix, node);
+ struct interface_ip_settings *ip = container_of(tree, struct interface_ip_settings, prefix);
+ if (tree && (!node_new || !node_old))
+ ip->iface->updated |= IUF_PREFIX;
+
struct device_route route;
memset(&route, 0, sizeof(route));
route.flags = DEVADDR_INET6;
if (!blobmsg_check_attr(data, true))
return UBUS_STATUS_INVALID_ARGUMENT;
- n = calloc(1, sizeof(*n) + blob_pad_len(data));
- memcpy(n->data, data, blob_pad_len(data));
- n->node.key = blobmsg_name(n->data);
+ const char *name = blobmsg_name(data);
+ unsigned len = blob_pad_len(data);
+
+ o = avl_find_element(&iface->data, name, o, node);
+ if (o) {
+ if (blob_pad_len(o->data) == len && !memcmp(o->data, data, len))
+ return 0;
- o = avl_find_element(&iface->data, n->node.key, o, node);
- if (o)
interface_data_del(iface, o);
+ }
+ n = calloc(1, sizeof(*n) + len);
+ memcpy(n->data, data, len);
+ n->node.key = blobmsg_name(n->data);
avl_insert(&iface->data, &n->node);
+
+ iface->updated |= IUF_DATA;
return 0;
}
void
interface_update_start(struct interface *iface)
{
+ iface->updated = 0;
interface_ip_update_start(&iface->proto_ip);
}
IFC_REMOVE
};
+enum interface_update_flags {
+ IUF_ADDRESS = (1 << 0),
+ IUF_ROUTE = (1 << 1),
+ IUF_PREFIX = (1 << 2),
+ IUF_DATA = (1 << 3),
+};
+
struct interface_error {
struct list_head list;
time_t start_time;
enum interface_state state;
enum interface_config_state config_state;
+ enum interface_update_flags updated;
struct list_head users;
if ((cur = tb[NOTIFY_DNS_SEARCH]))
interface_add_dns_search_list(&iface->proto_ip, cur);
+ if ((cur = tb[NOTIFY_DATA]))
+ proto_shell_parse_data(state->proto.iface, cur);
+
interface_update_complete(state->proto.iface);
if (!keep)
state->proto.proto_event(&state->proto, IFPEV_UP);
state->sm = S_IDLE;
- if ((cur = tb[NOTIFY_DATA]))
- proto_shell_parse_data(state->proto.iface, cur);
-
return 0;
}
blobmsg_add_string(&b, "device", dev->ifname);
if (iface->state == IFS_UP) {
+ if (iface->updated) {
+ a = blobmsg_open_array(&b, "updated");
+
+ if (iface->updated & IUF_ADDRESS)
+ blobmsg_add_string(&b, NULL, "addresses");
+ if (iface->updated & IUF_ROUTE)
+ blobmsg_add_string(&b, NULL, "routes");
+ if (iface->updated & IUF_PREFIX)
+ blobmsg_add_string(&b, NULL, "prefixes");
+ if (iface->updated & IUF_DATA)
+ blobmsg_add_string(&b, NULL, "data");
+
+ blobmsg_close_array(&b, a);
+ }
+
if (iface->ip4table)
blobmsg_add_u32(&b, "ip4table", iface->ip4table);
if (iface->ip6table)