summaryrefslogtreecommitdiff
path: root/src/dumm/bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumm/bridge.c')
-rw-r--r--src/dumm/bridge.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c
new file mode 100644
index 000000000..c6068e60c
--- /dev/null
+++ b/src/dumm/bridge.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <sys/types.h>
+#include <libbridge.h>
+
+#include <debug.h>
+#include <utils/linked_list.h>
+
+#include "bridge.h"
+
+typedef struct private_bridge_t private_bridge_t;
+
+struct private_bridge_t {
+ /** public interface */
+ bridge_t public;
+ /** device name */
+ char *name;
+ /** list of attached interfaces */
+ linked_list_t *ifaces;
+};
+
+/**
+ * Implementation of bridge_t.get_name.
+ */
+static char* get_name(private_bridge_t *this)
+{
+ return this->name;
+}
+
+/**
+ * Implementation of bridge_t.create_iface_iterator.
+ */
+static iterator_t* create_iface_iterator(private_bridge_t *this)
+{
+ return this->ifaces->create_iterator(this->ifaces, TRUE);
+}
+
+/**
+ * Implementation of bridge_t.disconnect_iface.
+ */
+static bool disconnect_iface(private_bridge_t *this, iface_t *iface)
+{
+ iterator_t *iterator;
+ iface_t *current;
+ bool good = FALSE;
+
+ iterator = this->ifaces->create_iterator(this->ifaces, TRUE);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current == iface)
+ {
+ if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
+ {
+ DBG1("removing iface '%s' from bridge '%s' in kernel failed: %m",
+ iface->get_hostif(iface), this->name);
+ }
+ else
+ {
+ iface->set_bridge(iface, NULL);
+ good = TRUE;
+ }
+ break;
+ }
+ }
+ if (iface != current)
+ {
+ DBG1("iface '%s' not found on bridge '%s'", iface->get_hostif(iface),
+ this->name);
+ }
+ iterator->destroy(iterator);
+ return good;
+}
+
+/**
+ * Implementation of bridge_t.connect_iface.
+ */
+static bool connect_iface(private_bridge_t *this, iface_t *iface)
+{
+ if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
+ {
+ DBG1("adding iface '%s' to bridge '%s' failed: %m",
+ iface->get_hostif(iface), this->name);
+ return FALSE;
+ }
+ iface->set_bridge(iface, &this->public);
+ this->ifaces->insert_last(this->ifaces, iface);
+ return TRUE;
+}
+
+/**
+ * instance counter to (de-)initialize libbridge
+ */
+static int instances = 0;
+
+/**
+ * unregister an interface from bridge
+ */
+static void unregister(iface_t *iface)
+{
+ iface->set_bridge(iface, NULL);
+}
+
+/**
+ * Implementation of bridge_t.destroy.
+ */
+static void destroy(private_bridge_t *this)
+{
+ this->ifaces->invoke_function(this->ifaces, (void(*)(void*))unregister);
+ this->ifaces->destroy(this->ifaces);
+ if (br_del_bridge(this->name) != 0)
+ {
+ DBG1("deleting bridge '%s' from kernel failed: %m", this->name);
+ }
+ free(this->name);
+ free(this);
+ if (--instances == 0)
+ {
+ br_shutdown();
+ }
+}
+
+/**
+ * create the bridge instance
+ */
+bridge_t *bridge_create(char *name)
+{
+ private_bridge_t *this;
+
+ if (instances == 0)
+ {
+ if (br_init() != 0)
+ {
+ DBG1("libbridge initialization failed: %m");
+ return NULL;
+ }
+ }
+
+ this = malloc_thing(private_bridge_t);
+ this->public.get_name = (char*(*)(bridge_t*))get_name;
+ this->public.create_iface_iterator = (iterator_t*(*)(bridge_t*))create_iface_iterator;
+ this->public.disconnect_iface = (bool(*)(bridge_t*, iface_t *iface))disconnect_iface;
+ this->public.connect_iface = (bool(*)(bridge_t*, iface_t *iface))connect_iface;
+ this->public.destroy = (void*)destroy;
+
+ if (br_add_bridge(name) != 0)
+ {
+ DBG1("creating bridge '%s' failed: %m", name);
+ free(this);
+ return NULL;
+ }
+
+ this->name = strdup(name);
+ this->ifaces = linked_list_create();
+
+ instances++;
+ return &this->public;
+}
+