summaryrefslogtreecommitdiff
path: root/nhrp/nhrp_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'nhrp/nhrp_interface.c')
-rw-r--r--nhrp/nhrp_interface.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/nhrp/nhrp_interface.c b/nhrp/nhrp_interface.c
new file mode 100644
index 0000000..32c2383
--- /dev/null
+++ b/nhrp/nhrp_interface.c
@@ -0,0 +1,188 @@
+/* nhrp_interface.c - NHRP configuration per interface
+ *
+ * Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ *
+ * See http://www.gnu.org/ for details.
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+#include "nhrp_common.h"
+#include "nhrp_interface.h"
+#include "nhrp_address.h"
+
+#define NHRP_INDEX_HASH_SIZE (1 << 6)
+
+static struct list_head name_list = LIST_INITIALIZER(name_list);
+static struct hlist_head index_hash[NHRP_INDEX_HASH_SIZE];
+
+static char *env(const char *key, const char *value)
+{
+ char *buf;
+ buf = malloc(strlen(key)+strlen(value)+2);
+ if (buf == NULL)
+ return NULL;
+ sprintf(buf, "%s=%s", key, value);
+ return buf;
+}
+
+static char *envu32(const char *key, uint32_t value)
+{
+ char *buf;
+ buf = malloc(strlen(key)+16);
+ if (buf == NULL)
+ return NULL;
+ sprintf(buf, "%s=%u", key, value);
+ return buf;
+}
+
+void nhrp_interface_cleanup(void)
+{
+ struct nhrp_interface *iface, *n;
+
+ list_for_each_entry_safe(iface, n, &name_list, name_list_entry) {
+ list_del(&iface->name_list_entry);
+ hlist_del(&iface->index_list_entry);
+ free(iface);
+ }
+}
+
+void nhrp_interface_hash(struct nhrp_interface *iface)
+{
+ int iidx = iface->index & (NHRP_INDEX_HASH_SIZE - 1);
+
+ list_del(&iface->name_list_entry);
+ list_add(&iface->name_list_entry, &name_list);
+
+ hlist_del(&iface->index_list_entry);
+ hlist_add_head(&iface->index_list_entry, &index_hash[iidx]);
+}
+
+int nhrp_interface_foreach(nhrp_interface_enumerator enumerator, void *ctx)
+{
+ struct nhrp_interface *iface;
+ int rc;
+
+ list_for_each_entry(iface, &name_list, name_list_entry) {
+ rc = enumerator(ctx, iface);
+ if (rc != 0)
+ return rc;
+ }
+ return 0;
+}
+
+struct nhrp_interface *nhrp_interface_get_by_name(const char *name, int create)
+{
+ struct nhrp_interface *iface;
+
+ list_for_each_entry(iface, &name_list, name_list_entry) {
+ if (strcmp(iface->name, name) == 0)
+ return iface;
+ }
+
+ if (!create)
+ return NULL;
+
+ iface = calloc(1, sizeof(struct nhrp_interface));
+ iface->holding_time = NHRP_DEFAULT_HOLDING_TIME;
+ iface->route_table = RT_TABLE_MAIN;
+ strncpy(iface->name, name, sizeof(iface->name));
+
+ list_init(&iface->peer_list);
+ list_init(&iface->mcast_list);
+ list_add(&iface->name_list_entry, &name_list);
+ hlist_add_head(&iface->index_list_entry, &index_hash[0]);
+
+ return iface;
+}
+
+struct nhrp_interface *nhrp_interface_get_by_index(unsigned int index, int create)
+{
+ struct nhrp_interface *iface;
+ struct hlist_node *n;
+ int iidx = index & (NHRP_INDEX_HASH_SIZE - 1);
+
+ hlist_for_each_entry(iface, n, &index_hash[iidx], index_list_entry) {
+ if (iface->index == index)
+ return iface;
+ }
+
+ return NULL;
+}
+
+struct nhrp_interface *nhrp_interface_get_by_nbma(struct nhrp_address *addr)
+{
+ struct nhrp_interface *iface;
+
+ list_for_each_entry(iface, &name_list, name_list_entry) {
+ if (!(iface->flags & NHRP_INTERFACE_FLAG_CONFIGURED))
+ continue;
+
+ if (nhrp_address_cmp(addr, &iface->nbma_address) == 0)
+ return iface;
+
+ if (iface->nbma_address.type == PF_UNSPEC && !iface->link_index)
+ return iface;
+ }
+
+ return NULL;
+}
+
+struct nhrp_interface *nhrp_interface_get_by_protocol(struct nhrp_address *addr)
+{
+ struct nhrp_interface *iface;
+
+ list_for_each_entry(iface, &name_list, name_list_entry) {
+ if (nhrp_address_cmp(addr, &iface->protocol_address) == 0)
+ return iface;
+ }
+
+ return NULL;
+}
+
+int nhrp_interface_run_script(struct nhrp_interface *iface, char *action)
+{
+ const char *argv[] = { nhrp_script_file, action, NULL };
+ char *envp[6];
+ pid_t pid;
+ int i = 0;
+
+ pid = fork();
+ if (pid == -1)
+ return FALSE;
+ if (pid > 0)
+ return TRUE;
+
+ envp[i++] = "NHRP_TYPE=INTERFACE";
+ envp[i++] = env("NHRP_INTERFACE", iface->name);
+ envp[i++] = envu32("NHRP_GRE_KEY", iface->gre_key);
+ envp[i++] = NULL;
+
+ execve(nhrp_script_file, (char **) argv, envp);
+ exit(1);
+}
+
+struct nhrp_peer *nhrp_interface_find_peer(struct nhrp_interface *iface,
+ const struct nhrp_address *nbma)
+{
+ unsigned int key = nhrp_address_hash(nbma) % NHRP_INTERFACE_NBMA_HASH_SIZE;
+ struct nhrp_peer *peer;
+ struct hlist_node *n;
+
+ hlist_for_each_entry(peer, n, &iface->nbma_hash[key], nbma_hash_entry) {
+ if (nhrp_address_cmp(nbma, &peer->next_hop_address) == 0)
+ return peer;
+ }
+ return NULL;
+}