#include "netifd.h"
#include "system.h"
#include "config.h"
+#include "wireless.h"
static struct list_head devtypes = LIST_HEAD_INIT(devtypes);
static struct avl_tree devices;
[DEV_ATTR_SENDREDIRECTS] = { .name = "sendredirects", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_NEIGHLOCKTIME] = { .name = "neighlocktime", .type = BLOBMSG_TYPE_INT32 },
[DEV_ATTR_ISOLATE] = { .name = "isolate", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_DROP_V4_UNICAST_IN_L2_MULTICAST] = { .name = "drop_v4_unicast_in_l2_multicast", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_DROP_V6_UNICAST_IN_L2_MULTICAST] = { .name = "drop_v6_unicast_in_l2_multicast", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_DROP_GRATUITOUS_ARP] = { .name = "drop_gratuitous_arp", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_DROP_UNSOLICITED_NA] = { .name = "drop_unsolicited_na", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_ARP_ACCEPT] = { .name = "arp_accept", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_AUTH] = { .name = "auth", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_SPEED] = { .name = "speed", .type = BLOBMSG_TYPE_INT32 },
+ [DEV_ATTR_DUPLEX] = { .name = "duplex", .type = BLOBMSG_TYPE_BOOL },
};
const struct uci_blob_param_list device_attr_list = {
return 0;
}
-/* Retrieve the device type for the given name. If 'bridge' is true, the type
- * must have bridge capabilities
- */
struct device_type *
device_type_get(const char *tname)
{
return NULL;
}
-void device_lock(void)
-{
- __devlock++;
-}
-
-void device_unlock(void)
-{
- __devlock--;
- if (!__devlock)
- device_free_unused(NULL);
-}
-
static int device_vlan_len(struct kvlist *kv, const void *data)
{
return sizeof(unsigned int);
vlist_update(&dev->vlans);
} else {
vlist_flush(&dev->vlans);
+
+ if (dev->type->vlan_update)
+ dev->type->vlan_update(dev);
}
}
}
+void device_stp_init(void)
+{
+ struct device *dev;
+
+ avl_for_each_element(&devices, dev, avl) {
+ if (!dev->type->stp_init)
+ continue;
+
+ dev->type->stp_init(dev);
+ }
+}
+
static int set_device_state(struct device *dev, bool state)
{
if (state) {
n->unicast_flood = s->unicast_flood;
n->sendredirects = s->flags & DEV_OPT_SENDREDIRECTS ?
s->sendredirects : os->sendredirects;
+ n->drop_v4_unicast_in_l2_multicast = s->flags & DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST ?
+ s->drop_v4_unicast_in_l2_multicast : os->drop_v4_unicast_in_l2_multicast;
+ n->drop_v6_unicast_in_l2_multicast = s->flags & DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST ?
+ s->drop_v6_unicast_in_l2_multicast : os->drop_v6_unicast_in_l2_multicast;
+ n->drop_gratuitous_arp = s->flags & DEV_OPT_DROP_GRATUITOUS_ARP ?
+ s->drop_gratuitous_arp : os->drop_gratuitous_arp;
+ n->drop_unsolicited_na = s->flags & DEV_OPT_DROP_UNSOLICITED_NA ?
+ s->drop_unsolicited_na : os->drop_unsolicited_na;
+ n->arp_accept = s->flags & DEV_OPT_ARP_ACCEPT ?
+ s->arp_accept : os->arp_accept;
+ n->auth = s->flags & DEV_OPT_AUTH ? s->auth : os->auth;
+ n->speed = s->flags & DEV_OPT_SPEED ? s->speed : os->speed;
+ n->duplex = s->flags & DEV_OPT_DUPLEX ? s->duplex : os->duplex;
n->flags = s->flags | os->flags | os->valid_flags;
}
s->flags |= DEV_OPT_ISOLATE;
}
+ if ((cur = tb[DEV_ATTR_DROP_V4_UNICAST_IN_L2_MULTICAST])) {
+ s->drop_v4_unicast_in_l2_multicast = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST;
+ }
+
+ if ((cur = tb[DEV_ATTR_DROP_V6_UNICAST_IN_L2_MULTICAST])) {
+ s->drop_v6_unicast_in_l2_multicast = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST;
+ }
+
+ if ((cur = tb[DEV_ATTR_DROP_GRATUITOUS_ARP])) {
+ s->drop_gratuitous_arp = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DROP_GRATUITOUS_ARP;
+ }
+
+ if ((cur = tb[DEV_ATTR_DROP_UNSOLICITED_NA])) {
+ s->drop_unsolicited_na = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DROP_UNSOLICITED_NA;
+ }
+
+ if ((cur = tb[DEV_ATTR_ARP_ACCEPT])) {
+ s->arp_accept = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_ARP_ACCEPT;
+ }
+
+ if ((cur = tb[DEV_ATTR_AUTH])) {
+ s->auth = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_AUTH;
+ }
+
+ if ((cur = tb[DEV_ATTR_SPEED])) {
+ s->speed = blobmsg_get_u32(cur);
+ s->flags |= DEV_OPT_SPEED;
+ }
+
+ if ((cur = tb[DEV_ATTR_DUPLEX])) {
+ s->duplex = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DUPLEX;
+ }
+
device_set_disabled(dev, disabled);
}
}
struct device *
-device_get(const char *name, int create)
+__device_get(const char *name, int create, bool check_vlan)
{
struct device *dev;
dev = avl_find_element(&devices, name, dev, avl);
- if (!dev && strchr(name, '.'))
+ if (!dev && check_vlan && strchr(name, '.'))
return get_vlan_device_chain(name, create);
if (name[0] == '@')
__device_set_present(dev, state);
}
+void
+device_set_auth_status(struct device *dev, bool value)
+{
+ if (dev->auth_status == value)
+ return;
+
+ dev->auth_status = value;
+ if (!dev->present)
+ return;
+
+ if (dev->auth_status) {
+ device_broadcast_event(dev, DEV_EVENT_AUTH_UP);
+ return;
+ }
+
+ device_broadcast_event(dev, DEV_EVENT_LINK_DOWN);
+ if (!dev->link_active)
+ return;
+
+ device_broadcast_event(dev, DEV_EVENT_LINK_UP);
+}
+
void device_set_present(struct device *dev, bool state)
{
if (dev->sys_present == state)
netifd_log_message(L_NOTICE, "%s '%s' link is %s\n", dev->type->name, dev->ifname, state ? "up" : "down" );
dev->link_active = state;
+ if (!state)
+ dev->auth_status = false;
device_broadcast_event(dev, state ? DEV_EVENT_LINK_UP : DEV_EVENT_LINK_DOWN);
}
}
static void
-__device_free_unused(struct device *dev)
+__device_free_unused(struct uloop_timeout *timeout)
{
- if (!safe_list_empty(&dev->users) ||
- !safe_list_empty(&dev->aliases) ||
- dev->current_config || __devlock)
- return;
+ struct device *dev, *tmp;
+
+ avl_for_each_element_safe(&devices, dev, avl, tmp) {
+ if (!safe_list_empty(&dev->users) ||
+ !safe_list_empty(&dev->aliases) ||
+ dev->current_config)
+ continue;
+
+ device_free(dev);
+ }
+}
- device_free(dev);
+void device_free_unused(void)
+{
+ static struct uloop_timeout free_timer = {
+ .cb = __device_free_unused,
+ };
+
+ uloop_timeout_set(&free_timer, 1);
}
void device_remove_user(struct device_user *dep)
safe_list_del(&dep->list);
dep->dev = NULL;
D(DEVICE, "Remove user for device '%s', refcount=%d\n", dev->ifname, device_refcount(dev));
- __device_free_unused(dev);
-}
-
-void
-device_free_unused(struct device *dev)
-{
- struct device *tmp;
-
- if (dev)
- return __device_free_unused(dev);
-
- avl_for_each_element_safe(&devices, dev, avl, tmp)
- __device_free_unused(dev);
+ device_free_unused();
}
void
blobmsg_add_u8(b, "up", !!dev->active);
blobmsg_add_u8(b, "carrier", !!dev->link_active);
+ blobmsg_add_u8(b, "auth_status", !!dev->auth_status);
if (dev->type->dump_info)
dev->type->dump_info(dev, b);
blobmsg_add_u8(b, "unicast_flood", st.unicast_flood);
if (st.flags & DEV_OPT_SENDREDIRECTS)
blobmsg_add_u8(b, "sendredirects", st.sendredirects);
+ if (st.flags & DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST)
+ blobmsg_add_u8(b, "drop_v4_unicast_in_l2_multicast", st.drop_v4_unicast_in_l2_multicast);
+ if (st.flags & DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST)
+ blobmsg_add_u8(b, "drop_v6_unicast_in_l2_multicast", st.drop_v6_unicast_in_l2_multicast);
+ if (st.flags & DEV_OPT_DROP_GRATUITOUS_ARP)
+ blobmsg_add_u8(b, "drop_gratuitous_arp", st.drop_gratuitous_arp);
+ if (st.flags & DEV_OPT_DROP_UNSOLICITED_NA)
+ blobmsg_add_u8(b, "drop_unsolicited_na", st.drop_unsolicited_na);
+ if (st.flags & DEV_OPT_ARP_ACCEPT)
+ blobmsg_add_u8(b, "arp_accept", st.arp_accept);
+ if (st.flags & DEV_OPT_AUTH)
+ blobmsg_add_u8(b, "auth", st.auth);
}
s = blobmsg_open_table(b, "statistics");
{
device_type_add(&simple_device_type);
}
+
+void device_hotplug_event(const char *name, bool add)
+{
+ struct device *dev;
+
+ wireless_device_hotplug_event(name, add);
+
+ dev = device_find(name);
+ if (!dev || dev->type != &simple_device_type)
+ return;
+
+ device_set_present(dev, add);
+}