aboutsummaryrefslogtreecommitdiffstats
path: root/pingu_route.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-10-07 11:13:27 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2011-10-07 11:13:27 +0200
commitf8b192af8b6611c3832df3024cbabaafffb47591 (patch)
tree43eb3a2493224a4a9b3303fc69fa5355d1b432c3 /pingu_route.c
parent2aa0126a96f8fe44c8b6a61e4051bbf9c3b3dc79 (diff)
downloadpingu-f8b192af8b6611c3832df3024cbabaafffb47591.tar.bz2
pingu-f8b192af8b6611c3832df3024cbabaafffb47591.tar.xz
pingu: rename pingu_gateway to pingu_route
Diffstat (limited to 'pingu_route.c')
-rw-r--r--pingu_route.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/pingu_route.c b/pingu_route.c
new file mode 100644
index 0000000..efc8ad0
--- /dev/null
+++ b/pingu_route.c
@@ -0,0 +1,128 @@
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "list.h"
+#include "log.h"
+#include "pingu_route.h"
+
+static void pingu_route_add_sorted(struct list_head *route_list,
+ struct pingu_route *new_gw)
+{
+ struct pingu_route *gw;
+ list_for_each_entry(gw, route_list, route_list_entry) {
+ if (gw->metric > new_gw->metric) {
+ list_add_tail(&new_gw->route_list_entry,
+ &gw->route_list_entry);
+ return;
+ }
+ }
+ list_add_tail(&new_gw->route_list_entry, route_list);
+}
+
+static struct pingu_route *pingu_route_clone(struct pingu_route *gw)
+{
+ struct pingu_route *new_gw = calloc(1, sizeof(struct pingu_route));
+ if (gw == NULL) {
+ log_perror("Failed to allocate gateway");
+ return NULL;
+ }
+ /* copy the fields without overwriting the list entry */
+ memcpy(&new_gw->dest, &gw->dest, sizeof(new_gw->dest));
+ memcpy(&new_gw->gw_addr, &gw->gw_addr, sizeof(new_gw->gw_addr));
+ new_gw->dst_len = gw->dst_len;
+ new_gw->src_len = gw->src_len;
+ new_gw->metric = gw->metric;
+ new_gw->protocol = gw->protocol;
+ new_gw->scope = gw->scope;
+ new_gw->type = gw->type;
+ return new_gw;
+}
+
+static void log_debug_gw(char *msg, struct pingu_route *gw)
+{
+ char destbuf[64], gwaddrbuf[64];
+ log_debug("%s: %s/%i via %s metric %i", msg,
+ sockaddr_to_string(&gw->dest, destbuf, sizeof(destbuf)),
+ gw->dst_len,
+ sockaddr_to_string(&gw->gw_addr, gwaddrbuf, sizeof(gwaddrbuf)),
+ gw->metric);
+}
+
+static int gateway_cmp(struct pingu_route *a, struct pingu_route *b)
+{
+ int r;
+ if (a->dst_len != b->dst_len)
+ return a->dst_len - b->dst_len;
+ r = sockaddr_cmp(&a->dest, &b->dest);
+ if (r != 0)
+ return r;
+ r = sockaddr_cmp(&a->gw_addr, &b->gw_addr);
+ if (r != 0)
+ return r;
+ return a->metric - b->metric;
+}
+
+static struct pingu_route *pingu_route_get(struct list_head *route_list,
+ struct pingu_route *gw)
+{
+ struct pingu_route *entry;
+ list_for_each_entry(entry, route_list, route_list_entry) {
+ if (gateway_cmp(entry, gw) == 0)
+ return entry;
+ }
+ return NULL;
+}
+
+void pingu_route_del_all(struct list_head *head)
+{
+ struct pingu_route *gw, *n;
+ list_for_each_entry_safe(gw, n, head, route_list_entry) {
+ list_del(&gw->route_list_entry);
+ free(gw);
+ }
+}
+
+void pingu_route_add(struct list_head *route_list,
+ struct pingu_route *gw)
+{
+ struct pingu_route *new_gw = pingu_route_clone(gw);
+ if (new_gw == NULL)
+ return;
+ pingu_route_add_sorted(route_list, new_gw);
+}
+
+void pingu_route_del(struct list_head *route_list,
+ struct pingu_route *delete)
+{
+ struct pingu_route *gw = pingu_route_get(route_list, delete);
+ if (gw == NULL)
+ return;
+ log_debug_gw("removed", gw);
+ list_del(&gw->route_list_entry);
+ free(gw);
+}
+
+int is_default_gw(struct pingu_route *route)
+{
+ switch (route->dest.sa.sa_family) {
+ case AF_INET:
+ return ((route->dest.sin.sin_addr.s_addr == 0)
+ && (route->gw_addr.sin.sin_addr.s_addr != 0));
+ break;
+ case AF_INET6:
+ log_debug("TODO: ipv6");
+ break;
+ }
+ return 0;
+}
+
+struct pingu_route *pingu_route_first_default(struct list_head *route_list)
+{
+ struct pingu_route *entry;
+ list_for_each_entry(entry, route_list, route_list_entry) {
+ if (is_default_gw(entry))
+ return entry;
+ }
+ return NULL;
+}