#include "device.h"
#include "system.h"
+struct event_socket {
+ struct uloop_fd uloop;
+ struct nl_sock *sock;
+ struct nl_cb *cb;
+};
+
static int sock_ioctl = -1;
static struct nl_sock *sock_rtnl = NULL;
-static struct nl_sock *sock_rtnl_event = NULL;
-static void handler_rtnl_event(struct uloop_fd *u, unsigned int events);
static int cb_rtnl_event(struct nl_msg *msg, void *arg);
-static struct uloop_fd rtnl_event = {.cb = handler_rtnl_event};
-static struct nl_cb *nl_cb_rtnl_event;
+static void handle_hotplug_event(struct uloop_fd *u, unsigned int events);
-int system_init(void)
+static void
+handler_nl_event(struct uloop_fd *u, unsigned int events)
{
- sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
- fcntl(sock_ioctl, F_SETFD, fcntl(sock_ioctl, F_GETFD) | FD_CLOEXEC);
+ struct event_socket *ev = container_of(u, struct event_socket, uloop);
+ nl_recvmsgs(ev->sock, ev->cb);
+}
- // Prepare socket for routing / address control
- sock_rtnl = nl_socket_alloc();
- if (!sock_rtnl)
- return -1;
+static struct nl_sock *
+create_socket(int protocol, int groups)
+{
+ struct nl_sock *sock;
- if (nl_connect(sock_rtnl, NETLINK_ROUTE))
- goto error_free_sock;
+ sock = nl_socket_alloc();
+ if (!sock)
+ return NULL;
- // Prepare socket for link events
- nl_cb_rtnl_event = nl_cb_alloc(NL_CB_DEFAULT);
- if (!nl_cb_rtnl_event)
- goto error_free_sock;
+ if (groups)
+ nl_join_groups(sock, groups);
- nl_cb_set(nl_cb_rtnl_event, NL_CB_VALID, NL_CB_CUSTOM,
- cb_rtnl_event, NULL);
+ if (nl_connect(sock, protocol))
+ return NULL;
- sock_rtnl_event = nl_socket_alloc();
- if (!sock_rtnl_event)
- goto error_free_cb;
+ return sock;
+}
- if (nl_connect(sock_rtnl_event, NETLINK_ROUTE))
- goto error_free_event;
+static bool
+create_raw_event_socket(struct event_socket *ev, int protocol, int groups,
+ uloop_fd_handler cb)
+{
+ ev->sock = create_socket(protocol, groups);
+ if (!ev->sock)
+ return false;
- // Receive network link events form kernel
- nl_socket_add_membership(sock_rtnl_event, RTNLGRP_LINK);
+ ev->uloop.fd = nl_socket_get_fd(ev->sock);
+ ev->uloop.cb = cb;
+ uloop_fd_add(&ev->uloop, ULOOP_READ | ULOOP_EDGE_TRIGGER);
+ return true;
+}
- rtnl_event.fd = nl_socket_get_fd(sock_rtnl_event);
- uloop_fd_add(&rtnl_event, ULOOP_READ | ULOOP_EDGE_TRIGGER);
+static bool
+create_event_socket(struct event_socket *ev, int protocol,
+ int (*cb)(struct nl_msg *msg, void *arg))
+{
+ // Prepare socket for link events
+ ev->cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!ev->cb)
+ return false;
- return 0;
+ nl_cb_set(ev->cb, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
-error_free_event:
- nl_socket_free(sock_rtnl_event);
- sock_rtnl_event = NULL;
-error_free_cb:
- nl_cb_put(nl_cb_rtnl_event);
- nl_cb_rtnl_event = NULL;
-error_free_sock:
- nl_socket_free(sock_rtnl);
- sock_rtnl = NULL;
- return -1;
+ return create_raw_event_socket(ev, protocol, 0, handler_nl_event);
}
-// If socket is ready for reading parse netlink events
-static void handler_rtnl_event(struct uloop_fd *u, unsigned int events)
+int system_init(void)
{
- nl_recvmsgs(sock_rtnl_event, nl_cb_rtnl_event);
+ static struct event_socket rtnl_event;
+ static struct event_socket hotplug_event;
+
+ sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ fcntl(sock_ioctl, F_SETFD, fcntl(sock_ioctl, F_GETFD) | FD_CLOEXEC);
+
+ // Prepare socket for routing / address control
+ sock_rtnl = create_socket(NETLINK_ROUTE, 0);
+ if (!sock_rtnl)
+ return -1;
+
+ if (!create_event_socket(&rtnl_event, NETLINK_ROUTE, cb_rtnl_event))
+ return -1;
+
+ if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1,
+ handle_hotplug_event))
+ return -1;
+
+ // Receive network link events form kernel
+ nl_socket_add_membership(rtnl_event.sock, RTNLGRP_LINK);
+
+ return 0;
}
static void system_set_sysctl(const char *path, const char *val)
goto out;
dev->ifindex = ifi->ifi_index;
- device_set_present(dev, (nh->nlmsg_type == RTM_NEWLINK));
+ /* TODO: parse link status */
out:
return 0;
}
+static void
+handle_hotplug_msg(char *data, int size)
+{
+ const char *subsystem = NULL, *interface = NULL;
+ char *cur, *end, *sep;
+ struct device *dev;
+ int skip;
+ bool add;
+
+ if (!strncmp(data, "add@", 4))
+ add = true;
+ else if (!strncmp(data, "remove@", 7))
+ add = false;
+ else
+ return;
+
+ skip = strlen(data) + 1;
+ end = data + size;
+
+ for (cur = data + skip; cur < end; cur += skip) {
+ skip = strlen(cur) + 1;
+
+ sep = strchr(cur, '=');
+ if (!sep)
+ continue;
+
+ *sep = 0;
+ if (!strcmp(cur, "INTERFACE"))
+ interface = sep + 1;
+ else if (!strcmp(cur, "SUBSYSTEM")) {
+ subsystem = sep + 1;
+ if (strcmp(subsystem, "net") != 0)
+ return;
+ }
+ if (subsystem && interface)
+ goto found;
+ }
+ return;
+
+found:
+ dev = device_get(interface, false);
+ if (!dev)
+ return;
+
+ if (dev->type != &simple_device_type)
+ return;
+
+ device_set_present(dev, add);
+}
+
+static void
+handle_hotplug_event(struct uloop_fd *u, unsigned int events)
+{
+ struct event_socket *ev = container_of(u, struct event_socket, uloop);
+ struct sockaddr_nl nla;
+ unsigned char *buf = NULL;
+ int size;
+
+ while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) {
+ if (nla.nl_pid == 0)
+ handle_hotplug_msg((char *) buf, size);
+
+ free(buf);
+ }
+}
+
static int system_rtnl_call(struct nl_msg *msg)
{
int s = -(nl_send_auto_complete(sock_rtnl, msg)
int system_if_check(struct device *dev)
{
- device_set_present(dev, (system_if_resolve(dev) >= 0));
+ device_set_present(dev, (system_if_resolve(dev) > 0));
return 0;
}
+struct device *
+system_if_get_parent(struct device *dev)
+{
+ char buf[64], *devname;
+ int ifindex, iflink, len;
+ FILE *f;
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname);
+ f = fopen(buf, "r");
+ if (!f)
+ return NULL;
+
+ len = fread(buf, 1, sizeof(buf) - 1, f);
+ fclose(f);
+
+ if (len <= 0)
+ return NULL;
+
+ buf[len] = 0;
+ iflink = strtoul(buf, NULL, 0);
+ ifindex = system_if_resolve(dev);
+ if (!iflink || iflink == ifindex)
+ return NULL;
+
+ devname = if_indextoname(iflink, buf);
+ if (!devname)
+ return NULL;
+
+ return device_get(devname, true);
+}
+
int system_if_dump_stats(struct device *dev, struct blob_buf *b)
{
const char *const counters[] = {