summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config-load.c8
-rw-r--r--src/device-interface.c147
-rw-r--r--src/device.h6
-rw-r--r--src/meson.build8
-rw-r--r--src/neco.c7
-rw-r--r--src/netlink.c38
-rw-r--r--src/netlink.h12
7 files changed, 216 insertions, 10 deletions
diff --git a/src/config-load.c b/src/config-load.c
index 92abca0..63a87b4 100644
--- a/src/config-load.c
+++ b/src/config-load.c
@@ -120,8 +120,14 @@ bool read_config(const char *path) {
free(subtypes);
device_t *dev, *tmp;
+ avl_for_each_element(devices, dev, node)
+ dev->type->init(dev);
+
+ //avl_for_each_element(devices, dev, node)
+ // dev->type->release(dev);
+
avl_remove_all_elements(devices, dev, node, tmp)
- dev->type->free_device(dev);
+ dev->type->free(dev);
free(devices);
diff --git a/src/device-interface.c b/src/device-interface.c
index 5ac7cee..a2aae14 100644
--- a/src/device-interface.c
+++ b/src/device-interface.c
@@ -1,17 +1,23 @@
#include "device.h"
#include "keywords.h"
+#include "netlink.h"
#include "util.h"
#include "vector.h"
-#include <arpa/inet.h>
-#include <netinet/ether.h>
-#include <netinet/in.h>
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
static device_type_t device_type_interface;
typedef struct _ipaddr {
@@ -144,7 +150,7 @@ static bool process_section_static(device_interface_t *iface, const ini_section_
return true;
}
-static void interface_free_device(device_t *dev) {
+static void interface_free(device_t *dev) {
device_interface_t *iface = container_of(dev, device_interface_t, device);
VECTOR_FREE(iface->addrs);
@@ -152,6 +158,129 @@ static void interface_free_device(device_t *dev) {
free(iface);
}
+static bool interface_set_link_flags(unsigned index, unsigned change, unsigned flags) {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ struct mnl_socket *nl = nl_socket();
+
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_SETLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ int seq = nlh->nlmsg_seq = nl_seq();
+
+ struct ifinfomsg *ifi = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifi));
+ ifi->ifi_index = index;
+ ifi->ifi_family = AF_UNSPEC;
+
+ ifi->ifi_change = change;
+ ifi->ifi_flags = flags;
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_sendto");
+ return false;
+ }
+
+ int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("mnl_socket_recvfrom");
+ return false;
+ }
+
+ ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);
+ if (ret == -1) {
+ perror("mnl_cb_run");
+ return false;
+ }
+
+ return true;
+}
+
+static bool interface_set_link_state(unsigned index, bool up) {
+ return interface_set_link_flags(index, IFF_UP, up ? IFF_UP : 0);
+}
+
+static bool interface_set_ipaddr(unsigned index, ipaddr_prefix_t *addr, bool add) {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ struct mnl_socket *nl = nl_socket();
+
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = add ? RTM_NEWADDR : RTM_DELADDR;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ if (add)
+ nlh->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+
+ int seq = nlh->nlmsg_seq = nl_seq();
+
+ struct ifaddrmsg *ifa = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifa));
+ ifa->ifa_index = index;
+ ifa->ifa_family = addr->addr.af;
+
+ ifa->ifa_prefixlen = addr->plen;
+
+ switch (addr->addr.af) {
+ case AF_INET:
+ mnl_attr_put(nlh, IFA_LOCAL, 4, &addr->addr.addr4);
+ break;
+
+ case AF_INET6:
+ mnl_attr_put(nlh, IFA_LOCAL, 16, &addr->addr.addr6);
+ break;
+
+ default:
+ errno = EINVAL;
+ return false;
+ }
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_sendto");
+ return false;
+ }
+
+ int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("mnl_socket_recvfrom");
+ return false;
+ }
+
+ ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL);
+ if (ret == -1) {
+ perror("mnl_cb_run");
+ return false;
+ }
+
+ return true;
+}
+
+static void interface_init(device_t *dev) {
+ device_interface_t *iface = container_of(dev, device_interface_t, device);
+
+ unsigned index = if_nametoindex(NODE_NAME(dev));
+ if (!index)
+ return;
+
+ interface_set_link_state(index, true);
+
+ for (size_t i = 0; i < VECTOR_LEN(iface->addrs); i++)
+ interface_set_ipaddr(index, &VECTOR_INDEX(iface->addrs, i), true);
+}
+
+static void interface_update(device_t *dev) {
+}
+
+static void interface_release(device_t *dev) {
+ device_interface_t *iface = container_of(dev, device_interface_t, device);
+
+ unsigned index = if_nametoindex(NODE_NAME(dev));
+ if (!index)
+ return;
+
+ for (size_t i = 0; i < VECTOR_LEN(iface->addrs); i++)
+ interface_set_ipaddr(index, &VECTOR_INDEX(iface->addrs, i), false);
+
+ interface_set_link_state(index, false);
+}
+
static device_t * interface_process_config(const char *name, const ini_file_t *config) {
device_interface_t *iface = calloc(1, sizeof(*iface));
if (!iface)
@@ -187,13 +316,17 @@ static device_t * interface_process_config(const char *name, const ini_file_t *c
return dev;
err:
- interface_free_device(dev);
+ interface_free(dev);
return NULL;
}
static device_type_t device_type_interface = {
.process_config = interface_process_config,
- .free_device = interface_free_device,
+ .free = interface_free,
+
+ .init = interface_init,
+ .update = interface_update,
+ .release = interface_release,
};
__attribute__((constructor))
diff --git a/src/device.h b/src/device.h
index f437021..33acfbb 100644
--- a/src/device.h
+++ b/src/device.h
@@ -16,7 +16,11 @@ typedef struct _device {
struct _device_type {
struct avl_node node;
device_t * (*process_config)(const char *name, const ini_file_t *config);
- void (*free_device)(device_t *device);
+ void (*free)(device_t *device);
+
+ void (*init)(device_t *device);
+ void (*update)(device_t *device);
+ void (*release)(device_t *device);
};
void register_device_type(const char *name, device_type_t *device_type);
diff --git a/src/meson.build b/src/meson.build
index b088e39..9056cf3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -7,7 +7,13 @@ src = [
'device-bridge.c',
'device-interface.c',
'keywords.c',
+ 'netlink.c',
'vector.c',
]
-executable('neco', sources: src, dependencies: [ubox_dep])
+dep = [
+ libubox_dep,
+ libmnl_dep,
+]
+
+executable('neco', sources: src, dependencies: dep)
diff --git a/src/neco.c b/src/neco.c
index 942ba2f..4e4d297 100644
--- a/src/neco.c
+++ b/src/neco.c
@@ -1,6 +1,13 @@
#include "config-load.h"
+#include "netlink.h"
int main(int argc, char *argv[]) {
+ if (!nl_init())
+ return 1;
+
read_config(argv[1]);
+
+ nl_deinit();
+
return 0;
}
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100644
index 0000000..ec9c935
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,38 @@
+#include "netlink.h"
+
+#include <stdio.h>
+
+static struct mnl_socket *nl;
+static uint32_t seq;
+
+bool nl_init(void) {
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ return false;
+ }
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+ perror("mnl_socket_bind");
+ nl_deinit();
+ return false;
+ }
+
+ return true;
+}
+
+void nl_deinit(void) {
+ if (!nl)
+ return;
+
+ mnl_socket_close(nl);
+ nl = NULL;
+}
+
+struct mnl_socket * nl_socket(void) {
+ return nl;
+}
+
+uint32_t nl_seq(void) {
+ return seq++;
+}
diff --git a/src/netlink.h b/src/netlink.h
new file mode 100644
index 0000000..6529e92
--- /dev/null
+++ b/src/netlink.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <libmnl/libmnl.h>
+
+#include <stdbool.h>
+#include <stdbool.h>
+
+bool nl_init(void);
+void nl_deinit(void);
+
+struct mnl_socket * nl_socket(void);
+uint32_t nl_seq(void);