/* * 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 . * * 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 #include #include #include #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; }; /** * defined in iface.c */ bool iface_control(char *name, bool up); METHOD(bridge_t, get_name, char*, private_bridge_t *this) { return this->name; } METHOD(bridge_t, create_iface_enumerator, enumerator_t*, private_bridge_t *this) { return this->ifaces->create_enumerator(this->ifaces); } METHOD(bridge_t, disconnect_iface, bool, private_bridge_t *this, iface_t *iface) { enumerator_t *enumerator; iface_t *current = NULL; bool good = FALSE; enumerator = this->ifaces->create_enumerator(this->ifaces); while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current == iface) { if (br_del_interface(this->name, iface->get_hostif(iface)) != 0) { DBG1(DBG_LIB, "removing iface '%s' from bridge '%s' in kernel" " failed: %m", iface->get_hostif(iface), this->name); } else { iface->set_bridge(iface, NULL); this->ifaces->remove_at(this->ifaces, enumerator); good = TRUE; } break; } } if (iface != current) { DBG1(DBG_LIB, "iface '%s' not found on bridge '%s'", iface->get_hostif(iface), this->name); } enumerator->destroy(enumerator); return good; } METHOD(bridge_t, connect_iface, bool, private_bridge_t *this, iface_t *iface) { if (br_add_interface(this->name, iface->get_hostif(iface)) != 0) { DBG1(DBG_LIB, "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; METHOD(bridge_t, destroy, void, private_bridge_t *this) { enumerator_t *enumerator; iface_t *iface; enumerator = this->ifaces->create_enumerator(this->ifaces); while (enumerator->enumerate(enumerator, (void**)&iface)) { if (br_del_interface(this->name, iface->get_hostif(iface)) != 0) { DBG1(DBG_LIB, "disconnecting iface '%s' failed: %m", iface->get_hostif(iface)); } iface->set_bridge(iface, NULL); } enumerator->destroy(enumerator); this->ifaces->destroy(this->ifaces); iface_control(this->name, FALSE); if (br_del_bridge(this->name) != 0) { DBG1(DBG_LIB, "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(DBG_LIB, "libbridge initialization failed: %m"); return NULL; } } INIT(this, .public = { .get_name = _get_name, .create_iface_enumerator = _create_iface_enumerator, .disconnect_iface = _disconnect_iface, .connect_iface = _connect_iface, .destroy = _destroy, } ); if (br_add_bridge(name) != 0) { DBG1(DBG_LIB, "creating bridge '%s' failed: %m", name); free(this); return NULL; } if (!iface_control(name, TRUE)) { DBG1(DBG_LIB, "bringing bridge '%s' up failed: %m", name); } this->name = strdup(name); this->ifaces = linked_list_create(); instances++; return &this->public; }