interface: report link up events for force_link interfaces
[project/netifd.git] / interface.c
index ffe7988..b9833d3 100644 (file)
@@ -75,6 +75,8 @@ const struct uci_blob_param_list interface_attr_list = {
 
 static void
 set_config_state(struct interface *iface, enum interface_config_state s);
+static void
+interface_event(struct interface *iface, enum interface_event ev);
 
 static void
 interface_error_flush(struct interface *iface)
@@ -187,6 +189,9 @@ interface_add_data(struct interface *iface, const struct blob_attr *data)
        }
 
        n = calloc(1, sizeof(*n) + len);
+       if (!n)
+               return UBUS_STATUS_UNKNOWN_ERROR;
+
        memcpy(n->data, data, len);
        n->node.key = blobmsg_name(n->data);
        avl_insert(&iface->data, &n->node);
@@ -195,6 +200,25 @@ interface_add_data(struct interface *iface, const struct blob_attr *data)
        return 0;
 }
 
+int interface_parse_data(struct interface *iface, const struct blob_attr *attr)
+{
+       struct blob_attr *cur;
+       int rem, ret;
+
+       iface->updated = 0;
+
+       blob_for_each_attr(cur, attr, rem) {
+               ret = interface_add_data(iface, cur);
+               if (ret)
+                       return ret;
+       }
+
+       if (iface->updated && iface->state == IFS_UP)
+               interface_event(iface, IFEV_UPDATE);
+
+       return 0;
+}
+
 static void
 interface_event(struct interface *iface, enum interface_event ev)
 {
@@ -236,10 +260,12 @@ mark_interface_down(struct interface *iface)
        if (state == IFS_DOWN)
                return;
 
+       iface->link_up_event = false;
        iface->state = IFS_DOWN;
        if (state == IFS_UP)
                interface_event(iface, IFEV_DOWN);
        interface_ip_set_enabled(&iface->config_ip, false);
+       interface_ip_set_enabled(&iface->proto_ip, false);
        interface_ip_flush(&iface->proto_ip);
        interface_flush_state(iface);
        system_flush_routes();
@@ -330,6 +356,11 @@ interface_set_link_state(struct interface *iface, bool new_state)
        netifd_log_message(L_NOTICE, "Interface '%s' has link connectivity %s\n", iface->name, new_state ? "" : "loss");
        iface->link_state = new_state;
        interface_check_state(iface);
+
+       if (new_state && iface->force_link && iface->state == IFS_UP && !iface->link_up_event) {
+               interface_event(iface, IFEV_LINK_UP);
+               iface->link_up_event = true;
+       }
 }
 
 static void
@@ -525,8 +556,7 @@ interface_alias_cb(struct interface_user *dep, struct interface *iface, enum int
        case IFEV_FREE:
                interface_remove_user(dep);
                break;
-       case IFEV_RELOAD:
-       case IFEV_UPDATE:
+       default:
                break;
        }
 }
@@ -664,6 +694,7 @@ interface_proto_event_cb(struct interface_proto_state *state, enum interface_pro
                        interface_set_l3_dev(iface, iface->main_dev.dev);
 
                interface_ip_set_enabled(&iface->config_ip, true);
+               interface_ip_set_enabled(&iface->proto_ip, true);
                system_flush_routes();
                iface->state = IFS_UP;
                iface->start_time = system_get_rtime();
@@ -873,6 +904,7 @@ interface_set_l3_dev(struct interface *iface, struct device *dev)
                return;
 
        interface_ip_set_enabled(&iface->config_ip, false);
+       interface_ip_set_enabled(&iface->proto_ip, false);
        interface_ip_flush(&iface->proto_ip);
        device_add_user(&iface->l3_dev, dev);
 
@@ -882,6 +914,7 @@ interface_set_l3_dev(struct interface *iface, struct device *dev)
                                return;
                }
                interface_ip_set_enabled(&iface->config_ip, enabled);
+               interface_ip_set_enabled(&iface->proto_ip, enabled);
        }
 }